/// <summary> /// Extracts the Envelope's header. /// </summary> /// <param name="envelope">The <see cref="TransportEnvelope"/> to retrieve the header from.</param> /// <returns>The <see cref="ITransportEnvelopeHeader"/> belonging to the given <see cref="TransportEnvelope"/>.</returns> public ITransportEnvelopeHeader ExtractHeader(TransportEnvelope envelope) { return((new Converters.TypeSerializer <ITransportEnvelopeHeader>()) .FromByteArray(TransportConfiguration.Compressor .Decompress(TransportConfiguration.Encryptor .Decrypt(envelope.Header)))); }
/// <summary> /// Takes an <see cref="TransportEnvelope"/> and sends it to the server. /// </summary> /// <param name="envelope">The <see cref="TransportEnvelope"/> to transmit to the server.</param> /// <param name="exception">Contains any exceptions encountered; otherwise <b>null</b>.</param> /// <returns><b>True</b> if successful; otherwise <b>false</b>.</returns> protected override bool PushEnvelopeToServer(TransportEnvelope envelope, out Exception exception) { // ******** SEND ENVELOPE TO SERVER ******** bool results = false; if (_ServiceProxy == null) { exception = new Exception("The client has been closed."); } else { exception = null; try { _ServiceProxy.PushEnvelopeToServer(envelope); results = true; } catch (Exception ex) { DestroyConnection(); exception = new Exception($"Unable to establish connection with server at {Address}", ex); } } return(results); }
/// <summary> /// Transmits a <see cref="TransportEnvelope"/> to the <b>Actual Client</b>. /// </summary> /// <param name="envelope">A piece of an <see cref="IMessage"/> to be transmitted to the <b>Actual Client</b>.</param> public void PushEnvelopeToClient(TransportEnvelope envelope) { // ******** RECIEVED ENVELOPE FROM SERVER ******** IMessage message = _TransporterController.AddEnvelopeFromTransport(envelope); if (message != null) { _MessageChannelAction(new MessageEventArgs(message)); } }
/// <summary> /// Takes <see cref="TransportEnvelope"/>s and puts them together into a whole <see cref="IMessage"/>. /// </summary> /// <param name="envelope">The <see cref="TransportEnvelope"/> to process.</param> /// <returns>If enough chucks have arrived to create a whole message; then that message will be returned; otherwise, <b>null</b>.</returns> public IMessage AddEnvelopeFromTransport(TransportEnvelope envelope) { if (envelope == null) { throw new ArgumentNullException("envelope"); } // update statistics lock (_SyncRootTransportStatistics) { _TransportStatistics.IncomingEnvelopes++; _TransportStatistics.IncomingBytes += (envelope.Header.Length + envelope.Payload.Length); } // envelope.HeaderActual = ExtractHeader(envelope); IMessage message = null; lock (_SyncRootEnvelopeCache) { // #### add envelope to proper group if (_EnvelopeCache.ContainsKey(envelope.HeaderActual.Id)) { // update existing group _EnvelopeCache[envelope.HeaderActual.Id].Payload.Envelopes.Add(envelope); } else { // create new group var group = new TransportEnvelopeGroup(envelope.HeaderActual.Id, envelope.HeaderActual); group.Envelopes.Add(envelope); var cacheItem = new Cache.CacheItem <TransportEnvelopeGroup>(group, new Cache.ValidateTime <TransportEnvelopeGroup>(DateTime.Now.Add(TransportConfiguration.EnvelopeCacheTimeLimit))); _EnvelopeCache.AddItem(envelope.HeaderActual.Id, cacheItem); } // #### check for completed message string processedMessageId = ""; foreach (var cacheItem in _EnvelopeCache.Items) { var expectedTotal = cacheItem.Payload.Header.ChunkTotal; var total = cacheItem.Payload.Envelopes.Count; if (expectedTotal == total) { processedMessageId = cacheItem.Payload.Id; var worker = Common.ByteArrayHelper.RestoreByteArray(from x in cacheItem.Payload.Envelopes orderby x.HeaderActual.ChunkIndex ascending select x.Payload); worker = TransportConfiguration.Encryptor.Decrypt(worker); worker = TransportConfiguration.Compressor.Decompress(worker); message = (new dodSON.Core.Converters.TypeSerializer <IMessage>()).FromByteArray(worker); // update statistics lock (_SyncRootTransportStatistics) { _TransportStatistics.IncomingMessages++; } } } // #### remove processed message if (_EnvelopeCache.ContainsKey(processedMessageId)) { _EnvelopeCache.RemoveItem(processedMessageId); } // courtesy purge _EnvelopeCache.Purge(); // #### check if message has already been processed if (message != null) { // #### primary gate --> cached message id lock (_SyncRootSeenMessagesCache) { // check cache for seen message if (_SeenMessagesCache.ContainsKey(message.Id)) { // reset cached item _SeenMessagesCache[message.Id].Validator.Reset(); // message stops here. return(null); } // add message.Id to cache _SeenMessagesCache.AddItem(message.Id, new Cache.CacheItem <string>(message.Id, new Cache.ValidateTime <string>(DateTime.Now + TransportConfiguration.SeenMessageCacheTimeLimit))); // courtesy purge _SeenMessagesCache.Purge(); } // #### fail-safe gate --> server id list // check if server id in ServerIds list if (message.ServerIds.Split(',').Contains(TransportConfiguration.ServerId)) { // message stops here. return(null); } // add server id to ServerIds list var comma = (message.ServerIds.Length == 0) ? "" : ","; message.ServerIds += comma + TransportConfiguration.ServerId; } // #### allow message to continue... return(message); } }
private void InternalSendEnvelopeToClient(TransportEnvelope envelope, DataHolder registeredClient) { registeredClient.CallbackClient.PushEnvelopeToClient(envelope); registeredClient.LastUsed = DateTime.Now; }
/// <summary> /// Transmits the <see cref="TransportEnvelope"/> to the server. /// </summary> /// <param name="envelope">The <see cref="TransportEnvelope"/> to send to the server.</param> public void PushEnvelopeToServer(TransportEnvelope envelope) { // ******** RECIEVED ENVELOPE FROM CLIENT ******** if (envelope != null) { System.Threading.Tasks.Task.Run(() => { // extract header, update stats ITransportEnvelopeHeader header = null; lock (_SyncRootTransporterController) { TransporterController.TransportStatisticsLive.IncomingEnvelopes++; TransporterController.TransportStatisticsLive.IncomingBytes += (envelope.Header.Length + envelope.Payload.Length); header = TransporterController.ExtractHeader(envelope); } // get list of registered clients List <KeyValuePair <string, DataHolder> > workerList = null; var removableClients = new List <string>(); lock (_SyncRootRegisteredCallbackClients) { workerList = new List <KeyValuePair <string, DataHolder> >(_RegisteredCallbackClients); } // send envelope to each registered client, that will accept it System.Threading.Tasks.Parallel.ForEach(workerList, new Action <KeyValuePair <string, DataHolder> >( (x) => { try { // handle type-based traffic filtering if (CanSendEnvelope(header, x.Value.ClientConfiguration, OverrideTypesFilter)) { lock (_SyncRootTransporterController) { TransporterController.TransportStatisticsLive.OutgoingEnvelopes++; TransporterController.TransportStatisticsLive.OutgoingBytes += (envelope.Header.Length + envelope.Payload.Length); } InternalSendEnvelopeToClient(envelope, x.Value); } else { } } catch { removableClients.Add(x.Value.ClientConfiguration.Id); } })); // **** unregister unresponsive clients foreach (var clientId in removableClients) { if (clientId != null) { lock (_SyncRootRegisteredCallbackClients) { if (_RegisteredCallbackClients.ContainsKey(clientId)) { _RegisteredCallbackClients.Remove(clientId); } } } } }); } else { // TODO: A null envelope? what could have caused this and what should I do about it? } }