Skip to content

specification: add RFC 7 (WebSocket transport) #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion protocol/specification/discovery.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ Implementation hints
See also `SECoP RFC 5`_.


.. _SECoP RFC 6: https://github.com/SampleEnvironment/SECoP/blob/master/rfcs/RFC-005-udp-discovery.rst
.. _SECoP RFC 5: https://github.com/SampleEnvironment/SECoP/blob/master/rfcs/RFC-005-udp-discovery.rst
75 changes: 75 additions & 0 deletions protocol/specification/messages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ needed. This should offer multiple TCP connections and contain the necessary
logic to map requests/replies from/to those network connections onto/from the
serial connection to the actual SEC node.

Finally, SECoP messages can also exchanged over WebSockets, which is useful for
interacting directly with browsers/JavaScript clients, see :ref:`websockets`.


Transfer modes
--------------
Expand Down Expand Up @@ -912,3 +915,75 @@ to be sent before it can continue as before.

| :issue:`004 The Timeout SEC Node Property`
| :issue:`006 Keep Alive`


.. _websockets:

SECoP over WebSockets
---------------------

Since browser (i.e. HTML+JavaScript) based human interface solutions are more
and more important, and JavaScript lacks traditional socket based APIs,
exchanging raw SECoP messages is not an option. The best alternative is
WebSockets (RFC :rfc:`6455`), which are a relatively overhead-free way of
exchanging messages between two endpoints in an arbitrary pattern.

See also `SECoP RFC 7`_.

Implementation in a SEC node
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After opening a connection, if the first message the SEC node receives starts
with ``GET /``, it treats the connection as a WebSocket connection, i.e. it
negotiates the connection using a prelude of HTTP requests, after which the
connection continues using the WebSocket protocol in both directions.

Since WebSockets provide reliable framing, every SECoP message is sent in a
frame. The line ending added to separate messages over raw TCP is therefore
unneded, but remains valid. Messages are sent as TEXT frames.

Everything else (message structure and semantics) remains unchanged.

.. note::

If the SEC node doesn't want to support WebSockets, no further action is
required. It will reply with the standard SECoP error messages, and the
client will abort the connection attempt.

A minimal implementation of the HTTP prelude is pretty small, does not have
a lot of complexity, and can be implemented even on microcontrollers `in
about 200 lines of code
<https://github.com/SampleEnvironment/microSECoP/blob/master/src/http.rs>`_.

Implementation in a client
~~~~~~~~~~~~~~~~~~~~~~~~~~

On the WebSocket client side, making a connection is as easy as opening a
connection and start sending request messages, handling response messages as
they come in. A very minimal example in JavaScript::

function on_connect(event) {
// On initial connect, we should ask for identification
event.target.send('*IDN?');
}

function on_message(event) {
let msg = event.data;
// Handle response to initial *IDN? and request descriptive data
if (msg.startsWith('ISSE')) {
event.target.send('describe');
return;
}
// Parse `msg` as a SECoP message here, and react to it
}

let ws = new WebSocket('ws://node:10767');
ws.addEventListener('open', on_connect);
ws.addEventListener('message', on_message);
// Should also listen on 'close' and 'error' events

// Whenever needed, send messages, for example:
ws.send('change mod:param 42');


.. _SECoP RFC 7: https://github.com/SampleEnvironment/SECoP/blob/master/rfcs/RFC-007-websockets.rst