/// <summary> /// Publish a message to clients. /// </summary> public void Publish <TMessage>(TMessage message, UInt32 topic) where TMessage : IExportableMessage, new() { // Handle un-publishes if (null == message) { TopicRecords.TryRemove(topic, out var a); return; } // Extract typecode var typeCode = message.TypeCode; // Extract payload var payload = message.Export(); Trace.WriteLineIf(payload.Count + Constants.SERVERTXHEADER_LENGTH > Mtu, $"Publish value length exceeds MTU set in options and will probably be dropped by the network. Sending anyway. ([Header]{Constants.SERVERTXHEADER_LENGTH} + [Value]{payload.Count} > [MTU]{Mtu})", "server-publish-warning"); lock (Sync) { if (IsDisposed) { throw new ObjectDisposedException("Object disposed."); } if (!IsStarted) { throw new InvalidOperationException("Not yet started."); } var record = new TopicRecord(); // Note that SendAfter initializes as '0000-00-00 00:00:00' // Calculate new revision if (TopicRecords.TryGetValue(topic, out var lastRecord)) { record.Revision = lastRecord.Revision; } else { record.Revision = UInt16.MaxValue; } record.Revision++; // Add all subscribers as pending recipents record.PendingSubscribers = SubscriberRecords.Select(a => a.Key).ToArray(); // Compose packet record.Packet = new Byte[Constants.SERVERTXHEADER_LENGTH + payload.Count]; Buffer.BlockCopy(BitConverter.GetBytes(typeCode), 0, record.Packet, 0, 4); // UInt32 typecode Buffer.BlockCopy(BitConverter.GetBytes(topic), 0, record.Packet, 4, 4); // UInt32 topic Buffer.BlockCopy(BitConverter.GetBytes(record.Revision), 0, record.Packet, 8, 2); // UInt16 revision Buffer.BlockCopy(payload.Array, payload.Offset, record.Packet, 10, payload.Count); // Byte[?] value // Release topic update TopicRecords[topic] = record; SendLock.Set(); } }
public void Publish <TMessage>(TMessage message, UInt32 topic = 0, UInt32 channel = 0) where TMessage : IExportableMessage { // Handle un-publishes if (null == message) { TopicRecords.TryRemove(topic, out var a); return; } // Extract payload var payload = message.Export(); lock (Sync) { if (IsDisposed) { throw new ObjectDisposedException("Object disposed."); } // Create new topic record var record = new TopicRecord() { Channel = channel, Revision = 0 }; // Calculate new revision if (TopicRecords.TryGetValue(topic, out var lastRecord)) { record.Revision = lastRecord.Revision + 1; } // Compose packet var packet = new Byte[Constants.SERVERTXHEADER_LENGTH + payload.Count]; Buffer.BlockCopy(BitConverter.GetBytes(topic), 0, packet, 0, 4); // UInt32 topic Buffer.BlockCopy(BitConverter.GetBytes(record.Revision), 0, packet, 4, 4); // UInt32 revision Buffer.BlockCopy(payload.Array, payload.Offset, packet, 8, payload.Count); // Byte[?] value record.Packet = new ArraySegment <Byte>(packet); // Release topic update TopicRecords[topic] = record; foreach (var subscriber in SubscriberRecords.Values) { if (subscriber.Channels.Contains(channel)) // Over optimisation? { subscriber.SendLock.Set(); } } } }