//------------------------------------------------------------------------------------------------------------------------ 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"); } }
//------------------------------------------------------------------------------------------------------------------------ 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); } } }
//------------------------------------------------------------------------------------------------------------------------ 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"); } }
//------------------------------------------------------------------------------------------------------------------------ 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"); } } }
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()); } } } }
//------------------------------------------------------------------------------------------------------------------------ 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); } }
//------------------------------------------------------------------------------------------------------------------------ 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 } }
//------------------------------------------------------------------------------------------------------------------------ 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"); } }
//------------------------------------------------------------------------------------------------------------------------ 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"); } }