The SMQ hub (a.k.a broker) API is divided into three parts:
You only need the first set of APIs(Part I) if you do not plan on writing any server code that interacts with the broker.
The broker maintains a Lua table for each connected SMQ client. We refer to this table as the "peer table". The broker is responsible for maintaining the following values:
To inspect subscriptions, handle the single-topic representation separately:
local topics = peer.topics
if type(topics) == "number" then
trace("Subscribed topic:", topics)
elseif type(topics) == "table" then
-- With several subscriptions, keys and values are both topic IDs.
for tid in pairs(topics) do trace("Subscribed topic:", tid) end
end
You may read these values and add additional information to the peer table, but you must under no circumstances modify the values used by the broker. Doing so will make the broker malfunction.
Creates and returns an SMQ instance: require"smq.hub".create([op])
Note: the broker instance also provides an SMQ client API enabling server-side Lua code to communicate with other SMQ nodes. The API does not enable server-to-server communication, however, the cluster manager provides two specialized publish methods that can be used for inter-server communication.
Parameters
Callback return values
Refusal codes:
The second return value is an optional string that may be returned when a connection is refused. This string is sent to the client.
The ondrop callback is called if a publisher publishes to a topic no one is subscribed to. The ondrop handler enables you to catch and process messages with no destination.
This callback is called by the broker prior to re-publishing a message. The message is denied and subsequently dropped by the broker if this function returns false. The function can be used for authorization purposes and for implementing Access Control Lists (ACL).
Return values from onconnect, onclose, ondrop and log callbacks are ignored. The onpublish, permittop and permitsubtop callbacks must return a boolean decision; false or nil denies the operation.
Example: see the LSP connection example for example code.
Return values
Throws
Incorrect options can throw. The constructor checks log, ondrop and onpublish when supplied; other callback and option errors may surface later when used. Errors raised by application callbacks are not converted to error returns.
The smq:connect function is typically called from an LSP page or a directory function and upgrades (morphs) an incoming HTTP(S) request originating from an SMQ client into a persistent SMQ connection. The function grabs the active socket connection from the request object, thus invalidating any further use of this object after that the function returns. The function will send an HTTP 404 response message should the incoming request not originate from an SMQ client.
Parameters
Example: see the LSP connection example for example code.
Return values
No values. A successful connection is reported through onconnect. Handshake failures are handled on the client connection rather than returned to this caller. For raw SMQ connections, bytes received after CONNECT are retained and processed in order after successful authentication and the successful CONNACK write. This includes complete or partial following commands. They are discarded if authentication fails. Message dispatch waits until onconnect returns, so that callback can initialize the peer before buffered commands run. Closing the socket from onconnect discards the pending commands. Incomplete CONNECT fields are rejected with protocol status 0x01 and the socket is closed; authentication is not called for these messages. After connection, raw SMQ clients may send fragmented publications with up to 65,520 payload bytes in total, excluding the message header. Exceeding this payload limit or sending an incomplete fragment header closes the connection through normal client cleanup, including removal of the peer entry and the onclose callback.
Throws
Incorrect command-object or callback use can throw. Application errors raised by authenticate or onconnect propagate. Reported socket-transfer and handshake failures do not produce a Lua error return from this method.
The pub/sub API enables server code to act as any other SMQ client. Server code can both publish and subscribe to messages sent to and from both browsers and devices.
Note: Lua strings can contain any value including binary data. Strings in Lua use 8 bit wide characters. Since JavaScript code utilizes 16 bit wide characters, data strings intended for interpretation by a JavaScript client must be provided as UTF-8 by the server code. Use of an UTF-8 enabled editor is recommended if you plan on sending strings to JavaScript code that includes non English characters. JavaScript code can also receive raw data. See the subscribe method in the JavaScript client and the "datatype" setting for details.
Create a topic and fetch the topic ID (TID). The SMQ protocol is optimized and does not directly use a string when publishing, but a number. The server randomly creates a 32 bit number and persistently stores the topic name and number. The 'create' method can optionally be used prior to publishing a message on a specific topic. Otherwise, the publish method can be used directly with a topic string since the publish method takes care of first creating a topic if you publish to a topic unknown to the broker. The broker will not invoke the permittop callback when the topic is created by server code.
Parameters
Return values
Throws
Incorrect name or ID use can throw here or when the stored values are used later. Supply valid names and nonzero unsigned 32-bit IDs; this method does not validate every stored value.
Create a sub-topic and fetch the subtopic ID. The createsub method can optionally be used prior to publishing a message on a specific topic and sub-topic. Alternatively, the publish method may be used directly with topic and sub-topic strings, respectively. The publish method will manage the sequence and creation of a topic, then sub-topic in circumstances where the topic name, sub-topic name, or both are unknown to the broker. The broker will not invoke the permitsubtop callback when the topic is created by server code.
Parameters
Return values
Throws
Incorrect name or ID use can throw here or when the stored values are used later. Supply valid names and nonzero unsigned 32-bit IDs; this method does not validate every stored value.
Get the server client's ephemeral topic ID.
Parameters
None.
Return values
Throws
Does not throw when called on a valid hub.
Registers an observation request with the broker, allowing your client to receive notifications whenever the number of subscribers to a given topic changes.
You can observe either named topics (as strings or topic IDs, i.e., tids) or Ephemeral TIDs (etids).
When you observe a named topic or a topic ID:
When you observe an etid:
In an SMQ cluster, you will also receive etid change notifications if a client connected to another cluster node disconnects. Think of observing etids as similar to the "will message" feature in MQTT, except the client does not need to define or send a will message in advance. Instead, any other client can call smq:observe() to monitor or "supervise" that client and automatically be notified when it disconnects.
Parameters
Callback return values are ignored. The callback may call unobserve() to cancel, including during the initial notification.
Return values
Throws
Throws if onchange is not a function. Invalid topic arguments and errors raised by an initial callback can also throw. Errors in later callback invocations propagate in the context delivering the notification.
Stop receiving change notifications for a topic or ephemeral TID.
Parameters
Return values
No values. Removes this server client's observer and callback. An unknown topic or an inactive observation has no effect. The topic, subscriptions and peer connection remain intact.
Throws
Does not throw for a string name or numeric ID on a valid hub.
Publish messages to a topic and optionally to a sub-topic. Topics may be topic names (strings), TIDs (numbers), or ephemeral TIDs (numbers). Messages published to unresolved topic names are instantly resolved. Topic names are resolved by calling smq:create and/or smq:createsub. The publisher ID is the server client's ephemeral TID, returned by smq:gettid(). Use smq:pubon() to send directly to a client on behalf of another client. Note: max payload size is 0xFFF0 (65,520 bytes).
Parameters
Return values
Calls from a socket coroutine deliver through the broker directly and do not use the queue, even when it is full. Other callers use the queue. See smq:queuesize() for available space.
Throws
Throws for incorrect API usage, including an unsupported data type, a table that cannot be JSON encoded, or a payload larger than 65,520 bytes. Invalid topic or subtopic arguments can also throw. A full queue returns nil,"full". Application callback errors can propagate when callbacks run during publication.
Publish a message on behalf of another SMQ client. This is an advanced function that enables server-side logic to connect SMQ clients together in a system that is not using named topics, but is instead using ephemeral topic IDs only. Both totid and fromtid must be ephemeral topic IDs. A subtopic number must be provided, but the number can be set to zero if not used.
Parameters
Return values
Throws
Throws before transmission if data exceeds 65,520 bytes. Invalid message or ID arguments can also throw when the message is assembled. Socket write failures return nil,error. Errors raised by application logging or connection callbacks can propagate.
Subscribe to a topic and optionally to a sub-topic. You may subscribe multiple times to the same topic if you use sub-topics. Subscribing to a topic without providing a sub-topic introduces a "catch all" for sub-topics that do not correspond to any subscribed sub-topics.
The topic name "self" is interpreted as subscribing to the server's own Ephemeral Topic ID. Subscribing to your own Topic ID makes it possible for other connected clients to send a message directly to the server.
Parameters
Return values
Throws
Throws for invalid options or a non-function onmsg. Incorrect topic or subtopic use and errors in subscription-change callbacks can also throw. Subscription state may already have changed before an argument or callback error occurs.
Requests the broker to unsubscribe the server from a topic. All registered onmsg callback functions, including all callbacks for sub-topics, will be removed from the broker.
Parameters
Return values
No values. An unknown topic name has no effect.
Throws
Incorrect argument use or errors in subscription-change callbacks can throw.
Install a global onmsg callback function. This handler receives messages for subscribed topics when no topic or subtopic callback matches. A JSON decoding failure stays with the matching callback and does not invoke this handler.
Parameters
Return values
No values. Replaces the global handler. Its callback return values are ignored.
Throws
Throws unless onmsg is a function. Errors raised when the callback handles a message propagate in the message-dispatch context.
Read the server publish queue's available space and current usage.
Parameters
None.
Return values
A socket coroutine bypasses this queue when publishing. For other callers, check publish()'s return values as well; this method reports space at the time of the call.
Throws
Does not throw when called on a valid hub.
Translates TID to topic name.
Parameters
Return values
Throws
Does not throw for a numeric ID. An unknown ID returns nil.
Translates topic name to TID.
Parameters
Return values
Throws
Does not throw for a string name. An unknown name returns nil.
Translates sub-topic name to sub-TID.
Parameters
Return values
Throws
Does not throw for a string name. An unknown name returns nil.
Translates sub-TID to sub-topic name.
Parameters
Return values
Throws
Does not throw for a numeric ID. An unknown ID returns nil.
Iterate over the hub's peer records. These include connected remote clients, the server's own client, and any cluster phantom peers.
Parameters
None.
Return values
Throws
Does not throw when called on a valid hub. Internal socket tables do not provide the full network socket API.
Example code:
for sock,peer in smq:peers() do
-- Only remote network clients have an IP address.
if type(sock) == "userdata" then
trace("IP address:",sock:peername(), "UID", peer.uid)
end
end
See function smq:sock2peer for more information on how to use the peer table returned by the iterator.
Parameters
Return values
Throws
Does not throw for a socket or table argument. An unregistered socket returns nil.
Parameters
Return values
Throws
Does not throw for a numeric ID. An unknown ID returns nil.
Returns an iterator that lets you iterate over all registered tids/topic-names.
Parameters
None.
Return values
Throws
Does not throw when called on a valid hub.
Example code:
for tid,topicname in smq:topics() do
trace("tid:",tid, "topic", topicname)
end
Returns an iterator that lets you iterate over all registered tids/sub-topic-names.
Parameters
None.
Return values
Throws
Does not throw when called on a valid hub.
Example code:
for subtid,subtopname in smq:subtopics() do
trace("sub tid:",subtid, "subtopic", subtopname)
end
Parameters
Sets the keepalive values applied to future SMQ connections using sock:setoption("keepalive",true,keepidle,keepintv). Existing connections retain their settings. The constructor defaults are keepidle=230 and keepintv=23 seconds.
Return values
No values.
Throws
An invalid keepidle can throw when the default interval is calculated. Invalid socket-option values can also fail when a later connection applies them.
Parameters
To close one client without a reason, call smq:shutdown(nil, etid). This closes only that client and allows its normal reconnect policy. Supplying a reason sends DISCONNECT, which tells a well-behaved client not to reconnect automatically.
When called without the etid parameter, the function closes all SMQ client socket connections. A well-behaved SMQ client should then attempt to reconnect. This mode is designed for dynamic runtime upgrades of the broker/server app. You may design server-side logic such that you can dynamically upgrade the server-side Lua application and broker without restarting the server.
If msg is provided, the broker will send the SMQ control message Disconnect to all connected clients before closing the connection. A well-behaved client should not attempt to reconnect when it receives a Disconnect request.
In a cluster setup, this method closes clients connected to this hub. Other cluster nodes receive notifications for the disconnected client IDs, but their clients and the cluster transport remain connected.
Return values
No values. This method does not return delivery errors for the optional DISCONNECT message; it proceeds to close the selected connections.
Throws
An invalid reason can throw when the DISCONNECT message is assembled. Errors from application connection or logging callbacks can propagate. An unknown numeric etid does not throw.
Parameters
This checks for a Sec-WebSocket-Key or SimpleMQ header. It does not validate an SMQ handshake; a WebSocket request for another protocol also matches.
Example code:
<?lsp
if require("smq.hub").isSMQ(request) then
-- Delegate to SMQ broker instance.
else
-- Not an SMQ client. Probably a standard HTTP client (browser).
end
?>
Return values
Throws
Throws for an invalid or expired request object.