/// <summary> /// Removes the client. /// </summary> /// <param name = "client">The client.</param> public void RemoveClient(IStompClient client) { Log.Info(string.Format("Removing client {0}", client.SessionId)); if (!_clients.ContainsKey(client)) { Log.Info(string.Format("Client to remove not found {0}", client.SessionId)); return; } SubscriptionMetadata meta; if (_clients.TryRemove(client, out meta)) { if (meta.OnCloseHandler != null) { client.OnClose -= meta.OnCloseHandler; } } // raise the last client removed event if needed if (!_clients.Any() && OnLastClientRemoved != null) { OnLastClientRemoved(this); } }
public IFrame Process(IStompClient client, IFrame request) { var versions = request.Headers["accept-version"]; if (versions == null) { var error = request.CreateError("Missing the 'accept-version' header."); error.Headers["version"] = "2.0"; return error; } if (!versions.Contains("2.0")) { var error = request.CreateError("Only accepting stomp 2.0 clients."); error.Headers["version"] = "2.0"; return error; } IFrame frame; if (!CheckCredentials(client, request, out frame)) return frame; //TODO: Heartbeating. var response = new BasicFrame("CONNECTED"); response.Headers["version"] = "2.0"; response.Headers["server"] = _serverName; if (client.SessionKey != null) response.Headers["session"] = client.SessionKey; return response; }
/// <summary> /// Adds the client. /// </summary> /// <param name = "client">The client.</param> /// <param name = "subscriptionId">The subscription id.</param> public void AddClient(IStompClient client, string subscriptionId) { Log.Info(string.Format("Adding client: {0}", client.SessionId)); if (_clients.ContainsKey(client)) { Log.Info(string.Format("Duplicate client found: {0}", client.SessionId)); return; } Action onClose = () => RemoveClient(client); client.OnClose += onClose; if (_clients.IsEmpty) { do { string body; if (Store.TryDequeue(out body)) { SendMessage(client, body, Guid.NewGuid(), subscriptionId); } } while (Store.HasMessages()); } _clients.TryAdd(client, new SubscriptionMetadata { Id = subscriptionId, OnCloseHandler = onClose }); }
/// <summary> /// Removes the frame from the client pending list and adds it back to the queue /// </summary> /// <param name="client">Connection that received the frame</param> /// <param name="request">Inbound frame to process</param> /// <returns> /// Frame to send back /// </returns> /// <exception cref="BadRequestException"> /// Missing the 'id' header in the frame. Required so that we know which message that the NACK is for. /// or /// </exception> public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["id"]; if (string.IsNullOrEmpty(id)) { throw new BadRequestException(request, "Missing the 'id' header in the frame. Required so that we know which message that the NACK is for."); } if (!client.IsFramePending(id)) { throw new BadRequestException(request, string.Format("Unknown message with id '{0}'. can therefore not NACK it.", id)); } var subscription = client.GetSubscription(id); var transactionId = request.Headers["transaction"]; if (!string.IsNullOrEmpty(transactionId)) { client.EnqueueInTransaction(transactionId, () => NackMessages(subscription, id), () => {}); return(null); } NackMessages(subscription, id); return(null); }
public StompMessage(IStompClient client, MessageFrame messageFrame, bool acknowledgeable, string transactionId = null) { _client = client; MessageFrame = messageFrame; IsAcknowledgeable = acknowledgeable; _transactionId = transactionId; }
/// <summary> /// Process an inbound frame. /// </summary> /// <param name="client">Connection that received the frame</param> /// <param name="request">Inbound frame to process</param> /// <returns> /// Frame to send back /// </returns> /// <exception cref="BadRequestException"> /// Missing the ID header in the frame. /// or /// </exception> public IFrame Process(IStompClient client, IFrame request) { if (client == null) { throw new ArgumentNullException("client"); } if (request == null) { throw new ArgumentNullException("request"); } var id = request.Headers["id"]; if (string.IsNullOrEmpty(id)) { throw new BadRequestException(request, "Missing the ID header in the frame."); } var subscription = client.RemoveSubscription(id); if (subscription == null) { throw new BadRequestException(request, string.Format("Failed to find an subscription with id '{0}'.", id)); } var queue = _queueRepository.Get(subscription.QueueName); if (queue == null) { //TODO: Log that the queue do not exist (even though our subscription existed). return(null); } queue.Unsubscribe(subscription); return(null); }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["id"]; if (id == null) { throw new BadRequestException(request, "You must include the 'id' header in the SUBSCRIBE frame."); } if (client.SubscriptionExists(id)) { throw new BadRequestException(request, string.Format("There is already a subscription with id '{0}'.", id)); } var ackType = GetAckType(request); var queue = GetQueue(request); var subscription = new Subscription(client, id) { AckType = ackType, QueueName = queue.Name }; queue.AddSubscription(subscription); client.AddSubscription(subscription); return(request.CreateReceiptIfRequired()); }
/// <summary> /// Sends an 'UNSUBSCRIBE' message /// </summary> public static void UnSubscribe(this IStompClient client, string destination) { var stompMsg = new StompMessage("UNSUBSCRIBE"); stompMsg["destination"] = destination; client.Send(stompMsg); }
/// <summary> /// Sends a 'SEND' message /// </summary> public static void Send(this IStompClient client, string message, string destination) { var stompMsg = new StompMessage("SEND", message); stompMsg["destination"] = destination; client.Send(stompMsg); }
/// <summary> /// Handles the CONNECT message /// </summary> /// <param name="client">The client.</param> /// <param name="message">The message.</param> private static void OnStompConnect(IStompClient client, StompMessage message) { var result = new StompMessage("CONNECTED"); result["session-id"] = client.SessionId.ToString(); client.Send(result); }
/// <summary> /// Handles the SUBSCRIBE message /// </summary> /// <param name="client">The client.</param> /// <param name="message">The message.</param> private void OnStompSubscribe(IStompClient client, StompMessage message) { string destination = message["destination"]; var queue = _queues.FirstOrDefault(s => s.Address == destination) ?? AddNewQueue(destination); queue.AddClient(client, message["id"]); }
/// <summary> /// Handles the SEND message /// </summary> /// <param name="client">The client.</param> /// <param name="message">The message.</param> private void OnStompSend(IStompClient client, StompMessage message) { var destination = message["destination"]; var queue = _queues.FirstOrDefault(s => s.Address == destination) ?? AddNewQueue(destination); queue.Publish(message.Body); }
/// <summary> /// /// </summary> /// <param name="client">Client that the subscription belongs to</param> /// <param name="id">Arbitrary string as specified by the client.</param> public Subscription(IStompClient client, string id) { if (client == null) throw new ArgumentNullException("client"); if (id == null) throw new ArgumentNullException("id"); Id = id; Client = client; MaxMessagesPerSecond = 5; }
/// <summary> /// Process an inbound frame. /// </summary> /// <param name="client">Connection that received the frame</param> /// <param name="request">Inbound frame to process</param> /// <returns> /// Frame to send back; <c>null</c> if no message should be returned; /// </returns> /// <exception cref="BadRequestException">Missing the 'transaction' header in the frame.</exception> public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["transaction"]; if (string.IsNullOrEmpty(id)) throw new BadRequestException(request, "Missing the 'transaction' header in the frame."); client.BeginTransaction(id); return null; }
public StompSubscription(IStompClient client, IObserver <IStompMessage> observer, string id, bool acknowledgeableMessages, string transactionId = null) { _client = client; _observer = observer; _id = id; _transactionId = transactionId; _acknowledgeableMessages = acknowledgeableMessages; _disposableSubscription = client.Subscribe(this); Root[this] = this; }
/// <summary> /// Create an observer to <paramref name="frameObservable"/> /// </summary> /// <param name="client"></param> /// <param name="frameObservable"></param> public StompHeartbeatManager(IStompClient client, IStompFrameObservable frameObservable) { this.client = client; this.frameObservable = frameObservable; if (this.frameObservable == null) { throw new ArgumentNullException("frameObservable"); } this.frameObservable.SubscribeEx(this.OnNext); }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["transaction"]; if (string.IsNullOrEmpty(id)) { throw new BadRequestException(request, "Missing the 'transaction' header in the frame."); } client.BeginTransaction(id); return(null); }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["receipt"]; if (string.IsNullOrEmpty(id)) throw new BadRequestException(request, "Missing the 'receipt' header in the frame. It's required so that we can notify you when the DISCONNECT frame has been received."); if (client.HasActiveTransactions) throw new BadRequestException(request, "Got pending transactions. Just close the socket to abort them, or send proper commits/rollbacks before the DISCONNECT frame.."); var response = new BasicFrame("RECEIPT"); response.AddHeader("receipt-id", id); return response; }
/// <summary> /// /// </summary> /// <param name="client">Client that the subscription belongs to</param> /// <param name="id">Arbitary string as specified by the client.</param> public Subscription(IStompClient client, string id) { if (client == null) { throw new ArgumentNullException("client"); } if (id == null) { throw new ArgumentNullException("id"); } Id = id; Client = client; MaxMessagesPerSecond = 5; }
public IFrame Process(IStompClient client, IFrame request) { ValidateContentHeaders(request); var queue = GetQueue(request); var message = CreateOutboundMessage(client, request); var transactionId = request.Headers["transaction"]; if (!string.IsNullOrEmpty(transactionId)) { client.EnqueueInTransaction(transactionId, () => queue.Enqueue(message), () => { }); return null; } return message; }
private void SendMessage(IStompClient client, string body, Guid messageId, string subscriptionId) { Log.Info(string.Format("Sending message to {0}", client.SessionId)); Log.Debug(string.Format("message {0}", body)); var stompMessage = new StompMessage("MESSAGE", body); stompMessage["message-id"] = messageId.ToString(); stompMessage["destination"] = Address; if (!string.IsNullOrEmpty(subscriptionId)) { stompMessage["subscription"] = subscriptionId; } client.Send(stompMessage); }
/// <summary> /// Process an inbound frame. /// </summary> /// <param name="client">Connection that received the frame</param> /// <param name="request">Inbound frame to process</param> /// <returns> /// Frame to send back; <c>null</c> if no message should be returned; /// </returns> public IFrame Process(IStompClient client, IFrame request) { ValidateContentHeaders(request); var queue = GetQueue(request); var message = CreateOutboundMessage(client, request); var transactionId = request.Headers["transaction"]; if (!string.IsNullOrEmpty(transactionId)) { client.EnqueueInTransaction(transactionId, () => queue.Enqueue(message), () => { }); return(null); } return(message); }
/// <summary> /// Handles the UNSUBSCRIBE message /// </summary> /// <param name="client">The client.</param> /// <param name="message">The message.</param> private void OnStompUnsubscribe(IStompClient client, StompMessage message) { string destination = message["destination"]; if (string.IsNullOrEmpty(destination)) { return; } var queue = _queues.FirstOrDefault(q => q.Address == destination); if (queue == null || queue.Clients.Contains(client) == false) { client.Send(new StompMessage("ERROR", "You are not subscribed to queue '" + destination + "'")); return; } queue.RemoveClient(client); }
private static BasicFrame CreateOutboundMessage(IStompClient client, IFrame request) { var message = new BasicFrame("MESSAGE"); foreach (var header in request.Headers) { message.AddHeader(header.Key, header.Value); } message.AddHeader("Originator-Session", client.SessionKey); message.AddHeader("Originator-Address", client.RemoteEndpoint.ToString()); if (request.Body != null) { message.Body = new MemoryStream(); request.Body.CopyTo(message.Body); message.Body.Position = 0; } return message; }
private static BasicFrame CreateOutboundMessage(IStompClient client, IFrame request) { var message = new BasicFrame("MESSAGE"); foreach (var header in request.Headers) { message.AddHeader(header.Key, header.Value); } message.AddHeader("Originator-Session", client.SessionKey); message.AddHeader("Originator-Address", client.RemoteEndpoint.ToString()); if (request.Body != null) { message.Body = new MemoryStream(); request.Body.CopyTo(message.Body); message.Body.Position = 0; } return(message); }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["id"]; if (string.IsNullOrEmpty(id)) throw new BadRequestException(request, "Missing the ID header in the frame."); var subscription = client.RemoveSubscription(id); if (subscription == null) throw new BadRequestException(request, string.Format("Failed to find an subscription with id '{0}'.", id)); var queue = _queueRepository.Get(subscription.QueueName); if (queue == null) { //TODO: Log that the queue do not exist (even though our subscription existed). return null; } queue.Unbsubscribe(subscription); return null; }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["id"]; if (string.IsNullOrEmpty(id)) throw new BadRequestException(request, "Missing the 'id' header in the frame. Required so that we know which message that the ACK is for."); if (!client.IsFramePending(id)) throw new BadRequestException(request, string.Format("Unknown message with id '{0}'. can therefore not ACK it.", id)); var subscription = client.GetSubscription(id); var transactionId = request.Headers["transaction"]; if (!string.IsNullOrEmpty(transactionId)) { client.EnqueueInTransaction(transactionId, () => subscription.Ack(id), () => { }); return null; } subscription.Ack(id); return null; }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["receipt"]; if (string.IsNullOrEmpty(id)) { throw new BadRequestException(request, "Missing the 'receipt' header in the frame. It's required so that we can notify you when the DISCONNECT frame has been received."); } if (client.HasActiveTransactions) { throw new BadRequestException(request, "Got pending transactions. Just close the socket to abort them, or send proper commits/rollbacks before the DISCONNECT frame.."); } var response = new BasicFrame("RECEIPT"); response.AddHeader("receipt-id", id); return(response); }
/// <summary> /// Excutes the action assigned to the message command /// </summary> /// <param name = "client"></param> /// <param name = "message"></param> private void OnClientMessage(IStompClient client, StompMessage message) { if (message == null || message.Command == null) { return; } if (client.SessionId == Guid.Empty) { client.SessionId = Guid.NewGuid(); } Log.Info(string.Format("Processing command: {0} from client {1}", message.Command, client.SessionId)); if (!_actions.ContainsKey(message.Command)) { Log.Warn(string.Format("Client {0} sended an unknown command: {1}", client.SessionId, message.Command)); return; } if (message.Command != "CONNECT" && client.IsConnected() == false) { Log.Info(string.Format("Client {0} was not connected before sending command: {1}", client.SessionId, message.Command)); client.Send(new StompMessage("ERROR", "Please connect before sending '" + message.Command + "'")); return; } _actions[message.Command](client, message); // when a receipt is request, we send a receipt frame if (message.Command == "CONNECT" || message["receipt"] == string.Empty) { return; } var response = new StompMessage("RECEIPT"); response["receipt-id"] = message["receipt"]; client.Send(response); }
/// <summary> /// Process an inbound frame. /// </summary> /// <param name="client">Connection that received the frame</param> /// <param name="request">Inbound frame to process</param> /// <returns> /// Frame to send back; <c>null</c> if no message should be returned; /// </returns> public IFrame Process(IStompClient client, IFrame request) { var versions = request.Headers["accept-version"]; if (versions == null) { var error = request.CreateError("Missing the 'accept-version' header."); error.Headers["version"] = "2.0"; return(error); } if (!versions.Contains("2.0")) { var error = request.CreateError("Only accepting stomp 2.0 clients."); error.Headers["version"] = "2.0"; return(error); } IFrame frame; if (!CheckCredentials(client, request, out frame)) { return(frame); } //TODO: Heartbeating. var response = new BasicFrame("CONNECTED"); response.Headers["version"] = "2.0"; response.Headers["server"] = _serverName; if (client.SessionKey != null) { response.Headers["session"] = client.SessionKey; } return(response); }
/// <summary> /// /// </summary> /// <param name="client"></param> /// <param name="request"></param> /// <param name="errorFrame"></param> /// <returns><c>true</c> means that we should exist.</returns> private bool CheckCredentials(IStompClient client, IFrame request, out IFrame errorFrame) { if (_authenticationService.IsActivated) { var user = request.Headers["login"]; var passcode = request.Headers["passcode"]; if (user == null || passcode == null) { var error = request.CreateError( "This broker have been configured to only allow authenticated clients. Send the 'login'/'password' headers in the 'STOMP' errorFrame."); error.Headers["version"] = "2.0"; { errorFrame = error; return(false); } } var loginResult = _authenticationService.Login(user, passcode); if (!loginResult.IsSuccessful) { var error = request.CreateError(loginResult.Reason); error.Headers["version"] = "2.0"; { errorFrame = error; return(false); } } client.SetAsAuthenticated(loginResult.Token); } else { client.SetAsAuthenticated(Guid.NewGuid().ToString()); } errorFrame = null; return(true); }
public IFrame Process(IStompClient client, IFrame request) { var id = request.Headers["id"]; if (id == null) throw new BadRequestException(request, "You must include the 'id' header in the SUBSCRIBE frame."); if (client.SubscriptionExists(id)) throw new BadRequestException(request, string.Format("There is already a subscription with id '{0}'.", id)); var ackType = GetAckType(request); var queue= GetQueue(request); var subscription = new Subscription(client, id) { AckType = ackType, QueueName = queue.Name }; queue.AddSubscription(subscription); client.AddSubscription(subscription); return request.CreateReceiptIfRequired(); }
/// <summary> /// /// </summary> /// <param name="client"></param> /// <param name="request"></param> /// <param name="errorFrame"></param> /// <returns><c>true</c> means that we should exist.</returns> private bool CheckCredentials(IStompClient client, IFrame request, out IFrame errorFrame) { if (_authenticationService.IsActivated) { var user = request.Headers["login"]; var passcode = request.Headers["passcode"]; if (user == null || passcode == null) { var error = request.CreateError( "This broker have been configured to only allow authenticated clients. Send the 'login'/'password' headers in the 'STOMP' errorFrame."); error.Headers["version"] = "2.0"; { errorFrame = error; return false; } } var loginResult = _authenticationService.Login(user, passcode); if (!loginResult.IsSuccessful) { var error = request.CreateError(loginResult.Reason); error.Headers["version"] = "2.0"; { errorFrame = error; return false; } } client.SetAsAuthenticated(loginResult.Token); } else client.SetAsAuthenticated(Guid.NewGuid().ToString()); errorFrame = null; return true; }
/// <summary> /// Handles the DISCONNECT message /// </summary> /// <param name="client">The client.</param> /// <param name="message">The message.</param> public void OnStompDisconnect(IStompClient client, StompMessage message) { var stompQueues = _queues.Where(q => q.Clients.Contains(client)).ToList(); stompQueues.ForEach(q => q.RemoveClient(client)); }
/// <summary> /// Sends a 'CONNECT' message /// </summary> public static void Connect(this IStompClient client) { var stompMsg = new StompMessage("CONNECT"); client.Send(stompMsg); }
public int CompareTo(IStompClient other) { return SessionId.CompareTo(other.SessionId); }
public int CompareTo(IStompClient other) { return(SessionId.CompareTo(other.SessionId)); }
/// <summary> /// Removes the client. /// </summary> /// <param name = "client">The client.</param> public void RemoveClient(IStompClient client) { Log.Info(string.Format("Removing client {0}", client.SessionId)); if (!_clients.ContainsKey(client)) { Log.Info(string.Format("Client to remove not found {0}", client.SessionId)); return; } SubscriptionMetadata meta; if (_clients.TryRemove(client, out meta)) if (meta.OnCloseHandler != null) client.OnClose -= meta.OnCloseHandler; // raise the last client removed event if needed if (!_clients.Any() && OnLastClientRemoved != null) OnLastClientRemoved(this); }
/// <summary> /// Determines whether the specified stomp client is connected. /// </summary> /// <param name="stompClient">The stomp client.</param> /// <returns> /// <c>true</c> if the specified stomp client is connected; otherwise, <c>false</c>. /// </returns> public static bool IsConnected(this IStompClient stompClient) { return(stompClient.SessionId != Guid.Empty); }
/// <summary> /// Adds the client. /// </summary> /// <param name = "client">The client.</param> /// <param name = "subscriptionId">The subscription id.</param> public void AddClient(IStompClient client, string subscriptionId) { Log.Info(string.Format("Adding client: {0}", client.SessionId)); if (_clients.ContainsKey(client)) { Log.Info(string.Format("Duplicate client found: {0}", client.SessionId)); return; } Action onClose = () => RemoveClient(client); client.OnClose += onClose; if (_clients.IsEmpty) { do { string body; if (Store.TryDequeue(out body)) { SendMessage(client, body, Guid.NewGuid(), subscriptionId); } } while (Store.HasMessages()); } _clients.TryAdd(client, new SubscriptionMetadata {Id = subscriptionId, OnCloseHandler = onClose}); }