コード例 #1
0
ファイル: LANDiscoverer.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        void HandleNewPacket(byte[] data, string addr)
        {
            try
            {
                //deserialize packet
                IDiscoveryMessageBase msg;
                try
                {
                    msg = Tools.Marshalling.ToObject(DiscoveryMessageType, data) as IDiscoveryMessageBase;
                }
                catch { return; }

                //is it me? (then discard msg)
                if (msg.Id == 0 || msg.Id == myID)
                {
                    return;
                }

                //create remote id
                var remID = new RemoteEndpointID()
                {
                    IPAddress = addr, ID = msg.Id
                };

                //examine existing association
                var info = DiscoveredEndpoints.TryGetOrDefault(remID);
                if (info == null)
                {
                    DebugEx.TraceLog($"LANDiscoverer : Discovered new endpoint. (ip:{addr} id:{msg.Id} flags:{msg.Flags})");
                    //create info
                    info = new RemoteEndpointInfo
                    {
                        ID = remID,
                        LastMessageTimestamp = DateTime.Now,
                        LastDiscoveryMessage = msg,
                    };
                    //add to discovered nodes
                    DiscoveredEndpoints.Add(remID, info);
                    //raise event
                    OnNewEndpointDiscovered?.Invoke(info);
                }

                //custom handle?
                OnEndpointMsgRx?.Invoke(info, msg);

                //update discovery message and timestamp
                Interlocked.Exchange(ref info.LastDiscoveryMessage, msg);
                info.LastMessageTimestamp = DateTime.Now;
            }
            catch (Exception ex) { DebugEx.TraceError(ex, "DiscoveryTaskEntryPoint error"); }
        }
コード例 #2
0
ファイル: NodeGraphManager.cs プロジェクト: sm6uax/plegma
 //------------------------------------------------------------------------------------------------------------------------
 public bool OnGraphLoadReq(GraphManager.GraphLoadRequestData req, out Graph Graph)
 {
     lock (locker)
     {
         Graph = null;
         var gi = Graphs.TryGetOrDefault(req.GraphKey);
         if (gi == null)
         {
             return(false);
         }
         else
         {
             Graph = gi.Graph;
             return(Graph != null);
         }
     }
 }
コード例 #3
0
ファイル: NodeDiscoverManager.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        public void SendVBMToBrothers(List <VirtualBlockEvent> events)
        {
            try
            {
                //split into packets-per brother
                var brotherPackets = new Dictionary <NodeKey, List <VirtualBlockEvent> >();
                foreach (var ev in events)
                {
                    var bk = (BlockKey)ev.BlockKey;
                    var nk = bk.GraphKey.NodeKey;
                    if (BrotherNodes.ContainsKey(nk))
                    {
                        //get (or create) packet list
                        var packets = brotherPackets.TryGetOrDefault(nk);
                        if (packets == null)
                        {
                            brotherPackets.Add(nk, packets = new List <VirtualBlockEvent>());
                        }
                        //add packet for brother node
                        packets.Add(ev);
                    }
                }

                //send to brothers and consume
                foreach (var bpkv in brotherPackets)
                {
                    //get brother
                    var brother = BrotherNodes.TryGetOrDefault(bpkv.Key);
                    if (brother != null && brother.IsConnected)
                    {
                        var msgReq = new VirtualBlockEventMsg()
                        {
                            BlockEvents = bpkv.Value.ToArray(),
                        };
                        var rsp = brother.SendRequest <GenericRsp>(msgReq, Timeout: TimeSpan.FromSeconds(3));
                        if (rsp != null && rsp.IsSuccess)
                        {
                            //consume events from original set
                            msgReq.BlockEvents.ForEach(e => events.Remove(e));
                        }
                    }
                }
            }
            catch (Exception ex) { DebugEx.Assert(ex, "Unhandled exception in SendVBMToBrothers"); }
        }
コード例 #4
0
        //------------------------------------------------------------------------------------------------------------------------
        private void OnRxPythonMsg(SharpPy msg)
        {
#if DEBUG
            DebugEx.TraceLog("OnRxPython " + msg.payload + ", syncid: " + msg.syncid + ", watcherid " + msg.watcherid);
            if (PendingRequests.Count != 0)
            {
                DebugEx.TraceLogInlineBegin("PENDING syncids: ");
                foreach (var item in PendingRequests.Keys)
                {
                    DebugEx.TraceLogInline(item.ToString());
                }
                DebugEx.TraceLogInlineEnd("");
            }
            DebugEx.TraceLog("This watcherid:" + this.WatcherId);
#endif
            if (msg.watcherid == this.WatcherId)
            {
                int syncId = msg.syncid;
                if (syncId == 0)
                {
                    return;
                }
                Waiter w = null;
                w = PendingRequests.TryGetOrDefault(syncId);
                //set result and wake
                if (w != null)
                {
                    lock (w)
                    {
                        w.response = msg.payload;
                        Monitor.Pulse(w);
                    }
                }
                else
                {
                    DebugEx.TraceLog("w is null");
                }
            }
        }
コード例 #5
0
ファイル: PluginMain.cs プロジェクト: sm6uax/plegma
        private void GotButton(Bdaddr bdAddr)
        {
            DebugEx.TraceLog("Got Button");
            var thing = flicThings.TryGetOrDefault(bdAddr);

            if (thing == null)
            {
                thing = ThingTools.FlicThing.CreateThing(bdAddr.ToString().Replace(":", ""), bdAddr.ToString());
                thing = AddThing(thing);
                flicThings.Add(bdAddr, thing);
            }

            DebugEx.TraceLog("===========>Add Button Thing Completed");
            var channel = ButtonChannels.TryGetOrDefault(bdAddr);

            if (channel == null)
            {
                DebugEx.TraceLog("===========>New Channel is created");
                channel = new ButtonConnectionChannel(bdAddr);

                channel.CreateConnectionChannelResponse += (sender1, eventArgs) =>
                {
                    if (eventArgs.Error == CreateConnectionChannelError.NoError)
                    {
                        _channelConnected((ButtonConnectionChannel)sender1);
                    }
                    else
                    {
                        DebugEx.TraceError(((ButtonConnectionChannel)sender1).BdAddr.ToString() + " could not be connected");
                    }
                };
                channel.Removed += (sender1, eventArgs) =>
                {
                    _channelDisconnected((ButtonConnectionChannel)sender1);
                };
                channel.ConnectionStatusChanged += (sender1, eventArgs) =>
                {
                    var chan = (ButtonConnectionChannel)sender1;
                    if (eventArgs.ConnectionStatus == ConnectionStatus.Disconnected)
                    {
                        _channelDisconnected(chan);
                    }
                };
                channel.ButtonSingleOrDoubleClickOrHold += (sender1, eventArgs) =>
                {
                    var chan      = (ButtonConnectionChannel)sender1;
                    var thisThing = flicThings.TryGetOrDefault(chan.BdAddr);
                    if (thisThing == null)
                    {
                        return;
                    }

                    DebugEx.TraceLog(eventArgs.ClickType + " for " + thisThing.Name + " (key:" + thisThing.ThingKey + ")");
                    switch (eventArgs.ClickType)
                    {
                    case ClickType.ButtonSingleClick:
                        SetPortState(PortKey.BuildFromArbitraryString(thisThing.ThingKey, ThingTools.FlicThing.SingleClick), "True");
                        break;

                    case ClickType.ButtonDoubleClick:
                        SetPortState(PortKey.BuildFromArbitraryString(thisThing.ThingKey, ThingTools.FlicThing.DoubleClick), "True");
                        break;

                    case ClickType.ButtonHold:
                        SetPortState(PortKey.BuildFromArbitraryString(thisThing.ThingKey, ThingTools.FlicThing.LongClick), "True");
                        break;

                    default:
                        break;
                    }

                    if (!ButtonChannels.ContainsKey(chan.BdAddr))
                    {
                        _channelConnected(chan);
                    }
                };

                //try to add channel
                _flicClient.AddConnectionChannel(channel);
                DebugEx.TraceLog("===========>Add Connection Channel Completed");

                foreach (var navctx in NavigationContext.Values)
                {
                    DebugEx.TraceLog("===========>navctx.CurrentPage.Title: " + navctx.CurrentPage.Title);
                    if (navctx.CurrentPage.Title == "Flic Pairing")
                    {
                        DebugEx.TraceLog("=====>here I am <======");
                        navctx.GoBack();
                        navctx.UpdateCurrentPage(createDiscoverPage());
                    }
                }
            }
        }
コード例 #6
0
ファイル: NodeGraphManager.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        public GenericRsp HandleGraphDeploymentReq(GraphDeploymentReq req, bool SupressSave)
        {
            lock (locker)
            {
                var res = new GenericRsp();
                try
                {
                    //get graphkey
                    var graphkey = (GraphKey)req.GraphKey;
                    if (graphkey.IsInvalid)
                    {
                        res.IsSuccess = false;
                        res.Message   = "Invalid GraphKey";
                        return(res);
                    }
                    if (graphkey.NodeId != this.Node.NodeKey.NodeID)
                    {
                        res.IsSuccess = false;
                        res.Message   = "Invalid NodeID in GraphKey";
                        return(res);
                    }

                    //collect sets
                    var sets = Node.BeginActiveThingsUpdate();

                    //deploy or undeploy?
                    if (req.IsDeployed)
                    {
                        //deserialize graph descriptor
                        GraphDescriptor graphDescriptor;
                        try { graphDescriptor = GraphBuilder.GetGraphDescriptorFromJson(req.GraphDescriptor, false); }
                        catch (Exception ex)
                        {
                            DebugEx.Assert(ex, "Could not deserialize graph descriptor");
                            res.IsSuccess = false;
                            res.Message   = "Could not deserialize graph descriptor";
                            return(res);
                        }
                        graphDescriptor.GraphKey = graphkey;

                        //Build Graph
                        Graph graph;
                        try { graph = BuildGraph(graphDescriptor); }
                        catch (Exception ex)
                        {
                            DebugEx.Assert(ex, "Could not build graph from graph descriptor (unhandled exception)");
                            res.IsSuccess = false;
                            res.Message   = "Could not  build graph from graph descriptor (unhandled exception)";
                            return(res);
                        }
                        if (graph == null)
                        {
                            DebugEx.Assert("Could not build graph from graph descriptor");
                            res.IsSuccess = false;
                            res.Message   = "Could not  build graph from graph descriptor";
                            return(res);
                        }

                        //set key
                        graph.GraphKey = graphkey;

                        //do i already have it?
                        if (Graphs.ContainsKey(graphkey))
                        {
                            //invalidate graph
                            _GraphManager.InvalidateGraph(graphkey);
                            //remove information
                            Graphs.Remove(graphkey);
                        }

                        //try deploy graph
                        try
                        {
                            Exception exception;
                            var       depres = graph.OnDeploy(true, null, out exception);
                            if (!depres)
                            {
                                res.IsSuccess = false;
                                res.Message   = "Graph OnDeploy() failed. Message : " + (exception?.Message ?? "null");
                                return(res);
                            }
                        }
                        catch (Exception ex)
                        {
                            DebugEx.Assert(ex, "Graph OnDeploy() failed");
                            res.IsSuccess = false;
                            res.Message   = "Graph OnDeploy() failed. Message : " + ex.Message;
                            return(res);
                        }

                        //add to lookup
                        var gi = new GraphInfo()
                        {
                            GraphKey              = graphkey,
                            GraphDescriptor       = graphDescriptor,
                            GraphDescriptorString = req.GraphDescriptor,
                            Graph = graph,
                        };
                        Graphs.Add(graphkey, gi);

                        //save!
                        if (IsInitialized && !SupressSave)
                        {
                            Save();
                        }

                        //associate block keys
                        foreach (var thingblock in graph.Blocks.OfType <BaseThings>())
                        {
                            //Add to Thing2Block set
                            {
                                //find block key set
                                var set = ThingKey2BlockKey.TryGetOrDefault(thingblock.ThingKey);
                                if (set == null)
                                {
                                    set = new HashSetTS <BlockKey>();
                                    ThingKey2BlockKey.Add(thingblock.ThingKey, set);
                                }
                                //add to loockup set
                                set.Add(thingblock.BlockKey);
                            }

                            //Add only for thingIn
                            if (thingblock.IsThingIn)
                            {
                                //find block key set
                                var set = ThingKey2ThingInBlockKey.TryGetOrDefault(thingblock.ThingKey);
                                if (set == null)
                                {
                                    set = new HashSetTS <BlockKey>();
                                    ThingKey2ThingInBlockKey.Add(thingblock.ThingKey, set);
                                }
                                //add to loockup set
                                set.Add(thingblock.BlockKey);
                            }
                        }

                        //Handle Deploy
                        res.IsSuccess = true;
                        res.Message   = "Graph Deployed Successfully";
                    }
                    else
                    {
                        //Handle UnDeploy
                        if (Graphs.ContainsKey(graphkey) == false)
                        {
                            res.IsSuccess = true;
                            res.Message   = "Graph Undeployed Successfully (was not deployed)";
                        }
                        else
                        {
                            //get graph
                            var gi    = Graphs[graphkey];
                            var graph = gi.Graph;
                            //inform graph
                            Exception exception;
                            try
                            {
                                if (graph.OnUndeploy(null, out exception) == false)
                                {
                                    DebugEx.Assert(exception, "Graph OnUndeploy failed");
                                }
                            }
                            catch (Exception ex) { DebugEx.Assert(ex, "Graph OnUndeploy failed"); }
                            //invalidate graph
                            _GraphManager.InvalidateGraph(graphkey);
                            //remove information
                            Graphs.Remove(graphkey);
                            //save!
                            if (IsInitialized && !SupressSave)
                            {
                                Save();
                            }
                            //disassociate block keys
                            if (graph != null)
                            {
                                foreach (var thingblock in gi.Graph.Blocks.OfType <BaseThings>())
                                {
                                    //remove from thing2block
                                    {
                                        var set = ThingKey2BlockKey.TryGetOrDefault(thingblock.ThingKey);
                                        if (set != null)
                                        {
                                            set.Remove(thingblock.BlockKey);
                                        }
                                    }

                                    //remove from thignIn2block
                                    if (thingblock.IsThingIn)
                                    {
                                        var set = ThingKey2ThingInBlockKey.TryGetOrDefault(thingblock.ThingKey);
                                        if (set != null)
                                        {
                                            set.Remove(thingblock.BlockKey);
                                        }
                                    }
                                }
                            }
                            //done
                            res.IsSuccess = true;
                            res.Message   = "Graph Undeployed Successfully";
                        }
                    }

                    //finish update
                    Node.EndActiveThingsUpdate(sets);
                }
                catch (Exception ex)
                {
                    res.IsSuccess = false;
                    res.Message   = "Unhandled exception in GraphDeploymentReq(). Message=" + ex.Message;
                }
                finally
                {
                    //begin activation state snapshot
                    var sets = Node.BeginActiveThingsUpdate();

                    //update active ports/things
                    var activeThings = ThingKey2BlockKey.Where(kv => kv.Value.Count > 0)
                                       .Select(kv => Node.Things.TryGetOrDefaultReadOnly(kv.Key))
                                       .WhereNotNull().ToHashSetTS();
                    var activeThingKeys = activeThings.Select(t => (ThingKey)t.ThingKey).ToHashSetTS();

                    var activePorts     = activeThings.SelectMany(t => t.Ports).ToHashSetTS();
                    var activePortsKeys = activePorts.Select(p => (PortKey)p.PortKey).ToHashSetTS();

                    //update sets
                    Interlocked.Exchange(ref _ActiveThings, activeThings);
                    Interlocked.Exchange(ref _ActivePorts, activePorts);
                    Interlocked.Exchange(ref _ActiveThingKeys, activeThingKeys);
                    Interlocked.Exchange(ref _ActivePortKeys, activePortsKeys);

                    //trigger node thing activation update
                    Node.EndActiveThingsUpdate(sets);
                }
                //return result msg
                return(res);
            }
        }
コード例 #7
0
ファイル: NodeGraphManager.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        public void HandlePortStates(IEnumerable <TupleS <Port, string> > States)
        {
            lock (locker)
            {
                List <Yodiwo.Logic.GraphManager.SimultaneousActionRequest> simReq = null;

                foreach (var portEvent in States)
                {
                    var port     = portEvent.Item1;
                    var portKey  = (PortKey)port.PortKey;
                    var state    = portEvent.Item2;
                    var thingKey = portKey.ThingKey;

                    //checks
                    if (port == null)
                    {
                        DebugEx.TraceError("Invalid portkey");
                        continue;
                    }
                    if (portKey.IsInvalid)
                    {
                        DebugEx.TraceError("Invalid portkey");
                        continue;
                    }

                    //find thing block set
                    var blockSet = ThingKey2ThingInBlockKey.TryGetOrDefault(thingKey);
                    if (blockSet == null)
                    {
                        continue;
                    }

                    //Update state and revision number
                    lock (port)
                    {
                        //Interlocked.Increment(ref port.RevNum); //TODO: should increase?
                        port.State = state;
                    }

                    //create action update message
                    var data = new Logic.Blocks.Things.ThingUpdateAction
                    {
                        PortKey   = portKey,
                        PortState = state,
                    };

                    //create a simultaneous action requests
                    foreach (var bk in blockSet)
                    {
                        var _req = new Yodiwo.Logic.GraphManager.SimultaneousActionRequest()
                        {
                            BlockKey        = bk,
                            BlockActionData = data,
                        };
                        //add to simReq
                        if (simReq == null)
                        {
                            simReq = new List <GraphManager.SimultaneousActionRequest>();
                        }
                        simReq.Add(_req);
                        DebugEx.TraceLog("send event for thing " + thingKey + " block " + bk);
                    }
                }

                //send action request
                if (simReq != null && simReq.Count > 0)
                {
                    GraphManager.RequestGraphAction(simReq);
                }

                //done
            }
        }
コード例 #8
0
ファイル: Server.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        void HandleNewConnection(Socket newsocket)
        {
            try
            {
                #region check reconnection throttle
                try
                {
                    //setup socket
                    newsocket.ReceiveTimeout = -1;
                    newsocket.SendTimeout    = 60 * 1000;

#if NETFX
                    var re = newsocket.RemoteEndPoint.GetIPAddress().ToStringInvariant();
#elif UNIVERSAL
                    var re = newsocket.Information.RemoteAddress.ToStringInvariant();
#endif
                    //filtering
                    if (OnNewSocketConnectionFilter != null && OnNewSocketConnectionFilter(this, re) == false)
                    {
#if NETFX
                        try { newsocket.Close(); } catch { }
#endif
                        try { newsocket.Dispose(); } catch { }
                        DebugEx.TraceWarning("Connection from " + re + " closed from filter");
                        return;
                    }

                    if (IsReconnectionThrottleEnabled && re != "127.0.0.1" && re != "localhost") //no reconnection throttle for localhost connections
                    {
                        var rbe = reconnectThrottleBookKeeper.TryGetOrDefault(re);
                        if (rbe == null)
                        {
                            rbe = new ReconnectionBookkeepEntry()
                            {
                                ConnectionTimestamp = DateTime.Now + TimeSpan.FromMilliseconds(100),
                                Connections         = 1,
                            };
                            reconnectThrottleBookKeeper.ForceAdd(re, rbe);
                        }
                        else
                        {
                            if (++rbe.Connections > ReconnectionThrottleAfterConnectionCount)
                            {
                                var elapsed = DateTime.Now - rbe.ConnectionTimestamp;
                                if (elapsed < ReconnectionThrottleTimeout)
                                {
#if NETFX
                                    try { newsocket.Close(); } catch { }
#endif
                                    try { newsocket.Dispose(); } catch { }
                                    DebugEx.TraceWarning("Connection from " + re + " closed due to reconnection throttle (" + elapsed.Seconds + " sec)");
                                    return;
                                }
                            }
                        }
                    }
                }
                catch (Exception ex) { DebugEx.TraceWarning(ex, "YPServer Reconnection throttle exception"); }

                //cleanup old entries
                reconnectThrottleBookKeeper.RemoveWhere(e => DateTime.Now - e.Value.ConnectionTimestamp > ReconnectionThrottleTimeout);
                #endregion

                //start task new connection
                Task.Run(() =>
                {
                    ServerChannel channel = null;
                    string channelKey     = null;

                    Thread.Sleep(MathTools.GetRandomNumber(1, 100));
                    try
                    {
                        //check
#if NETFX
                        if (!newsocket.Connected)
                        {
                            DebugEx.TraceWarning("YPServer newsocket not connected?");
                            try { newsocket.Close(); } catch { }
                            return;
                        }
#endif
                        //create channel
                        var con = ChannelConstructor;
                        channel = con == null ? new ServerChannel(this, Protocols, SupportedChannelSerializationModes, PreferredChannelSerializationModes, newsocket) : con(Protocols, newsocket);
                        if (channel == null)
                        {
                            DebugEx.Assert("Could not create channel");
#if NETFX
                            try { newsocket.Close(); } catch { }
#endif
                            try { newsocket.Dispose(); } catch { }
                            return;
                        }

                        //add to set
                        lock (_Channels)
                        {
                            //generate unique key
                            while (IssuedKeys.ContainsKey(channelKey = MathTools.GenerateRandomAlphaNumericString(64)))
                            {
                                ;
                            }
                            //set on channel
                            channel._ChannelKey = channelKey;
                            //add to lookups
                            _Channels.Add(channel);
                            IssuedKeys.Add(channelKey, channel);
                        }

                        //start task timeout monitor
                        bool setupFinished = false;
                        Task.Run(() =>
                        {
                            try
                            {
                                //wait
                                Thread.Sleep(30000);
                                //check
                                if (!setupFinished)
                                {
                                    DebugEx.TraceLog($"ServerChannel setup timeout ({channel})");
                                    try { channel.Close("ServerChannel setup timeout"); } catch { }
#if NETFX
                                    try { newsocket?.Close(); } catch { }
#endif
                                    try { newsocket?.Dispose(); } catch { }

                                    //remove from lookups
                                    lock (_Channels)
                                    {
                                        if (channel != null)
                                        {
                                            _Channels.Remove(channel);
                                        }
                                        if (channelKey != null)
                                        {
                                            IssuedKeys.Remove(channelKey);
                                        }
                                    }
                                    return;
                                }
                            }
                            catch (Exception ex)
                            {
                                DebugEx.Assert(ex, $"Unhandled exception ({channel})");
#if NETFX
                                try { newsocket?.Close(); } catch { }
#endif
                                try { newsocket?.Dispose(); } catch { }

                                //remove from lookups
                                lock (_Channels)
                                {
                                    if (channel != null)
                                    {
                                        _Channels.Remove(channel);
                                    }
                                    if (channelKey != null)
                                    {
                                        IssuedKeys.Remove(channelKey);
                                    }
                                }
                                return;
                            }
                        });

                        //set serializer
                        channel.MsgPack = MsgPackSerializer;

                        //setup channel socket
                        if (channel.SetupServerSocket() == false)
                        {
#if NETFX
                            try { newsocket?.Close(); } catch { }
#endif
                            try { newsocket?.Dispose(); } catch { }

                            //remove from lookups
                            lock (_Channels)
                            {
                                if (channel != null)
                                {
                                    _Channels.Remove(channel);
                                }
                                if (channelKey != null)
                                {
                                    IssuedKeys.Remove(channelKey);
                                }
                            }
                            return;
                        }

                        //mark setup finish
                        setupFinished = true;

                        //call event
                        OnNewChannel?.Invoke(this, channel);

                        //start heartbeat
                        channel.Start();
                    }
                    catch (Exception ex)
                    {
                        DebugEx.Assert(ex, "YPServer: Failed setting up new connection for " + channel);
#if NETFX
                        try { newsocket.Close(); } catch { }
#endif
                        try { newsocket.Dispose(); } catch { }

                        //remove from lookups
                        lock (_Channels)
                        {
                            if (channel != null)
                            {
                                _Channels.Remove(channel);
                            }
                            if (channelKey != null)
                            {
                                IssuedKeys.Remove(channelKey);
                            }
                        }
                        return;
                    }
                });
            }
            catch (Exception ex)
            {
                DebugEx.Assert(ex, "YPChannel server setup new connection error");
            }
        }
コード例 #9
0
ファイル: NodeDiscoverManager.cs プロジェクト: sm6uax/plegma
        //------------------------------------------------------------------------------------------------------------------------
        private void Discoverer_OnEndpointMsgRx(YPChannel.Transport.Sockets.LANDiscoverer.RemoteEndpointInfo endpoint, YPChannel.Transport.Sockets.IDiscoveryMessageBase __msg)
        {
            try
            {
                //get valid msg
                var msg = __msg as DiscoveryMessage;
                if (msg == null)
                {
                    return;
                }

                //create remotenodekey
                var rem_nodekey = API.Plegma.NodeKey.FromBytes(msg.NodeKey, 0);
                if (rem_nodekey.IsInvalid)
                {
                    return;
                }

                //examine existing association
                lock (RemoteNodes)
                {
                    var remInfo = RemoteNodes.TryGetOrDefault(endpoint.ID);
                    if (remInfo == null)
                    {
                        //inform
                        DebugEx.TraceLog($"NodeDiscoverer : Discovered new node. (ip:{endpoint.IPAddress} nodekey:{rem_nodekey})");

                        //create entry for remote node
                        remInfo = new RemoteNode(Node, TimeSpan.FromMinutes(5), this)
                        {
                            RemoteEndpointID = endpoint.ID,
                            DiscoveryMessage = msg,
                            RemoteNodeKey    = rem_nodekey,
                        };
                        //add to discovered remote nodes
                        RemoteNodes.Add(endpoint.ID, remInfo);

                        //hookevents
                        hookNewRemoteNodeEvents(remInfo);

                        //Start a connection attempt
                        remInfo.StartConnectionTask();

                        //raise event
                        if (OnRemoteNodeDiscovery != null)
                        {
                            Task.Run(() => { try { OnRemoteNodeDiscovery?.Invoke(remInfo); } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled exception"); } });
                        }
                    }
                    else
                    {
                        //start remote node connection
                        if (!remInfo.IsDisposed &&
                            (remInfo.ClientChannel == null || (remInfo.ClientChannel.State == YPChannel.ChannelStates.Closed && !remInfo.ConnectionTaskRunning)))
                        {
                            remInfo.StartConnectionTask();
                        }
                    }
                }
            }
            catch (Exception ex) { DebugEx.TraceError(ex, "DiscoveryTaskEntryPoint error"); }
        }