@@ -20,6 +20,9 @@ needed.  This should offer multiple TCP connections and contain the necessary
2020logic to map requests/replies from/to those network connections onto/from the
2121serial connection to the actual SEC node.
2222
23+ Finally, SECoP messages can also exchanged over WebSockets, which is useful for
24+ interacting directly with browsers/JavaScript clients, see :ref: `websockets `.
25+ 
2326
2427Transfer modes
2528-------------- 
@@ -912,3 +915,75 @@ to be sent before it can continue as before.
912915
913916   |  :issue:`004 The Timeout SEC Node Property` 
914917|  :issue:`006 Keep Alive` 
918+ 
919+ 
920+ .. _websockets :
921+ 
922+ SECoP over WebSockets
923+ --------------------- 
924+ 
925+ Since browser (i.e. HTML+JavaScript) based human interface solutions are more
926+ and more important, and JavaScript lacks traditional socket based APIs,
927+ exchanging raw SECoP messages is not an option.  The best alternative is
928+ WebSockets (RFC :rfc: `6455 `), which are a relatively overhead-free way of
929+ exchanging messages between two endpoints in an arbitrary pattern.
930+ 
931+ See also `SECoP RFC 7 `_.
932+ 
933+ Implementation in a SEC node
934+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
935+ 
936+ After opening a connection, if the first message the SEC node receives starts
937+ with ``GET / ``, it treats the connection as a WebSocket connection, i.e. it
938+ negotiates the connection using a prelude of HTTP requests, after which the
939+ connection continues using the WebSocket protocol in both directions.
940+ 
941+ Since WebSockets provide reliable framing, every SECoP message is sent in a
942+ frame.  The line ending added to separate messages over raw TCP is therefore
943+ unneded, but remains valid.  Messages are sent as TEXT frames.
944+ 
945+ Everything else (message structure and semantics) remains unchanged.
946+ 
947+ .. note ::
948+ 
949+     If the SEC node doesn't want to support WebSockets, no further action is
950+     required.  It will reply with the standard SECoP error messages, and the
951+     client will abort the connection attempt.
952+ 
953+     A minimal implementation of the HTTP prelude is pretty small, does not have
954+     a lot of complexity, and can be implemented even on microcontrollers `in 
955+     about 200 lines of code 
956+     <https://github.com/SampleEnvironment/microSECoP/blob/master/src/http.rs> `_.
957+ 
958+ Implementation in a client
959+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ 
960+ 
961+ On the WebSocket client side, making a connection is as easy as opening a
962+ connection and start sending request messages, handling response messages as
963+ they come in.  A very minimal example in JavaScript::
964+ 
965+     function on_connect(event) { 
966+         // On initial connect, we should ask for identification 
967+         event.target.send('*IDN?'); 
968+     } 
969+ 
970+     function on_message(event) { 
971+         let msg = event.data; 
972+         // Handle response to initial *IDN? and request descriptive data 
973+         if (msg.startsWith('ISSE')) { 
974+             event.target.send('describe'); 
975+             return; 
976+         } 
977+         // Parse `msg` as a SECoP message here, and react to it 
978+     } 
979+ 
980+     let ws = new WebSocket('ws://node:10767'); 
981+     ws.addEventListener('open', on_connect); 
982+     ws.addEventListener('message', on_message); 
983+     // Should also listen on 'close' and 'error' events 
984+ 
985+     // Whenever needed, send messages, for example: 
986+     ws.send('change mod:param 42'); 
987+ 
988+ 
989+ .. _SECoP RFC 7 : https://github.com/SampleEnvironment/SECoP/blob/master/rfcs/RFC-007-websockets.rst 
0 commit comments