public void RegisterListener(int messageId, ClientMessageListener listener) { if (!messageListenerDic.TryGetValue(messageId, out var list)) { list = ListPool <ClientMessageListener> .Get(); messageListenerDic.Add(messageId, list); } list.Add(listener); }
public void UnregisterListener(int messageId, ClientMessageListener listener) { if (messageListenerDic.TryGetValue(messageId, out var list)) { if (list.Remove(listener)) { if (list.Count == 0) { messageListenerDic.Remove(messageId); ListPool <ClientMessageListener> .Release(list); } } } }
/// <summary> /// Operation method that sends a message to the Server. The message is interpreted and handled by /// the Metadata Adapter associated to the current Session. This operation supports in-order /// guaranteed message delivery with automatic batching. In other words, messages are guaranteed /// to arrive exactly once and respecting the original order, whatever is the underlying transport /// (HTTP or WebSockets). Furthermore, high frequency messages are automatically batched, if necessary, /// to reduce network round trips. <br/> /// Upon subsequent calls to the method, the sequential management of the involved messages is guaranteed. /// The ordering is determined by the order in which the calls to sendMessage are issued. /// However, any message that, for any reason, doesn't reach the Server can be discarded by the Server /// if this causes the subsequent message to be kept waiting for longer than a configurable timeout. /// Note that, because of the asynchronous transport of the requests, if a zero or very low timeout is /// set for a message, it is not guaranteed that the previous message can be processed, even if no communication /// issues occur. <br/> /// Sequence identifiers can also be associated with the messages. In this case, the sequential management is /// restricted to all subsets of messages with the same sequence identifier associated. <br/> /// Notifications of the operation outcome can be received by supplying a suitable listener. The supplied /// listener is guaranteed to be eventually invoked; listeners associated with a sequence are guaranteed /// to be invoked sequentially. <br/> /// The "UNORDERED_MESSAGES" sequence name has a special meaning. For such a sequence, immediate processing /// is guaranteed, while strict ordering and even sequentialization of the processing is not enforced. /// Likewise, strict ordering of the notifications is not enforced. However, messages that, for any reason, /// should fail to reach the Server whereas subsequent messages had succeeded, might still be discarded after /// a server-side timeout. <br/> /// Moreover, if "UNORDERED_MESSAGES" is used and no listener is supplied, a "fire and forget" scenario /// is assumed. In this case, no checks on missing, duplicated or overtaken messages are performed at all, /// so as to optimize the processing and allow the highest possible throughput. /// /// <b>Lifecycle:</b> Since a message is handled by the Metadata Adapter associated to the current connection, a /// message can be sent only if a connection is currently active. If the special enqueueWhileDisconnected /// flag is specified it is possible to call the method at any time and the client will take care of sending /// the message as soon as a connection is available, otherwise, if the current status is "DISCONNECTED*", /// the message will be abandoned and the <seealso cref="ClientMessageListener.onAbort"/> event will be fired. <br/> /// Note that, in any case, as soon as the status switches again to "DISCONNECTED*", any message still pending /// is aborted, including messages that were queued with the enqueueWhileDisconnected flag set to true. <br/> /// Also note that forwarding of the message to the server is made appending the request to /// the internal scheduler queue; hence, if a message /// is sent while the connection is active, it could be aborted because of a subsequent disconnection. /// In the same way a message sent while the connection is not active might be sent because of a subsequent /// connection. /// </summary> /// <param name="message"> a text message, whose interpretation is entirely demanded to the Metadata Adapter /// associated to the current connection. </param> /// <param name="sequence"> an alphanumeric identifier, used to identify a subset of messages to be managed in sequence; /// underscore characters are also allowed. If the "UNORDERED_MESSAGES" identifier is supplied, the message will /// be processed in the special way described above. The parameter is optional; if set to null, "UNORDERED_MESSAGES" /// is used as the sequence name. </param> /// <param name="delayTimeout"> a timeout, expressed in milliseconds. If higher than the Server default timeout, the /// latter will be used instead. <br/> /// The parameter is optional; if a negative value is supplied, the Server default timeout will be applied. <br/> /// This timeout is ignored for the special "UNORDERED_MESSAGES" sequence, for which a custom server-side /// timeout applies. </param> /// <param name="listener"> an object suitable for receiving notifications about the processing outcome. The parameter is /// optional; if not supplied, no notification will be available. </param> /// <param name="enqueueWhileDisconnected"> if this flag is set to true, and the client is in a disconnected status when /// the provided message is handled, then the message is not aborted right away but is queued waiting for a new /// session. Note that the message can still be aborted later when a new session is established. </param> public virtual void sendMessage(string message, string sequence, int delayTimeout, ClientMessageListener listener, bool enqueueWhileDisconnected) { lock (this) { if (string.ReferenceEquals(sequence, null)) { sequence = Constants.UNORDERED_MESSAGES; } else if (!ext_alpha_numeric.Match(sequence).Success) { throw new System.ArgumentException("The given sequence name is not valid, use only alphanumeric characters plus underscore, or null"); } string seq = sequence; eventsThread.queue(() => { messages.send(message, seq, delayTimeout, listener, enqueueWhileDisconnected); }); } }