/// <summary> /// Handler method to create a network channel /// </summary> /// <returns>The network channel.</returns> /// <param name="scope">The scope calling the method.</param> /// <param name="attr">The channel attribute.</param> /// <param name="type">The type to create the channel for</param> private static IUntypedChannel Creator(ChannelScope scope, ChannelNameAttribute attr, Type type) { return ((IUntypedChannel)typeof(NetworkChannelScope) .GetMethod(nameof(CreateNetworkChannel), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.NonPublic) .MakeGenericMethod(type) .Invoke(scope, new object[] { attr })); }
/// <summary> /// Runs the channel handler. /// </summary> /// <param name="nwc">The network client used for communicating.</param> /// <param name="sc">The scope where channels are created.</param> protected static async void RunChannelHandler(NetworkClient nwc, ChannelScope sc) { await nwc.ConnectAsync(); var transactions = new Dictionary <string, TwoPhaseNetworkHandler>(); var lck = new object(); using (nwc) while (true) { var req = await nwc.ReadAsync(); // If this is a channel creation request, hijack it here if (req.RequestType == NetworkMessageType.CreateChannelRequest) { var chancfg = req.Value as ChannelNameAttribute; sc.GetOrCreate(chancfg, req.ChannelDataType); continue; } var chan = sc.GetOrCreate(req.ChannelID, req.ChannelDataType); switch (req.RequestType) { case NetworkMessageType.JoinRequest: ((IJoinAbleChannel)chan).Join((bool)req.Value); break; case NetworkMessageType.LeaveRequest: ((IJoinAbleChannel)chan).Leave((bool)req.Value); break; case NetworkMessageType.RetireRequest: chan.Retire((bool)req.Value); break; case NetworkMessageType.OfferAcceptResponse: transactions[req.RequestID].Accepted(); break; case NetworkMessageType.OfferDeclineResponse: transactions[req.RequestID].Denied(); break; case NetworkMessageType.ReadRequest: lock (lck) transactions[req.RequestID] = req.NoOffer ? null : new TwoPhaseNetworkHandler(req, nwc); ((IUntypedChannel)chan).ReadAsync(TimeoutToTimeSpan(req.Timeout), transactions[req.RequestID]).ContinueWith(async x => { NetworkMessageType responsetype; object responseitem = null; if (x.IsCanceled) { responsetype = NetworkMessageType.CancelResponse; } else if (x.IsFaulted && x.Exception.IsRetiredException()) { responsetype = NetworkMessageType.RetiredResponse; } else if (x.IsFaulted && x.Exception.IsTimeoutException()) { responsetype = NetworkMessageType.TimeoutResponse; } else if (x.IsFaulted) { responsetype = NetworkMessageType.FailResponse; responseitem = x.Exception; } else { responsetype = NetworkMessageType.ReadResponse; responseitem = await x; } lock (lck) transactions.Remove(req.RequestID); await nwc.WriteAsync(new PendingNetworkRequest( req.ChannelID, req.ChannelDataType, req.RequestID, req.SourceID, new DateTime(0), responsetype, responseitem, true )); }).FireAndForget(); break; case NetworkMessageType.WriteRequest: lock (lck) transactions[req.RequestID] = req.NoOffer ? null : new TwoPhaseNetworkHandler(req, nwc); ((IUntypedChannel)chan).WriteAsync(req.Value, TimeoutToTimeSpan(req.Timeout), transactions[req.RequestID]).ContinueWith(async x => { NetworkMessageType responsetype; object responseitem = null; if (x.IsCanceled) { responsetype = NetworkMessageType.CancelResponse; } else if (x.IsFaulted && x.Exception.IsRetiredException()) { responsetype = NetworkMessageType.RetiredResponse; } else if (x.IsFaulted && x.Exception.IsTimeoutException()) { responsetype = NetworkMessageType.TimeoutResponse; } else if (x.IsFaulted) { responsetype = NetworkMessageType.FailResponse; responseitem = x.Exception; } else { responsetype = NetworkMessageType.WriteResponse; } lock (lck) transactions.Remove(req.RequestID); await nwc.WriteAsync(new PendingNetworkRequest( req.ChannelID, req.ChannelDataType, req.RequestID, req.SourceID, new DateTime(0), responsetype, responseitem, true )); }).FireAndForget(); break; default: throw new Exception("Unsupported message: {0}"); } } }