FROM: 5HT
TO: #N2O
DATE: 24 SEP 2015

N2O Remote Protocol

TL;DR — Access N2O context state from node.js and PHP

Remote Architecture

Samples

Listing 1. node.js Index module sample

  var index = match({

      'init' : function () {
          wf.reg(this,sid,'room'); },

      '["chat",msg]' : function (msg) {
          wf.send(this.sid,'room',
              tuple(atom('client'),tuple(bin(this.sid),bin(msg))))); }

      '["client",[sid,msg]]' : function (sid,msg) {
          wf.insert_bottom(this.sid,"history",""+sid+": "+msg+""); },

  });

Listing 2. Erlang version

      -module(index).
      -compile(export_all).
      -include_lib("nitro/include/nitro.hrl").

      event(init)            -> wf:reg(room);
      event({chat,Msg})      -> wf:send(room,{client,{peer(),Msg}});
      event({client,{P,M}})  -> wf:insert_bottom(history,
                                #panel{id=history,body=[P,":",M,#br{}]});


      event(Event)           -> wf:info(?MODULE,"Event: ~p~n",[Event]).

Protocol Specification

This is a core specification on Nitrogen-like frameworks. N2O as an application server provices set of built-in services like ETS tables for storing cookies, process state, browser session or application cache data. Also it provides pubsub API through gproc and n2o_async API for process supervision. DOM API is optional for implementation.

Listing 3. N2O Remote Protocol

   % ETS tables access protocol

     {get,Table,Key}
     {put,Table,Key,Value}

   % MQ protocol

     {pub,Topic,Message}
     {sub,Topic,Args}
     {unsub,Topic}

   % DOM protocol

     {q,Key}
     {qc,Key}
     {cookie,Operation,Key,Value}
     {insert_top,Key,Value}
     {insert_bottom,Key,Value}

   % ASYNC protocol

     {start,Handler}
     {stop,Class,Name}
     {restart,Class,Name}
     {async,Name,Function}
     {flush}
     {flush,Key}

Please note that DOM protocol could be generated purely in JavaScript that returns prerendered IO packet for passing throught router to a gived WebSocket, XHR or TCP session. Thus relaying DOM protocol is optional.

Listing 4. JavaScript Proxy Implementation Generation

  module.exports = {reg:reg,send:send,insert_bottom};

  function send(sid,room,message) {
      $conn.send(enc(tuple(atom('pub'),
                           atom(room),
                           bin(message)))); }

  function reg(sid,room) {
      $conn.send(enc(tuple(atom('sub'),
                           atom(room)))); }

  function session(sid,key,value) {
      $conn.send(enc(tuple(atom('put'),
                           atom('session'),
                           bin(key),bin(value)))); }

  function state(sid,key,value) {
      $conn.send(enc(tuple(atom('put'),
                           atom('state'),
                           bin(key),bin(value)))); }

  function cache(sid,key,value) {
      $conn.send(enc(tuple(atom('put'),
                           atom('cache'),
                           bin(key),bin(value)))); }

  function insert_bottom(sid,element,htm) {
      var js = function() { var div = qn('div'); div.innerHTML = htm;
                        qi(element).appendChild(div.firstChild); };
      js = "(" + js.toString() + ")();";
      $conn.send(enc(tuple(atom('io'),
                           bin(js.toString()),
                           bin('')))); }