diff --git a/README.md b/README.md index 98a897a9..77a63d8b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Core Features * Purpose: High performance protocol relay * Endpoints: WebSockets, MQTT, TCP -* Codebase: 1K LOC (Erlang), 500 LOC (JavaScript) +* Codebase: 700 LOC (Erlang), 500 LOC (JavaScript) * Dialyzer: REBAR, REBAR3, MAD, MIX * Hosts: COWBOY, EMQ, MOCHIWEB, RING, TCP, UDP @@ -97,9 +97,10 @@ Protocols N2O ships with 3 optional protocols. -* [n2o_nitro](https://ws.n2o.dev/man/n2o_nitro.htm) — N2O Nitrogen web framework protocol * [n2o_ftp](https://ws.n2o.dev/man/n2o_ftp.htm) — N2O File protocol * [n2o_heart](https://ws.n2o.dev/man/n2o_heart.htm) — N2O Heart protocol +* [nitro_n2o](https://nitro.n2o.dev/man/nitro_n2o.htm) — Nitrogen Web Framework protocol +* [bpe_n2o](https://bpe.n2o.dev) — Business Process Engine protocol Services -------- @@ -118,7 +119,6 @@ JavaScript * [utf8.js](https://ws.n2o.dev/man/utf8.js.htm) — UTF8 encoder/decoder * [ieee754.js](https://ws.n2o.dev/man/ieee754.js.htm) — IEEE754 encoder/decoder * [heart.js](https://ws.n2o.dev/man/heart.js.htm) — HEART protocol -* [nitro.js](https://ws.n2o.dev/man/nitro.js.htm) — NITRO protocol * [ftp.js](https://ws.n2o.dev/man/ftp.js.htm) — FTP protocol * [n2o.js](https://ws.n2o.dev/man/n2o.js.htm) — N2O protocol loop * [mq.js](https://ws.n2o.dev/man/mq.js.htm) — MQTT client diff --git a/man/n2o_nitro.htm b/man/n2o_nitro.htm deleted file mode 100644 index b6a4e47e..00000000 --- a/man/n2o_nitro.htm +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - -NITRO - - - - - - - - - - -
- -

NITRO

-
-
-
-
-

INTRO

-

The n2o_nitro module provides - Nitrogen Web Framework - protocol specification and implementation.

-
-
-

INIT

-

Init message invokes event(init) function in page module. - There are two binary representations of INIT message. - The first one is BERT encoded #init record with binary - token that usually issued by n2o_session, transported in #io record - as data parameter and stored on client side in localStorage or Key Chain. - Clients with invalid tokens are being registered and reissued.

-
- - -record(init, { token :: binary() }). - -
-

The second one is TEXT encoded version of message, <<"N2O,">> - that usually works for hosts with raw binary falicities as WebSockets. -

-
- - <<"N2O,",Token/binary>> - -
-

For token issue protocol see n2o_session module.

-
-
-

PICKLE

-

Pickle message sends to server prerendered (by server) encripted message. - These messages hold #ev record with callee information (encripted). - Pickled messaged can prolongate expiration field in session token (renewed) - by updating client token on each UI request (tracking user activity) when - n2o application variable nitro_prolongate equals true.

-
-
- - -record(pickle, { source = [] :: [] | binary(), - pickled = [] :: [] | binary(), - args = [] :: list({atom(),any()}) }). - - -record(ev, { module = [] :: [] | atom(), - msg = [] :: any(), - trigger = [] :: [] | binary(), - name = [] :: [] | binary() }). - -
-
-
-
-

DIRECT

-

Direct message sends data without any convertation or encription or session logic.

-
-
- - -record(direct, { data = [] :: any() }). - -
-
-
-
-

FLUSH

-

Flush message only redirects data to the socket.

-
-
- - -record(flush, { data = [] :: [] | list(#action{}) }). - -
-
-
-
-

You may also want to read: - n2o_heart, - n2o_ftp. -

-
-
-
- - - - diff --git a/man/nitro.js.htm b/man/nitro.js.htm deleted file mode 100644 index ecf7e9ab..00000000 --- a/man/nitro.js.htm +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - -NITRO.JS - - - - - - - - - - -
- -

NITRO.JS

-
-
-
-
-

INTRO

-

The nitro.js - module provides client NITRO protocol implementation.

-
-
-

API

-

direct(term)

-

Sends DIRECT message from JavaScript. Use enc from bert.js

-
> direct(tuple(atom('direct'),atom('test')));
-

qi(id)

-

Returns DOM element by existing id.

-

qs(id)

-

Searches for DOM element.

-

qn(id)

-

Creates new DOM element.

-

querySource(name)

-

Retrives value fields of the given field.

-

validateSources(list)

-

Validates each value filed for the given list of fields.

-

$io.do

-

The event handler interceptor of the incoming IO message.

-
$io.do = function(x) { console.log(x); }
-
-
-

You may also want to read: - bert.js, - utf8.js, - mq.js, - n2o.js. -

-
-
-
- - - - diff --git a/priv/bert.java b/priv/bert.java deleted file mode 100644 index d507f772..00000000 --- a/priv/bert.java +++ /dev/null @@ -1,19 +0,0 @@ - -/* run tests: javac bert.java ; java -classpath . bert */ - -import java.nio.*; -import java.util.ArrayList; -public class bert { - public int t; - public Object v; - public bert(int t, Object v) { this.t = t; this.v = v; } - public static bert float_ (float o) { return new bert(70, o); } - public static bert tuple (ArrayList o) { return new bert(104,o); } - public static bert string (String o) { return new bert(107,o); } - public static bert list (ArrayList o) { return new bert(108,o); } - public static bert bin (ByteBuffer o) { return new bert(109,o); } - public static bert atom (String o) { return new bert(100,o); } - public static bert number (ArrayList o) { return new bert(110,o); } - public static bert map (ArrayList o) { return new bert(116,o); } - public static void main(String[] args) { System.out.println("BERT for Java (c) SYNRC 2019"); } -} diff --git a/priv/bert.js b/priv/bert.js index 7f505de3..8d06bac7 100644 --- a/priv/bert.js +++ b/priv/bert.js @@ -46,8 +46,13 @@ function en_104(o) { for (var i = 0; i < l; i++)r[i] = ein(o.v[i]); return [104, l, r]; } +function unilen(o) { + return (o.v instanceof ArrayBuffer || o.v instanceof Uint8Array) ? o.v.byteLength : + (new TextEncoder().encode(o.v)).byteLength; +} + function en_109(o) { - var l = o.v instanceof ArrayBuffer ? o.v.byteLength : o.v.length; + var l = unilen(o); return [109, l >>> 24, (l >>> 16) & 255, (l >>> 8) & 255, l & 255, ar(o)]; } function en_108(o) { diff --git a/priv/client.js b/priv/client.js deleted file mode 100644 index 307afabf..00000000 --- a/priv/client.js +++ /dev/null @@ -1,12 +0,0 @@ - -// JSON formatter - -var $client = {}; -$client.on = function onclient(evt, callback) { - try { msg = JSON.parse(evt.data); - if (debug) console.log(JSON.stringify(msg)); - if (typeof callback == 'function' && msg) callback(msg); - for (var i=0;i<$bert.protos.length;i++) { - p = $bert.protos[i]; if (p.on(msg, p.do).status == "ok") return { status: "ok"}; } - } catch (ex) { return { status: "error" }; } - return { status: "ok" }; }; diff --git a/priv/nitro.js b/priv/nitro.js deleted file mode 100644 index 8086ac77..00000000 --- a/priv/nitro.js +++ /dev/null @@ -1,49 +0,0 @@ -// Nitrogen Compatibility Layer - -function direct(term) { ws.send(enc(tuple(atom('direct'),term))); } -function validateSources() { return true; } -function querySourceRaw(Id) { - var val, el = document.getElementById(Id); - if (!el) { - val = qs('input[name='+Id+']:checked'); val = val ? val.value : ""; - } else switch (el.tagName) { - case 'FIELDSET': val = qs('[id="'+Id+'"]:checked'); val = val ? val.value : ""; break; - case 'INPUT': - switch (el.getAttribute("type")) { - case 'radio': case 'checkbox': val = qs('input[name='+Id+']:checked'); val = val ? val.value : ""; break; - case 'date': val = Date.parse(el.value); val = val && new Date(val) || ""; break; - case 'calendar': val = pickers[el.id]._d || ""; break; - default: var edit = el.contentEditable; - if (edit && edit === 'true') val = el.innerHTML; - else val = el.value; - } - break; - default: var edit = el.contentEditable; - if (edit && edit === 'true') { - val = el.innerHTML; - } else { - val = el.value; - switch (val) { - case "true": val = new Boolean(true); break; - case "false": val = new Boolean(false); break; - } - } - } - return val; -} - -function querySource(Id) { - var qs = querySourceRaw(Id); - if (qs instanceof Date) { - return tuple(number(qs.getFullYear()), - number(qs.getMonth() + 1), - number(qs.getDate())); } - else if (qs instanceof Boolean) { - return atom(qs.valueOf()); } - else { return bin(qs); } -} - -(function () { - window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; -})(); diff --git a/priv/template.js b/priv/template.js deleted file mode 100644 index 2b1be2a4..00000000 --- a/priv/template.js +++ /dev/null @@ -1,23 +0,0 @@ - -// N2O Simple Template - -function template(html, data) { // template("{this.name}",{name:"Maxim"}) - var re = /{([^}]+)?}/g, code = 'var r=[];', cursor = 0; - var add = function(line,js) { - js? (code += 'r.push(' + line + ');') : - (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");' : ''); // " - return add; } - while(match = re.exec(html)) { - add(html.slice(cursor, match.index))(match[1],true); - cursor = match.index + match[0].length; } - add(html.substr(cursor, html.length - cursor)); - code += 'return r.join("");'; - return new Function(code.replace(/[\r\t\n]/g, '')).apply(data); } - -function xml(html) { return new DOMParser().parseFromString(html, "application/xhtml+xml").firstChild; } -function dom(html) { - try { return new DOMParser().parseFromString(html, "text/html").firstChild.getElementsByTagName("body")[0].firstChild; } - catch (ex) { var temp = document.createElement("DIV"); - temp.innerHTML = html; - return temp.firstChild; } -} diff --git a/priv/validation.js b/priv/validation.js deleted file mode 100644 index a83667c4..00000000 --- a/priv/validation.js +++ /dev/null @@ -1,22 +0,0 @@ - -// N2O Validation - -function validateSources(list) { - return list.reduce(function(acc,x) { - var event = new CustomEvent('validation'); - event.initCustomEvent('validation',true,true,querySourceRaw(x)); - var el = qi(x), - listener = el && el.validation, - res = !listener || listener && el.dispatchEvent(event); - console.log(res); - if (el) el.style.background = res ? '' : 'pink'; - return res && acc; },true); } - -(function () { - function CustomEvent ( event, params ) { - params = params || { bubbles: false, cancelable: false, detail: undefined }; - var evt = document.createEvent( 'CustomEvent' ); - evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); - return evt; }; - CustomEvent.prototype = window.Event.prototype; - window.CustomEvent = CustomEvent; })(); diff --git a/src/protos/n2o_igor.erl b/src/protos/n2o_igor.erl deleted file mode 100644 index 5fae8ae0..00000000 --- a/src/protos/n2o_igor.erl +++ /dev/null @@ -1,47 +0,0 @@ --module(n2o_igor). --description("Module Merger"). --export([parse_transform/2]). - -parse_transform(Forms, _Options) -> - SearchPath = application:get_env(n2o,igor,"src/protos"), - put(igor,[]), - - {_,_,_,{Name,Arity}} = lists:keyfind(entry,3,Forms), - File = [ F || F={attribute,_,file,_} <- Forms], - Module = [ M || M={attribute,_,module,_} <- Forms], - Modules = [ M || {attribute,_,proto,M} <- Forms], - - X = lists:flatten([ - begin - {ok,R} = epp:parse_file(lists:concat([SearchPath,"/",M,".erl"]), [], []), - R - end || M <- Modules ]), - - Y = lists:flatten( - lists:map( - fun ({_,_,file,{N,_}}=F) -> - case filename:extension(N) of - ".erl" -> []; - ".hrl" -> case get(N) of - undefined -> put(N,F), F; - _ -> [] end end; - ({_,_,module,_}) -> []; - ({_,_,export,[{N,A}]}) when N==Name, A==Arity -> []; - ({A,B,export,List}) -> {A,B,export,List--[{Name,Arity}]}; - ({_,_,description,_}) -> []; - ({function,_,N,A,F}) when Name==N, Arity==A -> case get(igor) of - [] -> put(igor,F); - Saved -> put(igor,Saved ++ F) end, []; - ({eof,_}) -> []; - (Y) -> Y end, X)), - - {Exports,Body} = lists:partition(fun({_,_,export,_}) -> true; (_) -> false end, Y), - Exp = lists:usort(Exports) ++ [{attribute,3,export,[{Name,Arity}]}], - Lst = lists:usort(Body), - {Term,Clauses} = lists:partition(fun - ({clause,_,[{var,_,_},{var,_,_},{var,_,_}],[],_}) -> true; - (_) -> false end, get(igor)), - Igor = [{function,100,Name,Arity,Clauses ++ [hd(Term)]}], - - Module ++ File ++ Exp ++ Lst ++ Igor ++ [{eof,1000}]. - diff --git a/src/protos/n2o_nitro.erl b/src/protos/n2o_nitro.erl deleted file mode 100644 index 62a4cd97..00000000 --- a/src/protos/n2o_nitro.erl +++ /dev/null @@ -1,104 +0,0 @@ --module(n2o_nitro). --description('N2O Nitrogen Web Framework Protocol'). --include_lib("n2o/include/n2o.hrl"). --export([info/3,render_actions/1,io/1,io/2,event/1]). - -% Nitrogen pickle handler - -info({text,<<"N2O,",Auth/binary>>}, Req, State) -> - info(#init{token=Auth},Req,State); - -info(#init{token=Auth}, Req, State) -> - {'Token', Token} = n2o_session:authenticate([], Auth), - Sid = case n2o:depickle(Token) of {{S,_},_} -> S; X -> X end, - New = State#cx{session = Sid, token = Auth}, - put(context,New), - {reply,{bert,case io(init, State) of - {io,_,{stack,_}} = Io -> Io; - {io,Code,_} -> {io,Code,{'Token',Token}} end}, - Req,New}; - -info(#client{data=Message}, Req, State) -> - nitro:actions([]), - {reply,{bert,io(#client{data=Message},State)},Req,State}; - -info(#pickle{}=Event, Req, State) -> - nitro:actions([]), - {reply,{bert,html_events(Event,State)},Req,State}; - -info(#flush{data=Actions}, Req, State) -> - nitro:actions(Actions), - {reply,{bert,io(<<>>)},Req,State}; - -info(#direct{data=Message}, Req, State) -> - nitro:actions([]), - {reply,{bert,case io(Message, State) of - {io,_,{stack,_}} = Io -> Io; - {io,Code,Res} -> {io,Code,{direct,Res}} end}, - Req,State}; - -info(Message,Req,State) -> {unknown,Message,Req,State}. - -% double render: actions could generate actions - -render_actions(Actions) -> - nitro:actions([]), - First = nitro:render(Actions), - Second = nitro:render(nitro:actions()), - nitro:actions([]), - nitro:to_binary([First,Second]). - -% n2o events - -html_events(#pickle{source=Source,pickled=Pickled,args=Linked}, State=#cx{token = Token}) -> - Ev = n2o:depickle(Pickled), - L = n2o_session:prolongate(), - Res = case Ev of - #ev{} when L =:= false -> render_ev(Ev,Source,Linked,State), <<>>; - #ev{} -> render_ev(Ev,Source,Linked,State), n2o_session:authenticate([], Token); - _CustomEnvelop -> %?LOG_ERROR("EV expected: ~p~n",[CustomEnvelop]), - {error,"EV expected"} end, - io(Res). - -% calling user code in exception-safe manner - --ifdef(OTP_RELEASE). - -render_ev(#ev{module=M,name=F,msg=P,trigger=T},_Source,Linked,State) -> - try case F of - api_event -> M:F(P,Linked,State); - event -> [erlang:put(K,V) || {K,V} <- Linked], M:F(P); - _ -> M:F(P,T,State) end - catch E:R:S -> ?LOG_EXCEPTION(E,R,S), {stack,S} end. - -io(Event, #cx{module=Module}) -> - try X = Module:event(Event), {io,render_actions(nitro:actions()),X} - catch E:R:S -> ?LOG_EXCEPTION(E,R,S), {io,[],{stack,S}} end. - -io(Data) -> - try {io,render_actions(nitro:actions()),Data} - catch E:R:S -> ?LOG_EXCEPTION(E,R,S), {io,[],{stack,S}} end. - --else. - -render_ev(#ev{module=M,name=F,msg=P,trigger=T},_Source,Linked,State) -> - try case F of - api_event -> M:F(P,Linked,State); - event -> [erlang:put(K,V) || {K,V} <- Linked], M:F(P); - _ -> M:F(P,T,State) end - catch E:R -> S = erlang:get_stacktrace(), ?LOG_EXCEPTION(E,R,S), {stack,S} end. - -io(Event, #cx{module=Module}) -> - try X = Module:event(Event), {io,render_actions(nitro:actions()),X} - catch E:R -> S = erlang:get_stacktrace(), ?LOG_EXCEPTION(E,R,S), {io,<<>>,{stack,S}} end. - -io(Data) -> - try {io,render_actions(nitro:actions()),Data} - catch E:R -> S = erlang:get_stacktrace(), ?LOG_EXCEPTION(E,R,S), {io,<<>>,{stack,S}} end. - --endif. - -% event Nitrogen Web Framework protocol - -event(_) -> []. - diff --git a/src/protos/n2o_pack.erl b/src/protos/n2o_pack.erl deleted file mode 100644 index 3d2b13bb..00000000 --- a/src/protos/n2o_pack.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(n2o_pack). -%-compile({parse_transform, n2o_igor}). --entry(info/3). --proto(n2o_ftp). --proto(n2o_nitro). --proto(n2o_heart).