# Message Queue Protocol (Draft) An agent may choose to provide a message queue for other agents it has formed pairwise connections with. This protocol provides a way to inspect or change the properties of that queue and request for messages to be returned. ## Requesting the current queue status The `status-request` message is used to inquire about the current queue status. It does not take any properties. For example: ```json { "@id": "123456780", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/status-request", "~transport": { "return_route": "thread" } } ``` ## Receiving the current queue status The response to a `status-request` message is a `status` message. This describes the current status of the queue, if any is established or possible. ```json { "@id": "123456781", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/status", "~thread": { "thid": "123456780" }, "status": { "duration_limit": 86400, "duration_waited": 3600, "last_added_time": "2019-05-01 12:00:00Z", "last_delivered_time": "2019-05-01 12:00:01Z", "last_removed_time": "2019-05-01 12:00:01Z", "message_count": 7, "message_count_limit": 1000, "message_size_limit": 65536, "size": 8096, "size_limit": 65536000, "will_queue": true } } ``` #### Required Status Properties: - `message_count`: The number of messages in the queue - `will_queue`: A boolean representing whether the agent intends to queue future messages which can't immediately be delivered #### Optional Status Properties: - `duration_limit`: The maximum duration in seconds that a message may stay in the queue without being delivered (may be zero for no limit) - `duration_waited`: The duration in seconds since the last batch of messages was returned - `last_added_time`: A timestamp representing the last time a message was added to the queue - `last_delivered_time`: A timestamp representing the last time one or more messages were delivered from the queue - `last_removed_time`: A timestamp representing the last time one or more messages was removed from the queue - `message_count_limit`: The maximum number of messages the agent will queue for this connection (may be zero for no limit) - `message_size_limit`: The maximum size in bytes of an individual message entering the queue (may be zero for no limit) - `size`: The current total size of the message queue in bytes - `size_limit`: The maximum combined size in bytes of messages in the queue (may be zero for no limit) The minimal response from an agent which is not currently queuing messages for the agent but still allows queue inspection would be something like: ```json { "@id": "123456781", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/status", "~thread": { "thid": "123456780" }, "status": { "message_count": 0, "will_queue": false } } ``` For an agent which has `will_queue` enabled, both messages from third-party agents (received via Forward messages when message routing is enabled) as well as messages generated by the queue-providing agent may enter the queue if they cannot be immediately delivered. ## Updating the queue status By sending an `status-update-request` message, an agent may request changes to the queue behaviour for this connection. Such updates may be accepted or discarded at the discretion of the agent providing the queue. The response to this message is a `status` message. ```json { "@id": "123456780", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/status-update-request", "update": { "duration_limit": 3600, "message_count_limit": 100, "message_size_limit": 102400, "size_limit": 10240000, "will_queue": true } } ``` Update Properties: - `duration_limit`: Request a new duration (in seconds) before undelivered messages expire - `message_count_limit`: Request a new maximum number of messages to be queued - `message_size_limit`: Request a new message size limit (in bytes) - `size_limit`: Request a new total queue size limit (in bytes) - `will_queue`: Set to `true` to turn on request queuing of future messages, and `false` to request that future messages not be queued. This does not affect the state of any currently-queued messages. ## Requesting queued messages A `fetch-request` message is sent in order to retrieve outstanding messages from the queue. The optional `message_count_limit` property specifies a maximum number of messages to be returned, although the queuing agent may choose to enforce a lower limit. ```json { "@id": "123456782", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/fetch-request", "~transport": { "return_route": "thread" }, "message_count_limit": 10 } ``` ## Returning queued messages Messages in the queue are returned as part of a `batch` message in response to a `fetch-request` message. Each entry in the `messages` list must specify an `id` unique to the queue and may specify a `added_time` representing when the message entered the queue. The `msg` property may contain either a packed wire message or an unencrypted message. Messages are returned in the order they were added to the queue, from the oldest to the most recent. ```json { "@id": "123456783", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/queue/1.0/batch", "~thread": { "thid": "123456782" }, "message_count": 2, "messages": [ { "id": "123456778", "msg": { "@id": "123456778", "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message", "~l10n": { "locale": "en" }, "sent_time": "2019-04-15 18:42:01Z", "content": "Your hovercraft is full of eels." } "added_time": "2019-05-01 11:59:59Z" }, { "id": "123456779", "msg": { "protected": "eyJlbmMiOiJ4Y2hhY2hhMjBwb2x5MTMwNV9pZXRmIiwidHlwIjoiSldNLzEuMCIsImFsZyI6IkFub25jcnlwdCIsInJlY2lwaWVudHMiOlt7ImVuY3J5cHRlZF9rZXkiOiJYQ044VjU3UTF0Z2F1TFcxemdqMVdRWlEwV0RWMFF3eUVaRk5Od0Y2RG1pSTQ5Q0s1czU4ZHNWMGRfTlpLLVNNTnFlMGlGWGdYRnZIcG9jOGt1VmlTTV9LNWxycGJNU3RqN0NSUHNrdmJTOD0iLCJoZWFkZXIiOnsia2lkIjoiR0oxU3pvV3phdlFZZk5MOVhrYUpkclFlamZ6dE40WHFkc2lWNGN0M0xYS0wifX0seyJlbmNyeXB0ZWRfa2V5IjoiaG5PZUwwWTl4T3ZjeTVvRmd0ZDFSVm05ZDczLTB1R1dOSkN0RzRsS3N3dlljV3pTbkRsaGJidmppSFVDWDVtTU5ZdWxpbGdDTUZRdmt2clJEbkpJM0U2WmpPMXFSWnVDUXY0eVQtdzZvaUE9IiwiaGVhZGVyIjp7ImtpZCI6IjJHWG11Q04ySkN4U3FNUlZmdEJITHhWSktTTDViWHl6TThEc1B6R3FRb05qIn19XX0=", "iv": "M1GneQLepxfDbios", "ciphertext": "iOLSKIxqn_kCZ7Xo7iKQ9rjM4DYqWIM16_vUeb1XDsmFTKjmvjR0u2mWFA48ovX5yVtUd9YKx86rDVDLs1xgz91Q4VLt9dHMOfzqv5DwmAFbbc9Q5wHhFwBvutUx5-lDZJFzoMQHlSAGFSBrvuApDXXt8fs96IJv3PsL145Qt27WLu05nxhkzUZz8lXfERHwAC8FYAjfvN8Fy2UwXTVdHqAOyI5fdKqfvykGs6fV", "tag": "gL-lfmD-MnNj9Pr6TfzgLA==" }, "added_time": "2019-05-01 11:59:59Z" } ] } ``` ## Open questions - Should the `fetch-request` and/or `status-update-request` messages be used to specify deletion behaviour (preserve or remove messages as they are delivered)? - In that case, should there be a way to drop messages from the top of the queue, or clear the queue? Maybe delete up to a given message ID or fetch from a given message ID? Should `fetch-request` be able to request only the message IDs and times, leaving out the message body (analogous to an IMAP client fetching only headers)? - Should there be separate queues or queue limits for internal messages versus forwarded ones? - Should this protocol be used to manage queue notification methods, such as enabling Apple push notifications sent to a mobile client, or triggering a webhook? - What role(s) should be defined in the `protocol-discovery` response in order to specify that message queuing is a possibility, as opposed to simply supporting the message family?