/// <summary> /// Publishes a message. /// </summary> /// <param name="contract">The contract</param> /// <param name="message">The message to publish.</param> /// <param name="channelHash">The hashed channel id.</param> /// <param name="channelName">The full name of the channel.</param> /// <param name="ttl">The time-to-live value for the message.</param> public static void Publish(EmitterContract contract, uint channelHash, string channelName, ArraySegment <byte> message, int ttl = EmitterConst.Transient) { try { // Make sure the TTL is within limits and max is 30 days. if (ttl < 0) { ttl = EmitterConst.Transient; } if (ttl > 2592000) { ttl = 2592000; } var contractId = contract.Oid; var cid = ((long)contractId << 32) + channelHash; // Increment the counter Service.MessageReceived?.Invoke(contract, channelName, message.Count); // The SSID var ssid = EmitterChannel.Ssid(contractId, channelName); // Get the subscriptions var subs = Subscription.Match(ssid); if (subs != null) { // Fast-Path: check local subscribers and send it to them ForwardToClients(contractId, channelName, message, subs); // Publish into the messaging cluster once ForwardToServers(contractId, channelName, message, subs); } // Only call into the storage service if necessary if (ttl > 0 && Services.Storage != null) { // If we have a storage service, store the message Services.Storage.AppendAsync(contractId, ssid, ttl, message); } } catch (Exception ex) { Service.Logger.Log(LogLevel.Warning, "Publish failed. Reason: " + ex.Message); //Service.Logger.Log(ex); return; } }
/// <summary> /// Forwards a message to a set of subscriptions /// </summary> internal static void ForwardToClients(int contractId, string channel, ArraySegment <byte> message) { // Separator must be added channel += EmitterConst.Separator; // Create an SSID var ssid = EmitterChannel.Ssid(contractId, channel); // Get the matching subscriptions var subs = Subscription.Match(ssid); if (subs == null) { return; } // Forward to the clients ForwardToClients(contractId, channel, message, subs); }
/// <summary> /// Unregisters a subscription from the current registry. /// </summary> /// <param name="client">The client to unsubscribe.</param> /// <param name="contract">The contract.</param> /// <param name="channel"></param> /// <returns>Whether the subscription was removed or not.</returns> public static bool Unregister(IMqttSender client, int contract, string channel, SubscriptionInterest interest, out Subscription subs) { // Make the subscription id var ssid = EmitterChannel.Ssid(contract, channel); // Get the subscription first if (!Index.TryGetValue(ssid, 0, out subs)) { return(false); } // Validate, only the correct contract can unsubscribe if (subs.ContractKey != contract) { return(false); } // Unregister a client subs.Unsubscribe(client, interest); return(true); }
/// <summary> /// Disposes the subscription. /// </summary> public void Dispose() { try { // Unbind events if (this.Presence != null) { this.Presence.Change -= this.OnPresenceChange; } // Get the ssid var ssid = EmitterChannel.Ssid(this.ContractKey, this.Channel); // Remove the subscription from the registry Subscription removed; Index.TryRemove(ssid, 0, out removed); } catch (Exception ex) { Service.Logger.Log(ex); } }
/// <summary> /// Unregisters a subscription from the current registry. /// </summary> /// <param name="server">The server to unsubscribe.</param> /// <param name="contract">The contract.</param> /// <param name="channel"></param> /// <returns>Whether the subscription was removed or not.</returns> public static bool Unregister(IServer server, int contract, string channel) { // Make the subscription id var ssid = EmitterChannel.Ssid(contract, channel); // Get the subscription first Subscription subs; if (!Index.TryGetValue(ssid, 0, out subs)) { return(false); } // Validate, only the correct contract can unsubscribe if (subs.ContractKey != contract) { return(false); } // Unregister a server subs.Unsubscribe(server); return(false); }
/// <summary> /// Adds or updates the subscription. /// </summary> /// <param name="channel">The channel for the subscription to find.</param> /// <param name="contract">The channel for the subscription to find.</param> /// <param name="addFunc">The add function to execute.</param> /// <param name="updateFunc">The update function to execute.</param> /// <returns></returns> public Subscription AddOrUpdate(int contract, string channel, Func <Subscription> addFunc, Func <Subscription, Subscription> updateFunc) { return(this.AddOrUpdate(EmitterChannel.Ssid(contract, channel), 0, addFunc, updateFunc)); }
/// <summary> /// Attempts to fetch a subscription from the trie. /// </summary> /// <param name="sub">The subscription retrieved.</param> /// <param name="channel">The channel for the subscription to find.</param> /// <param name="contract">The channel for the subscription to find.</param> /// <returns>Whether the subscription was found or not.</returns> public bool TryGetValue(int contract, string channel, out Subscription sub) { return(this.TryGetValue(EmitterChannel.Ssid(contract, channel), 0, out sub)); }
/// <summary> /// Attempts to remove a subscription from the trie. /// </summary> /// <param name="sub">The subscription to remove.</param> /// <returns>Whether the subscription was removed or not.</returns> public bool TryRemove(Subscription sub) { Subscription removed; return(this.TryRemove(EmitterChannel.Ssid(sub.ContractKey, sub.Channel), 0, out removed)); }
/// <summary> /// Attempts to add a subscription to the trie. /// </summary> /// <param name="sub">The subscription to add.</param> /// <returns>Whether the subscription was added or not.</returns> public bool TryAdd(Subscription sub) { return(this.TryAdd(EmitterChannel.Ssid(sub.ContractKey, sub.Channel), sub)); }