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
-
-
-
-
-
-
-
-
-
-
- DEV
- N2O
- NITRO
-
-
-
-
- NITRO
-
-
-
-
-
- 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{}) }).
-
-
-
-
-
-
-
-2005—2019 © Synrc Research Center
-
-
-
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
-
-
-
-
-
-
-
-
-
-
- DEV
- N2O
- 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); }
-
-
-
-
-2005—2019 © Synrc Research Center
-
-
-
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).