From d92ce489e31458005a162e934d1fbc756db8c148 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Mon, 18 Sep 2017 03:09:06 +0300 Subject: [PATCH] Publish --- build.bat | 72 + build/esiur-debug.js | 4935 +++++++++++++++++++++++++++ build/esiur.js | 1 + examples/test-debug.html | 37 + examples/test-plain.html | 73 + examples/test.html | 37 + external/sha256.min.js | 9 + index.html | 73 + src/AsyncBag.js | 61 + src/AsyncQueue.js | 66 + src/AsyncReply.js | 53 + src/AutoList.js | 88 + src/AutoMap.js | 67 + src/BinaryList.js | 214 ++ src/Codec.js | 622 ++++ src/DataConverter.js | 490 +++ src/DataType.js | 110 + src/DistributedConnection.js | 860 +++++ src/DistributedResource.js | 180 + src/DistributedResourceQueueItem.js | 40 + src/EventTemplate.js | 49 + src/FunctionTemplate.js | 48 + src/Guid.js | 37 + src/IDestructible.js | 37 + src/IEventHandler.js | 78 + src/IIPAuthPacket.js | 264 ++ src/IIPPacket.js | 544 +++ src/IResource.js | 59 + src/IStore.js | 44 + src/Instance.js | 142 + src/MemberTemplate.js | 38 + src/NetworkBuffer.js | 115 + src/NotModified.js | 30 + src/PropertyTemplate.js | 83 + src/ResourceArray.js | 36 + src/ResourceTemplate.js | 284 ++ src/SendList.js | 39 + src/Structure.js | 37 + src/StructureArray.js | 36 + src/Warehouse.js | 129 + 40 files changed, 10217 insertions(+) create mode 100644 build.bat create mode 100644 build/esiur-debug.js create mode 100644 build/esiur.js create mode 100644 examples/test-debug.html create mode 100644 examples/test-plain.html create mode 100644 examples/test.html create mode 100644 external/sha256.min.js create mode 100644 index.html create mode 100644 src/AsyncBag.js create mode 100644 src/AsyncQueue.js create mode 100644 src/AsyncReply.js create mode 100644 src/AutoList.js create mode 100644 src/AutoMap.js create mode 100644 src/BinaryList.js create mode 100644 src/Codec.js create mode 100644 src/DataConverter.js create mode 100644 src/DataType.js create mode 100644 src/DistributedConnection.js create mode 100644 src/DistributedResource.js create mode 100644 src/DistributedResourceQueueItem.js create mode 100644 src/EventTemplate.js create mode 100644 src/FunctionTemplate.js create mode 100644 src/Guid.js create mode 100644 src/IDestructible.js create mode 100644 src/IEventHandler.js create mode 100644 src/IIPAuthPacket.js create mode 100644 src/IIPPacket.js create mode 100644 src/IResource.js create mode 100644 src/IStore.js create mode 100644 src/Instance.js create mode 100644 src/MemberTemplate.js create mode 100644 src/NetworkBuffer.js create mode 100644 src/NotModified.js create mode 100644 src/PropertyTemplate.js create mode 100644 src/ResourceArray.js create mode 100644 src/ResourceTemplate.js create mode 100644 src/SendList.js create mode 100644 src/Structure.js create mode 100644 src/StructureArray.js create mode 100644 src/Warehouse.js diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..c0c88c1 --- /dev/null +++ b/build.bat @@ -0,0 +1,72 @@ +@echo off + +del "build\esiur-debug.js" +del "build\esiur.js" + +type "src\IEventHandler.js" > build\esiur-debug.js +echo. >> build\esiur-debug.js +type "external\sha256.min.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\IDestructible.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\AutoList.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\IResource.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\IStore.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\Structure.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\StructureArray.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\ResourceArray.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\MemberTemplate.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\AsyncReply.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\AsyncBag.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\AsyncQueue.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\BinaryList.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\Codec.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\DataConverter.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\DataType.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\DistributedConnection.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\DistributedResource.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\DistributedResourceQueueItem.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\EventTemplate.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\FunctionTemplate.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\Guid.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\IIPAuthPacket.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\IIPPacket.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\Instance.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\NetworkBuffer.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\NotModified.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\PropertyTemplate.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\ResourceTemplate.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\SendList.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js +type "src\Warehouse.js" >> build\esiur-debug.js +echo. >> build\esiur-debug.js + +REM minify build/esiur-debug.js -o build/esiur.js +uglifyjs build/esiur-debug.js -c -o build/esiur.js diff --git a/build/esiur-debug.js b/build/esiur-debug.js new file mode 100644 index 0000000..74705ed --- /dev/null +++ b/build/esiur-debug.js @@ -0,0 +1,4935 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 30/08/2017. + */ + +class IEventHandler +{ + _register(event) + { + this._events[event] = []; + } + + constructor() + { + this._events = {}; + } + + _emit(event) + { + event = event.toLowerCase(); + var args = Array.prototype.slice.call(arguments, 1); + if (this._events[event]) + for(var i = 0; i < this._events[event].length; i++) + if (this._events[event][i].apply(this, args)) + return true; + + return false; + } + + on(event, fn) + { + event = event.toLowerCase(); + // add + if (!this._events[event]) + this._events[event] = []; + this._events[event].push(fn); + return this; + } + + off(event, fn) + { + event = event.toLocaleString(); + if (this._events[event]) + { + if (fn) + { + var index = this._events[event].indexOf(fn); + if (index > -1) + this._events[event].splice(index, 1); + } + else + { + this._events[event] = []; + } + } + } +} +/** + * [js-sha256]{@link https://github.com/emn178/js-sha256} + * + * @version 0.6.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2014-2017 + * @license MIT + */ +!function(){"use strict";function t(t,i){i?(p[0]=p[16]=p[1]=p[2]=p[3]=p[4]=p[5]=p[6]=p[7]=p[8]=p[9]=p[10]=p[11]=p[12]=p[13]=p[14]=p[15]=0,this.blocks=p):this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],t?(this.h0=3238371032,this.h1=914150663,this.h2=812702999,this.h3=4144912697,this.h4=4290775857,this.h5=1750603025,this.h6=1694076839,this.h7=3204075428):(this.h0=1779033703,this.h1=3144134277,this.h2=1013904242,this.h3=2773480762,this.h4=1359893119,this.h5=2600822924,this.h6=528734635,this.h7=1541459225),this.block=this.start=this.bytes=0,this.finalized=this.hashed=!1,this.first=!0,this.is224=t}function i(i,r,e){var n="string"!=typeof i;if(n){if(null===i||void 0===i)throw h;i.constructor===s.ArrayBuffer&&(i=new Uint8Array(i))}var o=i.length;if(n){if("number"!=typeof o||!Array.isArray(i)&&(!a||!ArrayBuffer.isView(i)))throw h}else{for(var f,u=[],o=i.length,c=0,y=0;o>y;++y)f=i.charCodeAt(y),128>f?u[c++]=f:2048>f?(u[c++]=192|f>>6,u[c++]=128|63&f):55296>f||f>=57344?(u[c++]=224|f>>12,u[c++]=128|f>>6&63,u[c++]=128|63&f):(f=65536+((1023&f)<<10|1023&i.charCodeAt(++y)),u[c++]=240|f>>18,u[c++]=128|f>>12&63,u[c++]=128|f>>6&63,u[c++]=128|63&f);i=u}i.length>64&&(i=new t(r,!0).update(i).array());for(var p=[],l=[],y=0;64>y;++y){var d=i[y]||0;p[y]=92^d,l[y]=54^d}t.call(this,r,e),this.update(l),this.oKeyPad=p,this.inner=!0,this.sharedMemory=e}var h="input is invalid type",s="object"==typeof window?window:{},r=!s.JS_SHA256_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;r&&(s=global);var e=!s.JS_SHA256_NO_COMMON_JS&&"object"==typeof module&&module.exports,n="function"==typeof define&&define.amd,a="undefined"!=typeof ArrayBuffer,o="0123456789abcdef".split(""),f=[-2147483648,8388608,32768,128],u=[24,16,8,0],c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],y=["hex","array","digest","arrayBuffer"],p=[];(s.JS_SHA256_NO_NODE_JS||!Array.isArray)&&(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)});var l=function(i,h){return function(s){return new t(h,!0).update(s)[i]()}},d=function(i){var h=l("hex",i);r&&(h=v(h,i)),h.create=function(){return new t(i)},h.update=function(t){return h.create().update(t)};for(var s=0;so;){if(this.hashed&&(this.hashed=!1,f[0]=this.block,f[16]=f[1]=f[2]=f[3]=f[4]=f[5]=f[6]=f[7]=f[8]=f[9]=f[10]=f[11]=f[12]=f[13]=f[14]=f[15]=0),i)for(n=this.start;r>o&&64>n;++o)f[n>>2]|=t[o]<o&&64>n;++o)e=t.charCodeAt(o),128>e?f[n>>2]|=e<e?(f[n>>2]|=(192|e>>6)<>2]|=(128|63&e)<e||e>=57344?(f[n>>2]|=(224|e>>12)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<>2]|=(240|e>>18)<>2]|=(128|e>>12&63)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<=64?(this.block=f[16],this.start=n-64,this.hash(),this.hashed=!0):this.start=n}return this}},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,i=this.lastByteIndex;t[16]=this.block,t[i>>2]|=f[3&i],this.block=t[16],i>=56&&(this.hashed||this.hash(),t[0]=this.block,t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[15]=this.bytes<<3,this.hash()}},t.prototype.hash=function(){var t,i,h,s,r,e,n,a,o,f,u,y=this.h0,p=this.h1,l=this.h2,d=this.h3,v=this.h4,A=this.h5,w=this.h6,b=this.h7,g=this.blocks;for(t=16;64>t;++t)r=g[t-15],i=(r>>>7|r<<25)^(r>>>18|r<<14)^r>>>3,r=g[t-2],h=(r>>>17|r<<15)^(r>>>19|r<<13)^r>>>10,g[t]=g[t-16]+i+g[t-7]+h<<0;for(u=p&l,t=0;64>t;t+=4)this.first?(this.is224?(a=300032,r=g[0]-1413257819,b=r-150054599<<0,d=r+24177077<<0):(a=704751109,r=g[0]-210244248,b=r-1521486534<<0,d=r+143694565<<0),this.first=!1):(i=(y>>>2|y<<30)^(y>>>13|y<<19)^(y>>>22|y<<10),h=(v>>>6|v<<26)^(v>>>11|v<<21)^(v>>>25|v<<7),a=y&p,s=a^y&l^u,n=v&A^~v&w,r=b+h+n+c[t]+g[t],e=i+s,b=d+r<<0,d=r+e<<0),i=(d>>>2|d<<30)^(d>>>13|d<<19)^(d>>>22|d<<10),h=(b>>>6|b<<26)^(b>>>11|b<<21)^(b>>>25|b<<7),o=d&y,s=o^d&p^a,n=b&v^~b&A,r=w+h+n+c[t+1]+g[t+1],e=i+s,w=l+r<<0,l=r+e<<0,i=(l>>>2|l<<30)^(l>>>13|l<<19)^(l>>>22|l<<10),h=(w>>>6|w<<26)^(w>>>11|w<<21)^(w>>>25|w<<7),f=l&d,s=f^l&y^o,n=w&b^~w&v,r=A+h+n+c[t+2]+g[t+2],e=i+s,A=p+r<<0,p=r+e<<0,i=(p>>>2|p<<30)^(p>>>13|p<<19)^(p>>>22|p<<10),h=(A>>>6|A<<26)^(A>>>11|A<<21)^(A>>>25|A<<7),u=p&l,s=u^p&d^f,n=A&w^~A&b,r=v+h+n+c[t+3]+g[t+3],e=i+s,v=y+r<<0,y=r+e<<0;this.h0=this.h0+y<<0,this.h1=this.h1+p<<0,this.h2=this.h2+l<<0,this.h3=this.h3+d<<0,this.h4=this.h4+v<<0,this.h5=this.h5+A<<0,this.h6=this.h6+w<<0,this.h7=this.h7+b<<0},t.prototype.hex=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,f=o[t>>28&15]+o[t>>24&15]+o[t>>20&15]+o[t>>16&15]+o[t>>12&15]+o[t>>8&15]+o[t>>4&15]+o[15&t]+o[i>>28&15]+o[i>>24&15]+o[i>>20&15]+o[i>>16&15]+o[i>>12&15]+o[i>>8&15]+o[i>>4&15]+o[15&i]+o[h>>28&15]+o[h>>24&15]+o[h>>20&15]+o[h>>16&15]+o[h>>12&15]+o[h>>8&15]+o[h>>4&15]+o[15&h]+o[s>>28&15]+o[s>>24&15]+o[s>>20&15]+o[s>>16&15]+o[s>>12&15]+o[s>>8&15]+o[s>>4&15]+o[15&s]+o[r>>28&15]+o[r>>24&15]+o[r>>20&15]+o[r>>16&15]+o[r>>12&15]+o[r>>8&15]+o[r>>4&15]+o[15&r]+o[e>>28&15]+o[e>>24&15]+o[e>>20&15]+o[e>>16&15]+o[e>>12&15]+o[e>>8&15]+o[e>>4&15]+o[15&e]+o[n>>28&15]+o[n>>24&15]+o[n>>20&15]+o[n>>16&15]+o[n>>12&15]+o[n>>8&15]+o[n>>4&15]+o[15&n];return this.is224||(f+=o[a>>28&15]+o[a>>24&15]+o[a>>20&15]+o[a>>16&15]+o[a>>12&15]+o[a>>8&15]+o[a>>4&15]+o[15&a]),f},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,o=[t>>24&255,t>>16&255,t>>8&255,255&t,i>>24&255,i>>16&255,i>>8&255,255&i,h>>24&255,h>>16&255,h>>8&255,255&h,s>>24&255,s>>16&255,s>>8&255,255&s,r>>24&255,r>>16&255,r>>8&255,255&r,e>>24&255,e>>16&255,e>>8&255,255&e,n>>24&255,n>>16&255,n>>8&255,255&n];return this.is224||o.push(a>>24&255,a>>16&255,a>>8&255,255&a),o},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(this.is224?28:32),i=new DataView(t);return i.setUint32(0,this.h0),i.setUint32(4,this.h1),i.setUint32(8,this.h2),i.setUint32(12,this.h3),i.setUint32(16,this.h4),i.setUint32(20,this.h5),i.setUint32(24,this.h6),this.is224||i.setUint32(28,this.h7),t},i.prototype=new t,i.prototype.finalize=function(){if(t.prototype.finalize.call(this),this.inner){this.inner=!1;var i=this.array();t.call(this,this.is224,this.sharedMemory),this.update(this.oKeyPad),this.update(i),t.prototype.finalize.call(this)}};var b=d();b.sha256=b,b.sha224=d(!0),b.sha256.hmac=w(),b.sha224.hmac=w(!0),e?module.exports=b:(s.sha256=b.sha256,s.sha224=b.sha224,n&&define(function(){return b}))}(); +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 31/08/2017. + */ +class IDestructible extends IEventHandler +{ + destroy() + { + this._emit("destroy", this); + } + + constructor() + { + super(); + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 05/09/2017. + */ + +class AutoList extends IEventHandler +{ + constructor() + { + super(); + this.list = []; + } + + add(value) + { + if (value instanceof IDestructible) + value.on("destroy", this._item_destroyed); + + this.list.push(value); + + this._emit("add", value); + } + + set(index, value) + { + if (index >= this.list.length || index < 0) + return; + + if (value instanceof IDestructible) + value.on("destroy", this._item_destroyed); + + if (this.list[index] instanceof IDestructible) + this.list[index].off("destroy", this._item_destroyed); + + this.list[index] = value; + } + + remove(value) + { + this.removeAt(this.list.indexOf(value)); + } + + contains(value) + { + return this.list.indexOf(value) > -1; + } + + removeAt(index) + { + if (index >= this.list.length || index < 0) + return; + + var item = this.list[index]; + + if (item instanceof IDestructible) + item.off("destroy", this._item_destroyed); + + this.list.splice(index, 1); + + this._emit("remove", item); + } + + _item_destroyed(sender) + { + this.remove(sender); + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var ResourceTrigger = +{ + Loaded : 0, + Initialize: 1, + Terminate: 2, + Configure: 3, + SystemInitialized: 4, + SystemTerminated: 5, + SystemReload: 6 +}; + +class IResource extends IDestructible +{ + trigger(trigger) + { + + } + + constructor() + { + super(); + } + + static getTemplate() + { + return { + namespace: "Esiur", + properties: [], + functions: [], + events: [] + } + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +class IStore extends IResource { + get(path) { + + } + + retrieve(iid) { + + } + + put(resource) { + + } + + constructor() + { + super(); + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class Structure +{ + getKeys() { + var rt = []; + for (var i in this) + if (!(this[i] instanceof Function)) + rt.push(i); + + return rt; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 06/09/2017. + */ + +class StructureArray extends Array +{ + push(value) + { + if (value instanceof Structure) + super.push(value); + else + return; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class ResourceArray extends Array +{ + push(value) + { + if (value instanceof IResource) + super.push(value); + else + return; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 24/08/2017. + */ + + +var MemberType = { + Function: 0, + Property: 1, + Event: 2 +}; + +class MemberTemplate { + compose() { + return DC.stringToBytes(this.name); + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +class AsyncReply +{ + then(callback) + { + this.callbacks.push(callback); + if (this.ready) + callback(this.result, this); + } + + trigger(result) + { + this.result = result; + this.ready = true; + + for(var i = 0; i < this.callbacks.length; i++) + this.callbacks[i](result, this); + } + + constructor(result) + { + this.callbacks = []; + + if (result) { + this.result = result; + this.ready = true; + } + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +class AsyncBag extends AsyncReply +{ + constructor() { + super(); + this.replies = []; + this.results = []; + this.count = 0; + this.sealedBag = false; + } + + seal() + { + this.sealedBag = true; + + if (this.results.length == 0) + this.trigger([]); + + var self = this; + + for(var i = 0; i < this.results.length; i++) + this.replies[i].then(function(r, reply){ + self.results[self.replies.indexOf(reply)] = r; + self.count++; + if (self.count == self.results.length) + self.trigger(self.results); + }); + } + + add(reply) + { + if (!this.sealedBag) { + this.replies.push(reply); + this.results.push(null); + } + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +class AsyncQueue extends AsyncReply +{ + + constructor() + { + super(); + this.list = []; + + var self = this; + + this.processQueue = function () + { + for (var i = 0; i < self.list.length; i++) + if (self.list[i].ready) + { + self.trigger(self.list[i].result); + self.list.splice(i, 1); + i--; + } + else + break; + + self.ready = (self.list.length == 0); + } + } + + add(reply) + { + this.list.push(reply); + this.ready = false; + reply.then(this.processQueue); + } + + remove(reply) + { + this.list.splice(this.list.indexOf(reply), 1); + this.processQueue(); + } + + + +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/08/2017. + */ + +var BL = function(){ + return new BinaryList(); +}; + +class BinaryList +{ + + constructor() + { + this.list = []; + } + + + addRange(bl) + { + for(var i = 0; i < bl.list.length; i++) + this.list.push(bl.list[i]); + + return this; + } + + add(typedValue, position) + { + if (position !== undefined) + this.list.splice(position, 0, typedValue); + else + this.list.push(typedValue); + return this; + } + + get length() + { + return this.toArray().length; + } + + toArray() + { + var ars = []; + // calculate length + for(var i = 0; i < this.list.length; i++) + { + switch (this.list[i].type) + { + case DataType.Bool: + ars.push(DC.boolToBytes(this.list[i].value)); + break; + case DataType.UInt8: + ars.push(DC.uint8ToBytes(this.list[i].value)); + break; + case DataType.Int8: + ars.push(DC.int8ToBytes(this.list[i].value)); + break; + case DataType.Char: + ars.push(DC.charToBytes(this.list[i].value)); + break; + case DataType.UInt16: + ars.push(DC.uint16ToBytes(this.list[i].value)); + break; + case DataType.Int16: + ars.push(DC.int16ToBytes(this.list[i].value)); + break; + case DataType.UInt32: + ars.push(DC.uint32ToBytes(this.list[i].value)); + break; + case DataType.Int32: + ars.push(DC.int32ToBytes(this.list[i].value)); + break; + case DataType.UInt64: + ars.push(DC.uint64ToBytes(this.list[i].value)); + break; + case DataType.Int64: + ars.push(DC.int64ToBytes(this.list[i].value)); + break; + case DataType.Float32: + ars.push(DC.float32ToBytes(this.list[i].value)); + break; + case DataType.Float64: + ars.push(DC.float64ToBytes(this.list[i].value)); + break; + case DataType.String: + ars.push(DC.stringToBytes(this.list[i].value)); + break; + case DataType.DateTime: + ars.push(DC.dateTimeToBytes(this.list[i].value)); + break; + case DataType.UInt8Array: + ars.push(this.list[i].value); + + //case DataType.Resource: + // ars.push(DC.uint32ToBytes(this.list[i].value.instance.id)); + // break; + //case DataType.DistributedResource: + // ars.push(DC.int8ToBytes(this.list[i].value)); + // break; + + + + } + } + + var length = 0; + ars.forEach(function(a){ + length += a.length; + }); + + var rt = new Uint8Array(length); + + var offset = 0; + for(var i = 0; i < ars.length; i++) { + rt.set(ars[i], offset); + offset+=ars[i].length; + } + + return rt; + } + + addUint8Array(value, position) + { + return this.add({type: DataType.UInt8Array, value: value}, position); + } + + + addHex(value, position) + { + return this.addUint8Array(DC.hexToBytes(value), position); + } + + addString(value, position) + { + return this.add({type: DataType.String, value: value}, position); + } + + addUint8(value, position) + { + return this.add({type: DataType.UInt8, value: value}, position); + } + + addInt8(value, position) + { + return this.add({type: DataType.Int8, value: value}, position); + } + + addChar(value, position) + { + return this.add({type: DataType.Char, value: value}, position); + } + + addUint16(value, position) + { + return this.add({type: DataType.UInt16, value: value}, position); + } + + addInt16(value, position) + { + return this.add({type: DataType.Int16, value: value}, position); + } + + addUint32(value, position) + { + return this.add({type: DataType.UInt32, value: value}, position); + } + + addInt32(value, position) + { + return this.add({type: DataType.Int32, value: value}, position); + } + + addUint64(value, position) + { + return this.add({type: DataType.UInt64, value: value}, position); + } + + addInt64(value, position) + { + return this.add({type: DataType.Int64, value: value}, position); + } + + addFloat32(value, position) + { + return this.add({type: DataType.Float32, value: value}, position); + } + + addFloat64(value, position) + { + return this.add({type: DataType.Float64, value: value}, position); + } + +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var ResourceComparisonResult = + { + Null: 0, + Distributed: 1, + DistributedSameClass: 2, + Local: 3, + Same: 4 + }; + +var StructureComparisonResult = + { + Null: 0, + Structure: 1, + StructureSameKeys: 2, + StructureSameTypes: 3, + Same: 4 + }; + +class Codec { + + static parse(data, offset, sizeObject, connection, dataType = DataType.Unspecified) { + + var size; + + var reply = new AsyncReply(); + + var isArray; + var t; + + if (dataType == DataType.Unspecified) { + size = 1; + dataType = data[offset++]; + } + else + size = 0; + + t = dataType & 0x7F; + + isArray = (dataType & 0x80) == 0x80; + + var payloadSize = DataType.sizeOf(dataType); + + var contentLength = 0; + + // check if we have the enough data + if (payloadSize == -1) { + contentLength = data.getUint32(offset); + offset += 4; + size += 4 + contentLength; + } + else + size += payloadSize; + + + sizeObject.size = size; + + if (isArray) { + switch (t) { + // VarArray ? + case DataType.Void: + return Codec.parseVarArray(data, offset, contentLength, connection); + + case DataType.Bool: + return new AsyncReply(data.getBooleanArray(offset, contentLength)); + + case DataType.UInt8: + return new AsyncReply(data.getUint8Array(offset, contentLength)); + + case DataType.Int8: + return new AsyncReply(data.getInt8Array(offset, contentLength)); + + case DataType.Char: + return new AsyncReply(data.getCharArray(offset, contentLength)); + + case DataType.Int16: + return new AsyncReply(data.getInt16Array(offset, contentLength)); + + case DataType.UInt16: + return new AsyncReply(data.getUint16Array(offset, contentLength)); + + case DataType.Int32: + return new AsyncReply(data.getInt32Array(offset, contentLength)); + + case DataType.UInt32: + return new AsyncReply(data.getUint32Array(offset, contentLength)); + + case DataType.Int64: + return new AsyncReply(data.getInt64Array(offset, contentLength)); + + case DataType.UInt64: + return new AsyncReply(data.getUint64Array(offset, contentLength)); + + case DataType.Float32: + return new AsyncReply(data.getFloat32Array(offset, contentLength)); + + case DataType.Float64: + return new AsyncReply(data.getFloat64Array(offset, contentLength)); + + case DataType.String: + return new AsyncReply(data.getStringArray(offset, contentLength)); + + case DataType.Resource: + case DataType.DistributedResource: + return Codec.parseResourceArray(data, offset, contentLength, connection); + + case DataType.DateTime: + return new AsyncReply(data.getDateTimeArray(offset, contentLength)); + + case DataType.Structure: + return Codec.parseStructureArray(data, offset, contentLength, connection); + } + } + else { + switch (t) { + case DataType.NotModified: + return new AsyncReply(new NotModified()); + + case DataType.Void: + return new AsyncReply(null); + + case DataType.Bool: + return new AsyncReply(data.getBoolean(offset)); + + case DataType.UInt8: + return new AsyncReply(data[offset]); + + case DataType.Int8: + return new AsyncReply(data.getInt8(offset)); + + case DataType.Char: + return new AsyncReply(data.getChar(offset)); + + case DataType.Int16: + return new AsyncReply(data.getInt16(offset)); + + case DataType.UInt16: + return new AsyncReply(data.getUint16(offset)); + + case DataType.Int32: + return new AsyncReply(data.getInt32(offset)); + + case DataType.UInt32: + return new AsyncReply(data.getUint32(offset)); + + case DataType.Int64: + return new AsyncReply(data.getInt64(offset)); + + case DataType.UInt64: + return new AsyncReply(data.getUint64(offset)); + + case DataType.Float32: + return new AsyncReply(data.getFloat32(offset)); + + case DataType.Float64: + return new AsyncReply(data.getFloat64(offset)); + + case DataType.String: + return new AsyncReply(data.getString(offset, contentLength)); + + case DataType.Resource: + return Codec.parseResource(data, offset); + + case DataType.DistributedResource: + return Codec.parseDistributedResource(data, offset, connection); + + case DataType.DateTime: + return new AsyncReply(data.getDateTime(offset)); + + case DataType.Structure: + return Codec.parseStructure(data, offset, contentLength, connection); + } + } + + + return null; + } + + static parseResource(data, offset) { + return Warehouse.get(data.getUint32(offset)); + } + + static parseDistributedResource(data, offset, connection) { + //var g = data.getGuid(offset); + //offset += 16; + + // find the object + var iid = data.getUint32(offset); + + return connection.fetch(iid);// Warehouse.Get(iid); + } + + + static parseStructure(data, offset, contentLength, connection, keylist = null, typelist = null, keys = null, types = null) { + var reply = new AsyncReply(); + var bag = new AsyncBag(); + + + if (keylist == null) + keylist = []; + if (typelist == null) + typelist = []; + + if (keys == null) { + while (contentLength > 0) { + var len = data[offset++]; + keylist.push(data.getString(offset, len)); + offset += len; + + typelist.push(data[offset]); + + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection)); + contentLength -= rt.size + len + 1; + offset += rt.size; + } + } + else if (types == null) { + for (var i = 0; i < keys.length; i++) + keylist.push(keys[i]); + + while (contentLength > 0) { + typelist.push(data[offset]); + + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection)); + contentLength -= rt.size + 1; + offset += rt.size + 1; + } + } + else { + for (var i = 0; i < keys.length; i++) { + keylist.push(keys[i]); + typelist.push(types[i]); + } + + var i = 0; + while (contentLength > 0) { + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection, types[i])); + contentLength -= rt.size; + offset += rt.size; + i++; + } + } + + bag.seal(); + + bag.then(function (res) { + // compose the list + var s = new Structure(); + for (var i = 0; i < keylist.length; i++) + s[keylist[i]] = res[i]; + reply.trigger(s); + }); + + + return reply; + } + + + static parseVarArray(data, offset, contentLength, connection) { + var rt = new AsyncBag(); + + while (contentLength > 0) { + var cs = {}; + + rt.add(Codec.parse(data, offset, cs, connection)); + + if (cs.size > 0) { + offset += cs.size; + contentLength -= cs.size; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.seal(); + return rt; + } + + + static compose(value, connection, prependType = true) { + + var type = Codec.getDataType(value, connection); + var rt = new BinaryList(); + + switch (type) { + case DataType.Void: + // nothing to do; + break; + + case DataType.String: + var st = DC.stringToBytes(value); + rt.addUint32(st.length).addUint8Array(st); + break; + + case DataType.Resource: + rt.addUint32(value.instance.id); + break; + + case DataType.DistributedResource: +// rt.addUint8Array(DC.stringToBytes(value.instance.template.classId)).addUint32(value.instance.id); + rt.addUint32(value.instance.id); + break; + + case DataType.Structure: + rt.addUint8Array(Codec.composeStructure(value, connection, true, true, true)); + break; + + case DataType.VarArray: + rt.addUint8Array(Codec.composeVarArray(value, connection, true)); + break; + + case DataType.ResourceArray: + rt.addUint8Array(Codec.composeResourceArray(value, connection, true)); + break; + + case DataType.StructureArray: + rt.addUint8Array(Codec.composeStructureArray(value, connection, true)); + break; + + default: + rt.add({type: type, value: value}); + if (DataType.isArray(type)) + rt.addUint32(rt.length, 0); + + break; + } + + if (prependType) + rt.addUint8(type, 0); + + return rt.toArray(); + } + + static composeVarArray(array, connection, prependLength = false) { + var rt = new BinaryList(); + + for (var i = 0; i < array.length; i++) + rt.addUint8Array(Codec.compose(array[i], connection)); + + if (prependLength) + rt.addUint32(rt.length, 0); + return rt.toArray(); + } + + static composeStructure(value, connection, includeKeys = true, includeTypes = true, prependLength = false) { + var rt = new BinaryList(); + + var keys = value.getKeys(); + + if (includeKeys) { + for (var i = 0; i < keys.length; i++) { + var key = DC.stringToBytes(keys[i]); + rt.addUint8(key.length).addString(key).addUint8Array(DC.compose(value[i], connection)); + } + } + else { + for (var i = 0; i < keys.length; i++) + rt.addUint8Array(DC.compose(value[keys[i]], connection, includeTypes)); + } + + if (prependLength) + rt.addUint32(rt.length, 0); + + return rt.toArray(); + } + + static composeStructureArray(structures, connection, prependLength = false) { + if (structures == null || structures.length == 0 || !(structures instanceof StructureArray)) + return new DC(0); + + var rt = new BinaryList(); + var comparision = StructureComparisonResult.Structure; + + rt.addUint8(comparision); + rt.addUint8Array(Codec.composeStructure(structures[0], connection)); + + for (var i = 1; i < structures.Length; i++) { + comparision = Codec.compareStructure(structures[i - 1], structures[i], connection); + rt.addUint8(comparision); + + if (comparision == StructureComparisonResult.Structure) + rt.addUint8Array(Codec.composeStructure(structures[i], connection)); + else if (comparision == StructureComparisonResult.StructureSameKeys) + rt.addUint8Array(Codec.composeStructure(structures[i], connection, false)); + else if (comparision == StructureComparisonResult.StructureSameTypes) + rt.addUint8Array(Codec.composeStructure(structures[i], connection, false, false)); + } + + if (prependLength) + rt.addUint32(rt.length, 0); + + return rt.toArray(); + } + + static compareStructure(previous, next, connection) { + if (next == null) + return StructureComparisonResult.Null; + + if (previous == null) + return StructureComparisonResult.Structure; + + if (next == previous) + return StructureComparisonResult.Same; + + if (previous.length != next.length) + return StructureComparisonResult.Structure; + + var previousKeys = previous.getKeys(); + var nextKeys = next.getKeys(); + + for (var i = 0; i < previousKeys.length; i++) + if (previousKeys[i] != nextKeys[i]) + return StructureComparisonResult.Structure; + + var previousTypes = Codec.getStructureDateTypes(previous, connection); + var nextTypes = Codec.getStructureDateTypes(next, connection); + + for (var i = 0; i < previousTypes.length; i++) + if (previousTypes[i] != nextTypes[i]) + return StructureComparisonResult.StructureSameKeys; + + return StructureComparisonResult.StructureSameTypes; + } + + static getStructureDateTypes(structure, connection) { + var keys = structure.getKeys(); + var types = []; + + for (var i = 0; i < keys.length; i++) + types.push(Codec.getDataType(structure[keys[i]], connection)); + return types; + } + +static isLocalResource(resource, connection) { + if (resource instanceof DistributedResource) + if (resource.connection == connection) + return true; + + return false; +} + + static composeResource(resource, connection) { + if (Codec.isLocalResource(resource, connection)) + return BL().addUint32(resource.id); + else { + return BL().addUint8Array(resource.instance.template.classId.value).addUint32(resource.instance.id); + } + } + + static compareResource(previous, next, connection) { + if (next == null) + return ResourceComparisonResult.Null; + + if (next == previous) + return ResourceComparisonResult.Same; + + if (Codec.isLocalResource(next, connection)) + return ResourceComparisonResult.Local; + + if (previous == null) + return ResourceComparisonResult.Distributed; + + if (previous.instance.template.classId.valueOf() == next.instance.template.classId.valueOf()) + return ResourceComparisonResult.DistributedSameClass; + + return ResourceComparisonResult.Distributed; + } + + static composeResourceArray(resources, connection, prependLength = false) { + if (resources == null || resources.length == 0 || !(resources instanceof ResourceArray)) + return new DC(0); + + var rt = new BinaryList(); + var comparsion = Codec.compareResource(null, resources[0], connection); + + rt.addUint8(comparsion); + + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32(resources[0].id); + else if (comparsion == ResourceComparisonResult.Distributed) { + rt.addUint8Array(resources[0].instance.template.classId.value); + rt.addUint32(resources[0].instance.id); + } + + for (var i = 1; i < resources.length; i++) { + comparsion = Codec.compareResource(resources[i - 1], resources[i], connection); + rt.addUint8(comparsion); + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32(resources[0].id); + else if (comparsion == ResourceComparisonResult.Distributed) { + rt.addUint8Array(resources[0].instance.template.classId.value); + rt.addUint32(resources[0].instance.id); + } + else if (comparsion == ResourceComparisonResult.DistributedSameClass) { + rt.addUint32(resources[0].instance.id); + } + } + + if (prependLength) + rt.addUint32(0, rt.length); + + return rt.toArray(); + } + + + +static getDataType(value) { + switch (typeof value) { + case "number": + // float or ? + if (Math.floor(value) == value) { + if (value > 0) { + // larger than byte ? + if (value > 0xFF) { + // larger than short ? + if (value > 0xFFFF) { + // larger than int ? + if (value > 0xFFFFFFFF) { + return DataType.UInt64; + } + else { + return DataType.UInt32; + } + } + else { + return DataType.UInt16; + } + } + else { + return DataType.UInt8; + } + } + else { + if (value < -128) { + if (value < -32768) { + if (value < -2147483648) { + return DataType.Int64; + } + else { + return DataType.Int32; + } + } + else { + return DataType.Int16; + } + } + else { + return DataType.Int8; + } + } + } + else { + // float or double + return DataType.Float64; + } + break; + + case "string": + return DataType.String; + case "boolean": + return DataType.Bool; + case "object": + if (value instanceof Array) { + return DataType.VarArray; + } + else if (value instanceof IResource) { + return Codec.isLocalResource(value, connection) ? DataType.Resource : DataType.DistributedResource; + } + else if (value instanceof Date) { + return DataType.DateTime; + } + else if (value instanceof Uint8Array + || value instanceof ArrayBuffer) { + return DataType.UInt8Array; + } + else if (value instanceof Number) { + // JS numbers are always 64-bit float + return DataType.Float64; + } + else if (value instanceof Structure) { + return DataType.Structure; + } + else { + return DataType.Void + } + + break; + + default: + return DataType.Void; + } + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var UNIX_EPOCH = 621355968000000000; +var TWO_PWR_32 = (1 << 16) * (1 << 16); + +class DC extends Uint8Array// extends DataView // Data Converter +{ + constructor(bufferOrSize) { + super(bufferOrSize); + + //if (bufferOrSize instanceof ArrayBuffer) { + // this.buffer = bufferOrSize; + //} + //else + //{ + // this.buffer = new Uint8Array(bufferOrSize); + //} + + this.dv = new DataView(this.buffer); + } + + + static boolToBytes(value) + { + var rt = new DC(1); + rt.setBoolean(0, value); + return rt; + } + + static int8ToBytes(value) + { + var rt = new DC(1); + rt.setInt8(0, value); + return rt; + } + + static hexToBytes(value) + { + // convert hex to Uint8Array + var rt = new DC(value.length/2); + for(var i = 0; i < ar.length; i++) + rt[i] = parseInt(value.substr(i*2, 2), 16); + return rt; + } + + static uint8ToBytes(value) + { + var rt = new DC(1); + rt.setUint8(0, value); + return rt; + } + + static charToBytes(value) + { + var rt = new DC(2); + rt.setChar(0, value); + return rt; + } + + static int16ToBytes(value) + { + var rt = new DC(2); + rt.setInt16(0, value); + return rt; + } + + static uint16ToBytes(value) + { + var rt = new DC(2); + rt.setUint16(0, value); + return rt; + } + + static int32ToBytes(value) + { + var rt = new DC(4); + rt.setInt32(0, value); + return rt; + } + + static uint32ToBytes(value) + { + var rt = new DC(4); + rt.setUint32(0, value); + return rt; + } + + static float32ToBytes(value) + { + var rt = new DC(4); + rt.setFloat32(0, value); + return rt; + } + + static int64ToBytes(value) + { + var rt = new DC(8); + rt.setInt64(0, value); + return rt; + } + + static uint64ToBytes(value) + { + var rt = new DC(8); + rt.setUint64(0, value); + return rt; + } + + static float64ToBytes(value) + { + var rt = new DC(8); + rt.setFloat64(0, value); + return rt; + } + + static dateTimeToBytes(value) + { + var rt = new DC(8); + rt.setDateTime(0, value); + return rt; + } + + static stringToBytes(value) + { + var utf8 = unescape(encodeURIComponent(value)); + var rt = []; + + for (var i = 0; i < utf8.length; i++) + rt.push(utf8.charCodeAt(i)); + + return new DC(rt); + } + + + + append(src, offset, length) + { + if (!(src instanceof DC)) + src = new DC(src); + + var appendix = src.clip(offset, length); + var rt = new DC(this.length + appendix.length); + rt.set(this, 0); + rt.set(appendix, this.length); + return rt; + } + + static combine(a, aOffset, aLength, b, bOffset, bLength) + { + if (!(a instanceof DC)) + a = new DC(a); + if (!(b instanceof DC)) + b = new DC(b); + + a = a.clip(aOffset, aLength); + b = b.clip(bOffset, bLength); + + var rt = new DC(a.length + b.length); + rt.set(a, 0); + rt.set(b, a.length); + return rt; + } + + clip(offset, length) + { + return this.slice(offset, offset+length); + } + + getInt8(offset) + { + return this.dv.getUint8(offset); + } + + getUint8(offset) + { + return this[offset];// this.dv.getUint8(offset); + } + + getInt16(offset) + { + return this.dv.getInt16(offset); + } + + getUint16(offset) + { + return this.dv.getUint16(offset); + } + + getInt32(offset) + { + return this.dv.getInt32(offset); + } + + getUint32(offset) + { + return this.dv.getUint32(offset); + } + + getFloat32(offset) + { + return this.dv.getFloat32(offset); + } + + getFloat64(offset) + { + return this.dv.getFloat64(offset); + } + + setInt8(offset, value) + { + return this.dv.setInt8(offset, value); + } + + setUint8(offset, value) + { + return this.dv.setUint8(offset, value); + } + + setInt16(offset, value) + { + return this.dv.setInt16(offset, value); + } + + setUint16(offset, value) + { + return this.dv.setUint16(offset, value); + } + + setInt32(offset, value) + { + return this.dv.setInt32(offset, value); + } + + setUint32(offset, value) + { + return this.dv.setUint32(offset, value); + } + + setFloat32(offset, value) + { + return this.dv.setFloat32(offset, value); + } + + setFloat64(offset, value) + { + return this.dv.setFloat64(offset, value); + } + + getInt8Array(offset, length) + { + return new Int8Array(this.buffer, offset, length); + } + + getUint8Array(offset, length) + { + return new Uint8Array(this.buffer, offset, length); + } + + getInt16Array(offset, length) + { + return new Int16Array(this.buffer, offset, length); + } + + getUint16Array(offset, length) + { + return new Uint16Array(this.buffer, offset, length); + } + + getInt32Array(offset, length) + { + return new Int32Array(this.buffer, offset, length); + } + + getUint32Array(offset, length) + { + return new Uint32Array(this.buffer, offset, length); + } + + getFloat32Array(offset, length) + { + return new Float32Array(this.buffer, offset, length); + } + + getFloat64Array(offset, length) + { + return new Float64Array(this.buffer, offset, length); + } + + getInt64Array(offset, length) + { + return new Int64Array(this.buffer, offset, length); + } + + + getUint64Array(offset, length) + { + return new Uint64Array(this.buffer, offset, length); + } + + getBoolean(offset) + { + return this.getUint8(offset) > 0; + } + + setBoolean(offset, value) + { + this.setUint8(offset, value ? 1: 0); + } + + getBooleanArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i++) + rt.push(this.getBoolean(offset+i)); + return rt; + } + + getChar(offset) + { + return String.fromCharCode(this.getUint16(offset)); + } + + setChar(offset, value) + { + this.setUint16(offset, value.charCodeAt(0)); + } + + getCharArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i+=2) + rt.push(this.getChar(offset+i)); + return rt; + } + + getHex(offset, length) + { + var rt = ""; + for(var i = offset; i < offset + length; i++) { + var h = this[i].toString(16); + rt += h.length == 1 ? "0" + h : h; + } + + return rt; + } + + getString(offset, length) + { + if (typeof StringView != "undefined") + return new StringView(this.buffer, "UTF-8", offset, length); + else + { + var bytes = this.getUint8Array(offset, length); + var encodedString = String.fromCharCode.apply(null, bytes), + decodedString = decodeURIComponent(escape(encodedString)); + return decodedString; + } + } + + getStringArray(offset, length) + { + var rt = []; + var i = 0; + + while (i < length) + { + var cl = this.getUint32(offset + i); + i += 4; + rt.push(this.getString(offset + i, cl)); + i += cl; + } + + return rt; + } + + getInt64(offset) + { + var h = this.getInt32(offset); + var l = this.getInt32(offset + 4); + + return h * TWO_PWR_32 + ((l >= 0) ? l : TWO_PWR_32 + l); + } + + getUint64(offset) + { + var h = this.getUint32(offset); + var l = this.getUint32(offset + 4); + return h * TWO_PWR_32 + ((l >= 0) ? l : TWO_PWR_32 + l); + } + + setInt64(offset, value) + { + var l = (value % TWO_PWR_32) | 0; + var h = (value / TWO_PWR_32) | 0; + this.setInt32(offset, h); + this.setInt32(offset + 4, l); + } + + setUint64(offset, value) + { + var l = (value % TWO_PWR_32) | 0; + var h = (value / TWO_PWR_32) | 0; + this.setInt32(offset, h); + this.setInt32(offset + 4, l); + } + + setDateTime(offset, value) + { + // Unix Epoch + var ticks = 621355968000000000 + (value.getTime() * 10000); + this.setUint64(offset, ticks); + } + + getDateTime(offset) + { + var ticks = this.getUint64(offset); + return new Date(Math.round((ticks-DCStatic.UNIX_EPOCH)/10000)); + } + + getDateTimeArray(offset) + { + var rt = []; + for(var i = 0; i < length; i+=8) + rt.push(this.getDateTime(offset+i)); + return rt; + } + + getGuid(offset) + { + return new Guid(this.getUint8Array(offset, 16)); + + /* + var d = this.getUint8Array(offset, 16); + var rt = ""; + for (var i = 0; i < 16; i++) { + rt += String.fromCharCode(d[i]); + } + + return btoa(rt); + */ + } + + getGuidArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i+=16) + rt.push(this.getGuid(offset+i)); + return rt; + } + + sequenceEqual(ar) + { + if (ar.length != this.length) + return false; + else + { + for(var i = 0; i < this.length; i++) + if (ar[i] != this[i]) + return false; + } + + return true; + } +} + + + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +DataType = { + Void: 0x0, + //Variant, + Bool: 1, + Int8: 2, + UInt8: 3, + Char: 4, + Int16: 5, + UInt16: 6, + Int32: 7, + UInt32: 8, + Int64: 9, + UInt64: 10, + Float32: 11, + Float64: 12, + Decimal: 13, + DateTime: 14, + Resource: 15, + DistributedResource: 16, + ResourceLink: 17, + String: 18, + Structure: 19, + //Stream, + //Array = 0x80, + VarArray: 0x80, + BoolArray: 0x81, + UInt8Array: 0x82, + Int8Array: 0x83, + CharArray: 0x84, + Int16Array: 0x85, + UInt16Array: 0x86, + Int32Array: 0x87, + UInt32Array: 0x88, + Int64Array: 0x89, + UInt64Array: 0x8A, + Float32Array: 0x8B, + Float64Array: 0x8C, + DecimalArray: 0x8D, + DateTimeArray: 0x8E, + ResourceArray: 0x8F, + DistributedResourceArray: 0x90, + ResourceLinkArray: 0x91, + StringArray: 0x92, + StructureArray: 0x93, + NotModified: 0x7f, + Unspecified: 0xff, + + isArray: function(type) + { + return ((type & 0x80) == 0x80) && (type != DataType.NotModified); + }, + + sizeOf: function(type) + { + switch (type) + { + case DataType.Void: + case DataType.NotModified: + return 0; + case DataType.Bool: + case DataType.Int8: + case DataType.UInt8: + return 1; + case DataType.Char: + case DataType.Int16: + case DataType.UInt16: + return 2; + case DataType.Int32: + case DataType.UInt32: + case DataType.Float32: + case DataType.Resource: + return 4; + case DataType.Int64: + case DataType.UInt64: + case DataType.Float64: + case DataType.DateTime: + return 8; + case DataType.DistributedResource: + return 4; + + default: + return -1; + } + } +}; + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var AuthenticationType = +{ + Host: 0, + CoHost: 1, + Client: 2, + Alien: 3 +}; + +class DistributedConnection extends IStore { + + send(data) { + this.socket.send(data.buffer); + } + + sendParams() { + return new SendList(this); + } + + constructor(url, domain, username, password, checkInterval = 30, connectionTimeout = 600, revivingTime = 120) { + + super(); + + //Instance.Name = Global.GenerateCode(12); + this.hostType = AuthenticationType.Client; + this.domain = domain; + this.localUsername = username; + this.localPassword = DC.stringToBytes(password); + + this.socket = new WebSocket(url, "iip"); + this.socket.binaryType = "arraybuffer"; + this.socket.connection = this; + this.socket.networkBuffer = new NetworkBuffer(); + + this.debug = false; + this.totalReceived = 0; + this.totalSent = 0; + + this.checkInterval = checkInterval * 1000; // check every 30 seconds + this.connectionTimeout = connectionTimeout * 1000; // 10 minutes (4 pings failed) + this.revivingTime = revivingTime * 1000; // 2 minutes + this.lastAction = Date.now(); + + this.packet = new IIPPacket(); + this.authPacket = new IIPAuthPacket(); + + this.resources = {}; + this.templates = {}; + this.requests = {}; + this.pathRequests = {}; + this.templateRequests = {}; + this.resourceRequests = {}; + this.callbackCounter = 0; + + this.queue = new AsyncQueue(); + + this.queue.then(function (x) { + if (x.type == DistributedResourceQueueItemType.Event) { + x.resource._emitEventByIndex(x.index, x.value); + } + else { + x.resource._updatePropertyByIndex(x.index, x.value); + } + }); + + this.localNonce = new Uint8Array(32); + window.crypto.getRandomValues(this.localNonce); + + // declare (Credentials -> No Auth, No Enctypt) + var un = DC.stringToBytes(username); + var dmn = DC.stringToBytes(domain); + var self = this; + + this.socket.onopen = function () { + var bl = new BinaryList(); + bl.addUint8(0x60).addUint8(dmn.length).addUint8Array(dmn).addUint8Array(self.localNonce).addUint8(un.length).addUint8Array(un); + self.send(bl.toArray()); + }; + + this.socket.onmessage = function (msg) { + + //console.log(msg); + + this.networkBuffer.writeAll(msg.data); + + self.lastAction = new Date(); + + while (this.networkBuffer.available > 0 && !this.networkBuffer.protected) + self.receive(this.networkBuffer); + + + }; + } + + + receive(data) { + var msg = data.read(); + var offset = 0; + var ends = msg.length; + var packet = this.packet; + var authPacket = this.authPacket; + + //console.log("Data"); + + while (offset < ends) { + + if (this.ready) { + var rt = packet.parse(msg, offset, ends); + if (rt <= 0) { + data.holdFor(msg, offset, ends - offset, -rt); + return; + } + else { + offset += rt; + + if (packet.command == IIPPacketCommand.Event) { + switch (packet.event) { + case IIPPacketEvent.ResourceReassigned: + this.IIPEventResourceReassigned(packet.resourceId, packet.newResourceId); + break; + case IIPPacketEvent.ResourceDestroyed: + this.IIPEventResourceDestroyed(packet.resourceId); + break; + case IIPPacketEvent.PropertyUpdated: + this.IIPEventPropertyUpdated(packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketEvent.EventOccured: + this.IIPEventEventOccured(packet.resourceId, packet.methodIndex, packet.content); + break; + } + } + else if (packet.command == IIPPacketCommand.Request) { + switch (packet.action) { + case IIPPacketAction.AttachResource: + this.IIPRequestAttachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ReattachResource: + this.IIPRequestReattachResource(packet.callbackId, packet.resourceId, packet.resourceAge); + break; + case IIPPacketAction.DetachResource: + this.IIPRequestDetachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.CreateResource: + this.IIPRequestCreateResource(packet.callbackId, packet.className); + break; + case IIPPacketAction.DeleteResource: + this.IIPRequestDeleteResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.TemplateFromClassName: + this.IIPRequestTemplateFromClassName(packet.callbackId, packet.className); + break; + case IIPPacketAction.TemplateFromClassId: + this.IIPRequestTemplateFromClassId(packet.callbackId, packet.classId); + break; + case IIPPacketAction.TemplateFromResourceLink: + this.IIPRequestTemplateFromResourceLink(packet.callbackId, packet.resourceLink); + break; + case IIPPacketAction.TemplateFromResourceId: + this.IIPRequestTemplateFromResourceId(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ResourceIdFromResourceLink: + this.IIPRequestResourceIdFromResourceLink(packet.callbackId, packet.resourceLink); + break; + case IIPPacketAction.InvokeFunction: + this.IIPRequestInvokeFunction(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketAction.GetProperty: + this.IIPRequestGetProperty(packet.callbackId, packet.resourceId, packet.methodIndex); + break; + case IIPPacketAction.GetPropertyIfModified: + this.IIPRequestGetPropertyIfModifiedSince(packet.callbackId, packet.resourceId, packet.methodIndex, packet.resourceAge); + break; + case IIPPacketAction.SetProperty: + this.IIPRequestSetProperty(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); + break; + } + } + else if (packet.command == IIPPacketCommand.Reply) { + switch (packet.action) { + case IIPPacketAction.AttachResource: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceAge, packet.resourceLink, packet.content); + break; + case IIPPacketAction.ReattachResource: + this.IIPReply(packet.callbackId, packet.resourceAge, packet.content); + break; + case IIPPacketAction.DetachResource: + this.IIPReply(packet.callbackId); + break; + case IIPPacketAction.CreateResource: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceId); + break; + case IIPPacketAction.DeleteResource: + this.IIPReply(packet.callbackId); + break; + case IIPPacketAction.TemplateFromClassName: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromClassId: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromResourceLink: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromResourceId: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.ResourceIdFromResourceLink: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceId, packet.resourceAge); + break; + case IIPPacketAction.InvokeFunction: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.GetProperty: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.GetPropertyIfModified: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.SetProperty: + this.IIPReply(packet.callbackId); + break; + } + + } + + } + } + + else { + var rt = authPacket.parse(msg, offset, ends); + + + if (rt <= 0) { + data.holdAllFor(msg, ends - rt); + return; + } + else { + offset += rt; + + if (this.hostType == AuthenticationType.Host) { + if (authPacket.command == IIPAuthPacketCommand.Declare) { + if (authPacket.remoteMethod == IIPAuthPacketMethod.credentials + && authPacket.localMethod == IIPAuthPacketMethod.None) { + this.remoteUsername = authPacket.remoteUsername; + this.remoteNonce = authPacket.remoteNonce; + this.domain = authPacket.domain; + this.sendParams().addUint8(0xa0).addUint8Array(this.localNonce).done(); + } + } + else if (authPacket.command == IIPAuthPacketCommand.Action) { + if (authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + var remoteHash = authPacket.hash; + + this.server.membership.getPassword(this.remoteUsername, this.domain).then(function (pw) { + if (pw != null) { + + var hash = new DC(sha256.arrayBuffer(BL().addString(pw).addUint8Array(remoteNonce).addUint8Array(this.localNonce).toArray())); + + + if (hash.sequenceEqual(remoteHash)) { + // send our hash + var localHash = new DC(sha256.arrayBuffer((new BinaryList()).addUint8Array(this.localNonce).addUint8Array(remoteNonce).addUint8Array(pw).toArray())); + this.sendParams().addUint8(0).addUint8Array(localHash).done(); + + this.readyToEstablish = true; + } + else { + // incorrect password + this.sendParams().addUint8(0xc0).addInt32(1).addUint16(5).addString("Error").done(); + } + } + }); + } + else if (authPacket.action == IIPAuthPacketAction.NewConnection) { + if (readyToEstablish) { + this.sessionId = new DC(32); + window.crypto.getRandomValues(this.sessionId); + + this.sendParams().addUint8(0x28).addUint8Array(this.sessionId).done(); + this.ready = true; + this._emit("ready", this); + } + } + } + } + else if (this.hostType == AuthenticationType.Client) { + if (authPacket.command == IIPAuthPacketCommand.Acknowledge) { + this.remoteNonce = authPacket.remoteNonce; + + // send our hash + + var localHash = new DC(sha256.arrayBuffer(BL().addUint8Array(this.localPassword) + .addUint8Array(this.localNonce) + .addUint8Array(this.remoteNonce).toArray())); + this.sendParams().addUint8(0).addUint8Array(localHash).done(); + } + else if (authPacket.command == IIPAuthPacketCommand.Action) { + if (authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + // check if the server knows my password + var remoteHash = new DC(sha256.arrayBuffer(BL().addUint8Array(this.remoteNonce) + .addUint8Array(this.localNonce) + .addUint8Array(this.localPassword).toArray() + )); + + if (remoteHash.sequenceEqual(authPacket.hash)) { + // send establish request + this.sendParams().addUint8(0x20).addUint16(0).done(); + } + else { + this.sendParams().addUint8(0xc0).addUint32(1).addUint16(5).addString("Error").done(); + } + } + else if (authPacket.action == IIPAuthPacketAction.ConnectionEstablished) { + this.sessionId = authPacket.sessionId; + this.ready = true; + this._emit("ready", this); + } + } + else if (authPacket.command == IIPAuthPacketCommand.Error) + { + this._emit("error", this, authPacket.errorCode, authPacket.errorMessage); + this.close(); + } + } + } + } + } + + } + + close() + { + this.socket.close(); + } + + trigger(trigger) { + return true; + } + + put(resource) { + this.resources[parseInt(resource.instance.name)] = resource; + return true; + } + + + // Protocol Implementation + + sendRequest(action, binaryList) { + var reply = new AsyncReply(); + this.callbackCounter++; + this.sendParams().addUint8(0x40 | action).addUint32(this.callbackCounter).addRange(binaryList).done(); + this.requests[this.callbackCounter] = reply; + return reply; + } + + IIPReply(callbackId) { + var results = Array.prototype.slice.call(arguments, 1); + var req = this.requests[callbackId]; + delete this.requests[callbackId]; + req.trigger(results); + } + + IIPEventResourceReassigned(resourceId, newResourceId) { + + } + + IIPEventResourceDestroyed(resourceId) { + if (this.resources[resourceId]) { + var r = this.resources[resourceId]; + delete this.resources[resourceId]; + r.destroy(); + } + } + + IIPEventPropertyUpdated(resourceId, index, content) { + if (this.resources[resourceId]) { + // push to the queue to gaurantee serialization + var reply = new AsyncReply(); + this.queue.add(reply); + + var r = this.resources[resourceId]; + Codec.parse(content, 0, this).then(function (args) { + var pt = r._p.template.getPropertyTemplateByIndex(index); + if (pt != null) { + reply.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Propery, args, index)); + } + else { // ft found, fi not found, this should never happen + this.queue.remove(reply); + } + }); + } + } + + + IIPEventEventOccured(resourceId, index, content) { + if (this.resources[resourceId]) { + // push to the queue to guarantee serialization + var reply = new AsyncReply(); + var r = this.resources[resourceId]; + + this.queue.add(reply); + + Codec.parseVarArray(content, 0, content.length, this).then(function (args) { + var et = r._p.template.getEventTemplateByIndex(index); + if (et != null) { + reply.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Event, args, index)); + } + else { // ft found, fi not found, this should never happen + this.queue.remove(reply); + } + }); + } + } + + IIPRequestAttachResource(callback, resourceId) { + + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + r.instance.on("ResourceEventOccured", this.instance_eventOccured); + r.instance.on("ResourceModified", this.instance_propertyModified); + r.instance.on("ResourceDestroyed", this.instance_resourceDestroyed); + // reply ok + + var link = DC.stringToBytes(r.instance.link); + + sl.addUint8(0x80) + .addUint32(callback) + .addUint8Array(r.instance.template.classId.value) + .addUint32(r.instance.age) + .addUint16(link.length) + .addUint8Array(link) + .addUint8Array(Codec.composeVarArray(r.instance.serialize(), this, true)) + .done(); + } + else { + // reply failed + //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); + } + }); + } + + IIPRequestReattachResource(callback, resourceId, resourceAge) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (res != null) { + r.instance.on("ResourceEventOccured", this.instance_eventOccured); + r.instance.on("ResourceModified", this.instance_propertyModified); + r.instance.on("ResourceDestroyed", this.instance_resourceDestroyed); + // reply ok + sl.addUint8(0x81) + .addUint32(callback) + .addUint32(r.instance.age) + .addUint8Array(Codec.composeVarArray(r.instance.serialize(), this, true)) + .done(); + } + else { + // reply failed + } + }); + } + + IIPRequestDetachResource(callback, resourceId) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + r.instance.off("ResourceEventOccured", this.instance_eventOccured); + r.instance.off("ResourceModified", this.instance_propertyModified); + r.instance.off("ResourceDestroyed", this.instance_resourceDestroyed); + + // reply ok + sl.addUint8(0x82).addUint32(callback).done(); + } + else { + // reply failed + } + }); + } + + IIPRequestCreateResource(callback, className) { + // not implemented + } + + IIPRequestDeleteResource(callback, resourceId) { + // not implemented + } + + IIPRequestTemplateFromClassName(callback, className) { + var sl = this.sendParams(); + + Warehouse.getTemplateByClassName(className).then(function (t) { + if (t != null) + sl.addUint8(0x88).addUint32(callback).addUint8Array(t.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromClassId(callback, classId) { + var sl = this.sendParams(); + + Warehouse.getTemplateByClassId(classId).then(function (t) { + if (t != null) + sl.addUint8(0x89) + .addUint32(callback) + .addUint32(t.content.length) + .addUint8Array(t.content) + .done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromResourceLink(callback, resourceLink) { + var sl = this.sendParams(); + + Warehouse.getTemplate(resourceLink).then(function (t) { + if (t != null) + sl.addUint8(0x8a).addUint32(callback).addUint8Array(t.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromResourceId(callback, resourceId) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) + sl.addUint8(0x8b).addUint32(callback).addUint8Array(r.instance.template.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestResourceIdFromResourceLink(callback, resourceLink) { + + var sl = this.sendParams(); + + Warehouse.get(resourceLink).then(function (r) { + if (r != null) + sl.addUint8(0x8c) + .addUint32(callback) + .addUint8Array(r.instance.template.classId.value) + .addUint32(r.instance.id) + .addUint32(r.instance.age).done(); + else { + // reply failed + } + }); + } + + IIPRequestInvokeFunction(callback, resourceId, index, content) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + Codec.parseVarArray(content, 0, content.length, sl.connection).then(function (args) { + var ft = r.instance.template.getFunctionTemplateByIndex(index); + if (ft != null) { + if (r instanceof DistributedResource) { + var rt = r._invoke(index, args); + if (rt != null) { + rt.then(function (res) { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(res, sl.connection)).done(); + }); + } + else { + // function not found on a distributed object + } + } + else { + + var fi = r[ft.name]; + if (fi instanceof Function) { + args.push(sl.connection); + + var rt = fi.apply(r, args); + + + if (rt instanceof AsyncReply) { + rt.then(function (res) { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(res, sl.connection)).done(); + }); + } + else { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(rt, sl.connection)).done(); + } + } + else { + // ft found, fi not found, this should never happen + } + } + } + else { + // no function at this index + } + }); + } + else { + // no resource with this id + } + }); + } + + IIPRequestGetProperty(callback, resourceId, index) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + var pt = r.instance.template.getFunctionTemplateByIndex(index); + if (pt != null) { + if (r instanceof DistributedResource) { + sl.addUint8(0x91).addUint32(callback).addUint8Array(Codec.compose(r._get(pt.index), sl.connection)).done(); + } + else { + var pv = r[pt.name]; + sl.addUint8(0x91).addUint32(callback).addUint8Array(Codec.compose(pv, sl.connection)).done(); + } + } + else { + // pt not found + } + } + else { + // resource not found + } + }); + } + + IIPRequestGetPropertyIfModifiedSince(callback, resourceId, index, age) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + var pt = r.instance.template.getFunctionTemplateByIndex(index); + if (pt != null) { + if (r.instance.getAge(index) > age) { + var pv = r[pt.name]; + sl.addUint8(0x92).addUint32(callback).addUint8Array(Codec.compose(pv, sl.connection)).done(); + } + else { + sl.addUint8(0x92).addUint32(callback).addUint8(DataType.NotModified).done(); + } + } + else { + // pt not found + } + } + else { + // resource not found + } + }); + } + + IIPRequestSetProperty(callback, resourceId, index, content) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + + + var pt = r.instance.template.getPropertyTemplateByIndex(index); + if (pt != null) { + Codec.parse(content, 0, this).then(function (value) { + if (r instanceof DistributedResource) { + // propagation + r._set(index, value).then(function (x) { + sl.addUint8(0x93).addUint32(callback).done(); + }); + } + else { + r[pt.name] = value; + sl.addUint8(0x93).addUint32(callback).done(); + } + + }); + } + else { + // property not found + } + } + else { + // resource not found + } + }); + } + + + getTemplate(classId) { + if (this.templates[classId]) + return new AsyncReply(this.templates[classId]); + else if (this.templateRequests[classId]) + return this.templateRequests[classId]; + + var reply = new AsyncReply(); + this.templateRequests[classId] = reply; + + var self = this; + + this.sendRequest(IIPPacketAction.TemplateFromClassId, BL().addUint8Array(classId.value)).then(function (rt) { + delete self.templateRequests[classId]; + self.templates[rt[0].classId] = rt[0]; + reply.trigger(rt[0]); + }); + + return reply; + } + +// IStore interface + get(path) { + if (this.pathRequests[path]) + return this.pathRequests[path]; + + var reply = new AsyncReply(); + this.pathRequests[path] = reply; + + var bl = new BinaryList(); + bl.addString(path); + bl.addUint16(bl.length, 0); + + var self = this; + + this.sendRequest(IIPPacketAction.ResourceIdFromResourceLink, bl).then(function (rt) { + delete self.pathRequests[path]; + + self.fetch(rt[1]).then(function (r) { + reply.trigger(r); + }); + }); + + + return reply; + } + + retrieve(iid) { + for (var r in this.resources) + if (this.resources[r].instance.id == iid) + return new AsyncReply(r); + return new AsyncReply(null); + } + +// Get a resource from the other end + fetch(id) { + if (this.resourceRequests[id] && this.resources[id]) { + // dig for dead locks + return this.resourceRequests[id]; + } + else if (this.resourceRequests[id]) + return this.resourceRequests[id]; + else if (this.resources[id]) + return new AsyncReply(this.resources[id]); + + var reply = new AsyncReply(); + + var self = this; + + this.sendRequest(IIPPacketAction.AttachResource, BL().addUint32(id)).then(function (rt) { + self.getTemplate(rt[0]).then(function (tmp) { + + var dr = new DistributedResource(self, tmp, id, rt[1], rt[2]); + Warehouse.put(dr, id.toString(), self); + + Codec.parseVarArray(rt[3], 0, rt[3].length, self).then(function (ar) { + dr._attached(ar); + delete self.resourceRequests[id]; + reply.trigger(dr); + }); + }); + }); + + return reply; + } + + instance_resourceDestroyed(resource) { + // compose the packet + this.sendParams().addUint8(0x1).addUint32(resource.instance.id).done(); + } + + instance_propertyModified(resource, name, newValue, oldValue) { + var pt = resource.instance.template.getPropertyTemplateByName(name); + + if (pt == null) + return; + + // compose the packet + if (newValue instanceof Function) + sendParams().addUint8(0x10) + .addUint32(resource.instance.id) + .addUint8(pt.index) + .addUint8Array(Codec.compose(newValue(this), this)) + .done(); + else + sendParams().addUint8(0x10) + .addUint32(resource.instance.id) + .addUint8(pt.index) + .addUint8Array(Codec.compose(newValue, this)) + .done(); + } + + instance_eventOccured(resource, name, receivers, args) { + var et = resource.instance.template.getEventTemplateByName(name); + + if (et == null) + return; + + if (receivers != null) + if (receivers.indexOf(this.remoteUsername) < 0) + return; + + var clientArgs = [];//new object[args.Length]; + for (var i = 0; i < args.Length; i++) + if (args[i] instanceof Function) + clientArgs[i] = args[i](this); + else + clientArgs[i] = args[i]; + + + // compose the packet + sendParams().addUint8(0x11) + .addUint32(resource.instance.id) + .addUint8(et.index) + .addUint8Array(Codec.composeVarArray(args, this, true)) + .done(); + + } + +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + + +class DistributedResource extends IResource +{ + destroy() + { + this.destroyed = true; + this._emit("destroy"); + } + + + + constructor(connection, template, instanceId, age) + { + super(); + + this._p = { + isAttached: false, + connection: connection, + instanceId: instanceId, + age: age, + template: template + }; + } + + _attached(properties) + { + + if (this._isAttached) + return false; + else + { + this._p.properties = properties; + this._p.ages = new Uint32Array(properties.length); + //this.events = [];//new [this.template.events.length]; + this._p.isAttached = true; + + var self = this; + + var makeFunc = function(index) + { + return function () { + return self._invoke(index, arguments); + }; + }; + + var makeGetter = function(index) + { + return function () { + return self._get(index); + }; + }; + + var makeSetter = function(index) + { + return function (value) { + self._set(index, value); + }; + }; + + for(var i = 0; i < this._p.template.functions.length; i++) + { + var ft = this._p.template.functions[i]; + this[ft.name] = makeFunc(ft.index); + } + + for(var i = 0; i < this._p.template.properties.length; i++) + { + var pt = this._p.template.properties[i]; + + Object.defineProperty(this, pt.name, { + get: makeGetter(pt.index), + set: makeSetter(pt.index), + enumerable: true, + configurable: true + }); + + } + } + return true; + } + + _emitEventByIndex(index, args) + { + var et = this._p.template.getEventTemplateByIndex(index); + this._emit(et.name, args); + this.instance.emitResourceEvent(et.name, null, args); + } + + _invoke(index, args) { + if (this.destroyed) + throw new Exception("Trying to access destroyed object"); + + if (index >= this._p.template.functions.length) + throw new Exception("Function index is incorrect"); + + var reply = new AsyncReply(); + + var parameters = Codec.composeVarArray(args, this._p.connection, true); + + var self = this; + + this._p.connection.sendRequest(IIPPacketAction.InvokeFunction, + BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)) + .then(function (res) { + Codec.parse(res[0], 0, self._p.connection).then(function (rt) { + reply.trigger(rt); + }); + }); + + + return reply; + + } + + + _get(index) + { + if (index >= this._p.properties.length) + return null; + return this._p.properties[index]; + } + + + + _updatePropertyByIndex(index, value) + { + var pt = this._p.template.getPropertyTemplateByIndex(index); + this._p.properties[index] = value; + this.instance.modified(pt.name, value); + } + + _set(index, value) + { + if (index >= this._p.properties.length) + return null; + + var reply = new AsyncReply(); + + var parameters = Codec.compose(value, this._p.connection); + var self = this; + + this._p.connection.sendRequest(IIPPacketAction.SetProperty, + BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)) + .then(function(res) + { + // not really needed, server will always send property modified, this only happens if the programmer forgot to emit in property setter + //Update(index, value); + reply.trigger(null); + // nothing to do here + }); + + return reply; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var DistributedResourceQueueItemType = + { + Propery: 0, + Event: 1 + }; + +class DistributedResourceQueueItem { + constructor(resource, type, value, index) { + this.resource = resource; + this.index = index; + this.type = type; + this.value = value; + } +} + + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 24/08/2017. + */ + +class EventTemplate extends MemberTemplate +{ + + constructor() + { + super(); + this.type = MemberType.Event; + } + + compose() + { + var rt = new BinaryList(); + + var name = super.compose(); + if (this.expansion != null) { + var exp = DC.stringToBytes(this.expansion); + return rt.addUint8(0x50).addUint32(exp.length).addUint8Array(exp).addUint8(name.length).addUint8Array(name).toArray(); + } + else + return rt.addUint8(0x40).addUint32(name.length).addUint8Array(name).toArray(); + } + +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 27/08/2017. + */ + +class FunctionTemplate extends MemberTemplate { + compose() { + var name = super.compose(); + var rt = new BinaryList(); + + if (this.expansion != null) { + var exp = DC.stringToBytes(this.expansion); + + return rt.addUint8(0x10 | (IsVoid ? 0x8 : 0x0)) + .addUint32(exp.length).addUint8Array(exp) + .addUint8(name.length).addUint8Array(name).toArray(); + } + else + return rt.addUint8(IsVoid ? 0x8 : 0x0).addUint8(name.length).addUint8Array(name).toArray(); + } + + + constructor() { + super(); + this.type = MemberType.Function; + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 02/09/2017. + */ +class Guid +{ + constructor(dc) + { + this.value = dc; + } + + valueOf() + { + return this.value.getHex(0, 16); + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var IIPAuthPacketCommand = +{ + Action: 0, + Declare: 1, + Acknowledge: 2, + Error: 3 +}; + +var IIPAuthPacketAction = +{ + // Authenticate + AuthenticateHash: 0, + NewConnection: 0x20, + ResumeConnection: 0x21, + ConnectionEstablished: 0x28 +}; + + +var IIPAuthPacketMethod = +{ + None: 0, + Certificate: 1, + Credentials: 2, + Token: 3 +}; + +class IIPAuthPacket +{ + constructor() + { + this.command = 0; + this.action = 0; + this.errorCode = 0; + this.errorMessage = ""; + this.localMethod = 0; + this.sourceInfo = ""; + this.hash = ""; + this.sessionId = ""; + this.remoteMethod = 0; + this.domain = ""; + this.CertificateId = 0; + this.localUsername = ""; + this.remoteUsername = ""; + this.localPassword = ""; + this.remotePassword = ""; + this.localToken = []; + this.reemoteToken = []; + this.asymetricEncryptionKey = []; + this.localNonce = []; + this.remoteNonce = []; + this.dataLengthNeeded = 0; + } + + notEnough(offset, ends, needed) + { + if (offset + needed > ends) + { + this.dataLengthNeeded = needed - (ends - offset); + return true; + } + else + return false; + } + + parse(data, offset, ends) + { + var oOffset = offset; + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.command = data.getUint8(offset) >> 6; + + if (this.command == IIPAuthPacketCommand.Action) + { + this.action = data[offset++] & 0x3f; + + if (this.action == IIPAuthPacketAction.AuthenticateHash) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.hash = data.getUint8Array(offset, 32); + + offset += 32; + } + else if (this.action == IIPAuthPacketAction.NewConnection) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var length = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, length)) + return -this.dataLengthNeeded; + + this.sourceInfo = data.clip(offset, length); + + offset += 32; + } + else if (this.action == IIPAuthPacketAction.ResumeConnection + || this.action == IIPAuthPacketAction.ConnectionEstablished) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.sessionId = data.clip(offset, 32); + + offset += 32; + } + } + else if (this.command == IIPAuthPacketCommand.Declare) + { + this.remoteMethod = ((data.getUint8(offset) >> 4) & 0x3); + this.localMethod = ((data.getUint8(offset) >> 2) & 0x3); + + var encrypt = ((data.getUint8(offset++) & 0x2) == 0x2); + + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var domainLength = data.getUint8(offset++); + if (this.notEnough(offset, ends, domainLength)) + return -this.dataLengthNeeded; + + this.domain = data.getString(offset, domainLength); + + offset += domainLength; + + + if (this.remoteMethod == IIPAuthPacketMethod.Credentials) + { + if (this.localMethod == IIPAuthPacketMethod.None) + { + if (this.notEnough(offset, ends, 33)) + return -this.dataLengthNeeded; + + this.remoteNonce = data.clip(offset, 32); + + offset += 32; + + var length = data.getUint8(offset++); + + if (this.notEnough(offset, ends, length)) + return -this.dataLengthNeeded; + + this.remoteUsername = data.getString(offset, length); + + + offset += length; + } + } + + if (encrypt) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var keyLength = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, keyLength)) + return -this.dataLengthNeeded; + + this.asymetricEncryptionKey = data.clip(offset, keyLength); + + offset += keyLength; + } + } + else if (this.command == IIPAuthPacketCommand.Acknowledge) + { + this.remoteMethod = (data.getUint8(offset) >> 4) & 0x3; + this.localMethod = (data.getUint8(offset) >> 2) & 0x3; + var encrypt = ((data.getUint8(offset++) & 0x2) == 0x2); + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + + if (this.remoteMethod == IIPAuthPacketMethod.Credentials) + { + if (this.localMethod == IIPAuthPacketMethod.None) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.remoteNonce = data.clip(offset, 32); + + offset += 32; + + } + } + + if (encrypt) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var keyLength = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, keyLength)) + return -this.dataLengthNeeded; + + this.asymetricEncryptionKey = data.clip(offset, keyLength); + + offset += keyLength; + } + } + else if (this.command == IIPAuthPacketCommand.Error) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + offset++; + this.errorCode = data.getUint8(offset++); + + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.errorMessage = data.getString(offset, cl); + offset += cl; + + } + + + return offset - oOffset; + + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + + +var IIPPacketCommand = +{ + Event: 0, + Request: 1, + Reply: 2, + Error: 3 +}; + +var IIPPacketEvent = +{ + // Event Manage + ResourceReassigned : 0, + ResourceDestroyed: 1, + + // Event Invoke + PropertyUpdated : 0x10, + EventOccured: 0x11 +}; + +var IIPPacketAction = +{ + // Request Manage + AttachResource: 0, + ReattachResource: 1, + DetachResource: 2, + CreateResource: 3, + DeleteResource: 4, + + // Request Inquire + TemplateFromClassName: 0x8, + TemplateFromClassId: 0x9, + TemplateFromResourceLink: 0xA, + TemplateFromResourceId: 0xB, + ResourceIdFromResourceLink: 0xC, + + // Request Invoke + InvokeFunction: 0x10, + GetProperty: 0x11, + GetPropertyIfModified: 0x12, + SetProperty: 0x13 +}; + + + + + +class IIPPacket +{ + constructor() + { + this.command = 0; + this.action = 0; + this.event = 0; + this.resourceId = 0; + this.newResourceId = 0; + this.resourceAge = 0; + this.content = []; + this.errorCode = 0; + this.errorMessage = ""; + this.className = ""; + this.resourceLink = ""; + this.classId = ""; + this.methodIndex = ""; + this.methodName = ""; + this.callbackId = 0; + this.dataLengthNeeded = 0; + } + + notEnough(offset, ends, needed) + { + if (offset + needed > ends) + { + this.dataLengthNeeded = needed - (ends - offset); + return true; + } + else + return false; + } + + parse(data, offset, ends) + { + var oOffset = offset; + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.command = (data.getUint8(offset) >> 6); + + if (this.command == IIPPacketCommand.Event) + { + this.event = (data.getUint8(offset++) & 0x3f); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else + { + this.action = (data.getUint8(offset++) & 0x3f); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.callbackId = data.getUint32(offset); + offset += 4; + } + + if (this.command == IIPPacketCommand.Event) + { + if (this.event == IIPPacketEvent.ResourceReassigned) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.newResourceId = data.getUint32( offset); + offset += 4; + + } + else if (this.event == IIPPacketEvent.ResourceDestroyed) + { + // nothing to parse + } + else if (this.event == IIPPacketEvent.PropertyUpdated) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + this.methodIndex = data[offset++]; + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 1, size + 1); + offset += size; + } + } + else if (this.event == IIPPacketEvent.EventOccured) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + this.methodIndex = data.getUint8(offset++); + + var cl = data.getUint32(offset); + offset += 4; + + this.content = data.clip(offset, cl); + offset += cl; + } + } + else if (this.command == IIPPacketCommand.Request) + { + if (this.action == IIPPacketAction.AttachResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.ReattachResource) + { + if (this.notEnough(offset, ends, 8)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.resourceAge = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.DetachResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.CreateResource) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var cl = data.getUint8(offset++); + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.className = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.DeleteResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.TemplateFromClassName) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var cl = data.getUint8(offset++); + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.className = data.getString(offset, cl); + offset += cl; + + } + else if (this.action == IIPPacketAction.TemplateFromClassId) + { + if (this.notEnough(offset, ends, 16)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + } + else if (this.action == IIPPacketAction.TemplateFromResourceLink) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.TemplateFromResourceId) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.ResourceIdFromResourceLink) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.InvokeFunction) + { + if (this.notEnough(offset, ends, 9)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data.getUint8(offset++); + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + + } + else if (this.action == IIPPacketAction.GetProperty) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data.getUint8(offset++); + + } + else if (this.action == IIPPacketAction.GetPropertyIfModified) + { + if (this.notEnough(offset, ends, 9)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data[offset++]; + + this.resourceAge = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.SetProperty) + { + if (this.notEnough(offset, ends, 6)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data[offset++]; + + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset-5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset-1, size + 1); + offset += size; + } + } + } + else if (this.command == IIPPacketCommand.Reply) + { + if (this.action == IIPPacketAction.AttachResource + || this.action == IIPPacketAction.ReattachResource) + { + if (this.notEnough(offset, ends, 26)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + + this.resourceAge = data.getUint32(offset); + offset += 4; + + var cl = data.getUint16(offset); + offset+=2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.DetachResource) + { + // nothing to do + } + else if (this.action == IIPPacketAction.CreateResource) + { + if (this.notEnough(offset, ends, 20)) + return -this.dataLengthNeeded; + + this.classId = data.GetGuid(offset); + offset += 16; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.DetachResource) + { + // nothing to do + } + else if (this.action == IIPPacketAction.TemplateFromClassName + || this.action == IIPPacketAction.TemplateFromClassId + || this.action == IIPPacketAction.TemplateFromResourceLink + || this.action == IIPPacketAction.TemplateFromResourceId) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.ResourceIdFromResourceLink) + { + if (this.notEnough(offset, ends, 24)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.resourceAge = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.InvokeFunction + || this.action == IIPPacketAction.GetProperty + || this.action == IIPPacketAction.GetPropertyIfModified) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 1, size + 1); + offset += size; + } + } + else if (this.action == IIPPacketAction.SetProperty) + { + // nothing to do + } + } + else if (this.command == IIPPacketCommand.Error) + { + // Error + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.callbackId = data.getUint32(offset); + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.errorCode = data.getUint8(offset++); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.errorMessage = data.getString(offset, cl); + offset += cl; + } + + return offset - oOffset; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 29/08/2017. + */ +class Instance extends IEventHandler +{ + + getAge(index) + { + if (index < this.ages.Count) + return this.ages[index]; + else + return 0; + } + + + deserialize(properties) + { + for(var i = 0; i < this.template.properties.length; i++) + this.resource[this.template.properties[i].name] = properties[i]; + return true; + } + + serialize() + { + var props = []; + + for (var i = 0; i < this.template.properties.length; i++) + props.push(this.resource[this.template.properties[i].name]); + + return props; + } + + isStorable() + { + return resource instanceof Storable; + } + + + modified(propertyName = null, newValue = null, oldValue = null) + { + if (propertyName == null) + propertyName = modified.caller.name; + + if (newValue == null) + { + var val = {}; + if (this.getPropertyValue(propertyName, val)) + super._emit("ResourceModified", this.resource, propertyName, val.value, oldValue); + } + else + super._emit("ResourceModified", this.resource, propertyName, newValue, oldValue); + } + + emitResourceEvent(name, receivers, args) + { + super._emit("ResourceEventOccured", this.resource, name, receivers, args); + } + + getPropertyValue(name, resultObject) + { + for (var i = 0; i < this.template.properties.length; i++) + if (this.template.properties[i].name == name) + { + resultObject.value = this.resource[name]; + return true; + } + + return false; + } + + + + constructor(id, name, resource, store) + { + super(); + + this.store = store; + this.resource = resource; + this.id = id; + this.name = name; + + this.children = new AutoList(); + this.parents = new AutoList(); + + var self = this; + + this.children.on("add", function(value){ + value.instance.parents.add(self.resource); + }); + + this.children.on("remove", function(value){ + value.instance.parents.remove(self.resource); + }); + + + this.resource.on("Destroy", function(sender){ + self._emit("ResourceDestroyed", sender); + }); + + this.template = Warehouse.getTemplateByType(this.resource.constructor); + + // set ages + this.ages = new Uint32Array(this.template.properties.length); + + + // connect events + var makeHandler = function(name, receivers, args) + { + return new function(receivers, args) + { + self.emitResourceEvent(name, receivers, args); + }; + }; + + for (var i = 0; i < this.template.events.length; i++) + this.resource.on(this.template.events[i].name, makeHandler(this.template.events[i].name)); + + } + +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 01/09/2017. + */ + +class NetworkBuffer { + constructor() { + this.neededDataLength = 0; + this.data = new DC(0); + } + + get protected() { + return this.neededDataLength > this.data.length; + } + + get available() { + + return this.data.length; + } + + holdAllForNextWrite(src) { + this.holdFor(src, src.length + 1); + } + + holdForNextWrite(src, offset, size) { + this.holdFor(src, offset, size, size + 1); + } + + + holdFor(src, offset, size, needed) { + if (size >= needed) + throw new Exception("Size >= Needed !"); + + this.data = DC.combine(src, offset, size, this.data, 0, this.data.length); + this.neededDataLength = needed; + } + + holdAllFor(src, needed) { + this.holdFor(src, 0, src.length, needed); + } + + protect(data, offset, needed) { + var dataLength = data.length - offset; + + // protection + if (dataLength < needed) { + this.holdFor(data, offset, dataLength, needed); + return true; + } + else + return false; + } + + writeAll(src) { + this.write(src, 0, src.length ? src.length : src.byteLength); + } + + write(src, offset, length) { + this.data = this.data.append(src, offset, length); + } + + get canRead() { + if (this.data.length == 0) + return false; + else if (this.data.length < this.neededDataLength) + return false; + return true; + } + + read() { + if (this.data.length == 0) + return null; + + var rt = null; + + if (this.neededDataLength == 0) { + rt = this.data; + this.data = new DC(0); + } + else { + if (this.data.length >= this.neededDataLength) { + rt = this.data; + this.data = new DC(0); + this.neededDataLength = 0; + return rt; + } + else { + return null; + } + } + + return rt; + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class NotModified +{ + +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 27/08/2017. + */ + +var PropertyPermission = { + Read: 1, + Write: 2, + ReadWrite: 3 +}; + + +class PropertyTemplate extends MemberTemplate +{ + + constructor() + { + super(); + this.type = MemberType.Property; + } + + compose() + { + var name = super.compose(); + var rt = new BinaryList(); + + if (this.writeExpansion != null && this.readExpansion != null) + { + var rexp = DC.stringToBytes(this.readExpansion); + var wexp = DC.stringToBytes(this.writeExpansion); + return rt.addUint8(0x38 | this.permission) + .addUint32(wexp.length) + .addUint8Array(wexp) + .addUint32(rexp.length) + .addUint8Array(rexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else if (this.writeExpansion != null) + { + var wexp = DC.stringToBytes(this.writeExpansion); + return rt.addUint8(0x30 | this.permission) + .addUint32(wexp.length) + .addUint8Array(wexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else if (this.readExpansion != null) + { + var rexp = DC.stringToBytes(this.readExpansion); + return rt.addUint8(0x28 | this.permission) + .addUint32(rexp.length) + .addUint8Array(rexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else + return rt.addUint8(0x20 | this.permission) + .addUint32(name.length) + .addUint8Array(name).toArray(); + } +} + +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +class ResourceTemplate { + + getMemberTemplate(member) { + if (member instanceof MethodInfo) + return this.getFunctionTemplate(member.name); + else if (member instanceof EventInfo) + return this.getEventTemplate(member.name); + else if (member instanceof PropertyInfo) + return this.getPropertyTemplate(member.name); + else + return null; + } + + getEventTemplateByName(eventName) { + for (var i = 0; i < this.events.length; i++) + if (this.events[i].name == eventName) + return this.events[i]; + return null; + } + + getEventTemplateByIndex(index) { + for (var i = 0; i < this.events.length; i++) + if (this.events[i].index == index) + return this.events[i]; + return null; + } + + getFunctionTemplateByName(functionName) { + for (var i = 0; i < this.functions.length; i++) + if (this.functions[i].name == functionName) + return this.functions[i]; + return null; + } + + getFunctionTemplateByIndex(index) { + for (var i = 0; i < this.functions.length; i++) + if (this.functions[i].index == index) + return this.functions[i]; + return null; + } + + getPropertyTemplateByName(propertyName) { + for (var i = 0; i < this.properties.length; i++) + if (this.properties[i].name == propertyName) + return this.properties[i]; + return null; + } + + getPropertyTemplateByIndex(index) { + for (var i = 0; i < this.properties.length; i++) + if (this.properties[i].index == index) + return this.properties[i]; + return null; + } + + + /* + + template: { + properties: [ + {name: 'size', read: null, write: null} + ], + functions: [ + + ], + events: [ + + ] + } + */ + + constructor(type) { + + + this.properties = []; + this.events = []; + this.functions = []; + this.members = []; + + if (type === undefined) + return; + + var template = type.getTemplate(); + + // set guid + this.className = template.namespace + "." + type.prototype.constructor.name; + + this.classId = (new DC(sha256.arrayBuffer(this.className))).getGuid(0); + + //byte currentIndex = 0; + + for (var i = 0; i < template.properties.length; i++) { + var pt = new PropertyTemplate(); + pt.name = template.properties[i].name; + pt.index = i; + pt.readExpansion = template.properties[i].read; + pt.writeExpansion = template.properties[i].write; + this.properties.push(pt); + } + + for (var i = 0; i < template.events.length; i++) { + var et = new EventTemplate(); + et.name = template.events[i].name; + et.index = i; + et.expansion = template.events[i].expansion; + this.events.push(et); + } + + for (var i = 0; i < template.functions.length; i++) { + var ft = new FunctionTemplate(); + ft.name = template.functions[i].name; + ft.index = i; + ft.isVoid = template.functions[i].void; + ft.expansion = template.functions[i].expansion; + this.functions.push(ft); + } + + + // append signals + for (var i = 0; i < this.events.length; i++) + this.members.push(this.events[i]); + // append slots + for (var i = 0; i < this.functions.length; i++) + this.members.push(this.functions[i]); + // append properties + for (var i = 0; i < this.properties.length; i++) + this.members.push(this.properties[i]); + + // bake it binarily + var b = new BinaryList(); + var cls = DC.stringToBytes(this.className); + b.addUint8Array(this.classId.value) + .addUint8(cls.length).addUint8Array(cls).addUint32(template.version).addUint16(this.members.length); + + for (var i = 0; i < this.functions.length; i++) + b.addUint8Array(this.functions[i].compose()); + + for (var i = 0; i < this.properties.length; i++) + b.addUint8Array(this.properties[i].compose()); + + for (var i = 0; i < this.events.length; i++) + b.addUint8Array(this.events[i].compose()); + + this.content = b.toArray(); + } + + static parse(data, offset = 0, contentLength = -1) { + + if (contentLength == -1) + contentLength = data.length; + + var ends = offset + contentLength; + + var oOffset = offset; + + // start parsing... + + var od = new ResourceTemplate(); + od.content = data.clip(offset, contentLength); + + od.classId = data.getGuid(offset); + offset += 16; + od.className = data.getString(offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + od.version = data.getInt32(offset); + offset += 4; + + var methodsCount = data.getUint16(offset); + offset += 2; + + var functionIndex = 0; + var propertyIndex = 0; + var eventIndex = 0; + + for (var i = 0; i < methodsCount; i++) { + var type = data.getUint8(offset) >> 5; + + if (type == 0) // function + { + var ft = new FunctionTemplate(); + ft.index = functionIndex++; + var expansion = ((data.getUint8(offset) & 0x10) == 0x10); + ft.isVoid = ((data.getUint8(offset++) & 0x08) == 0x08); + ft.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (expansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + ft.expansion = data.getString(offset, cs); + offset += cs; + } + + od.functions.push(ft); + } + else if (type == 1) // property + { + + var pt = new PropertyTemplate(); + pt.index = propertyIndex++; + var readExpansion = ((data.getUint8(offset) & 0x8) == 0x8); + var writeExpansion = ((data.getUint8(offset) & 0x10) == 0x10); + pt.permission = ((data.getUint8(offset++) >> 1) & 0x3); + pt.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (readExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + pt.readExpansion = data.getString(offset, cs); + offset += cs; + } + + if (writeExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + pt.writeExpansion = data.getString(offset, cs); + offset += cs; + } + + od.properties.push(pt); + } + else if (type == 2) // Event + { + var et = new EventTemplate(); + et.index = eventIndex++; + var expansion = ((data.getUint8(offset++) & 0x10) == 0x10); + + et.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, (int)data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (expansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + et.expansion = data.getString(offset, cs); + offset += cs; + } + + od.events.push(et); + + } + } + + // append signals + for (var i = 0; i < od.events.length; i++) + od.members.push(od.events[i]); + // append slots + for (var i = 0; i < od.functions.length; i++) + od.members.push(od.functions[i]); + // append properties + for (var i = 0; i < od.properties.length; i++) + od.members.push(od.properties[i]); + + + return od; + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 02/09/2017. + */ + +class SendList extends BinaryList +{ + constructor(connection) + { + super(); + this.connection = connection; + } + + done() + { + this.connection.send(this.toArray()); + } +} +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var Warehouse = { + + stores: [], + resources: {}, + resourceCounter: 0, + templates: {}, + + new(type, name, store = null, parent = null) + { + var res = type(); + Warehouse.put(res, name, store, parent); + return res; + }, + +get: function(id) + { + if (Warehouse.resources[id]) + return new AsyncReply(Warehouse.resources[id]); + else + return null; + }, + + put: function(resource, name, store, parent){ + resource.instance = new Instance(Warehouse.resourceCounter++, name, resource, store); + //resource.instance.children.on("add", Warehouse._onChildrenAdd).on("remove", Warehouse._onChildrenRemove); + //resource.instance.parents.on("add", Warehouse._onParentsAdd).on("remove", Warehouse._onParentsRemove); + + if (parent) + { + parent.instance.children.add(resource); + } + else + { + if (!(resource instanceof IStore)) + store.instance.children.add(resource); + } + + if (resource instanceof IStore) + Warehouse.stores.push(resource); + else + store.put(resource); + + Warehouse.resources[resource.instance.id] = resource; + }, + + _onParentsRemove: function(value) + { + if (value.instance.children.contains(value)) + value.instance.children.remove(value); + }, + + _onParentsAdd: function(value) + { + if (!value.instance.children.contains(value)) + value.instance.children.add(value); + }, + + _onChildrenRemove: function(value) + { + if (value.instance.parents.contains(value)) + value.instance.parents.remove(value); + }, + + _onChildrenAdd: function(value) + { + if (!value.instance.parents.contains(value)) + value.instance.parents.add(value); + }, + + putTemplate: function(template) + { + if (Warehouse.templates[template.classId]) + Warehouse.templates[template.classId] = template; + }, + + getTemplateByType: function(type) + { + // loaded ? + for (var t in Warehouse.templates) + if (Warehouse.templates[t].className == typeof(type)) + return t; + + var template = new ResourceTemplate(type); + Warehouse.templates[template.classId] = template; + + return template; + }, + + getTemplateByClassId: function(classId) + { + if (Warehouse.templates[classId]) + return new AsyncReply(Warehouse.templates[classId]); + return null; + }, + + getTemplateByClassName: function(className) + { + for(var t in Warehouse.templates) + if (Warehouse.templates[t].className == className) + return new AsyncReply(t); + + return null; + } +}; diff --git a/build/esiur.js b/build/esiur.js new file mode 100644 index 0000000..a48965e --- /dev/null +++ b/build/esiur.js @@ -0,0 +1 @@ +class IEventHandler{_register(event){this._events[event]=[]}constructor(){this._events={}}_emit(event){event=event.toLowerCase();var args=Array.prototype.slice.call(arguments,1);if(this._events[event])for(var i=0;i-1&&this._events[event].splice(index,1)}else this._events[event]=[]}}!function(){"use strict";function t(t,i){i?(p[0]=p[16]=p[1]=p[2]=p[3]=p[4]=p[5]=p[6]=p[7]=p[8]=p[9]=p[10]=p[11]=p[12]=p[13]=p[14]=p[15]=0,this.blocks=p):this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],t?(this.h0=3238371032,this.h1=914150663,this.h2=812702999,this.h3=4144912697,this.h4=4290775857,this.h5=1750603025,this.h6=1694076839,this.h7=3204075428):(this.h0=1779033703,this.h1=3144134277,this.h2=1013904242,this.h3=2773480762,this.h4=1359893119,this.h5=2600822924,this.h6=528734635,this.h7=1541459225),this.block=this.start=this.bytes=0,this.finalized=this.hashed=!1,this.first=!0,this.is224=t}function i(i,r,e){var n="string"!=typeof i;if(n){if(null===i||void 0===i)throw h;i.constructor===s.ArrayBuffer&&(i=new Uint8Array(i))}o=i.length;if(n){if("number"!=typeof o||!Array.isArray(i)&&(!a||!ArrayBuffer.isView(i)))throw h}else{for(var f,u=[],o=i.length,c=0,y=0;o>y;++y)128>(f=i.charCodeAt(y))?u[c++]=f:2048>f?(u[c++]=192|f>>6,u[c++]=128|63&f):55296>f||f>=57344?(u[c++]=224|f>>12,u[c++]=128|f>>6&63,u[c++]=128|63&f):(f=65536+((1023&f)<<10|1023&i.charCodeAt(++y)),u[c++]=240|f>>18,u[c++]=128|f>>12&63,u[c++]=128|f>>6&63,u[c++]=128|63&f);i=u}i.length>64&&(i=new t(r,!0).update(i).array());for(var p=[],l=[],y=0;64>y;++y){var d=i[y]||0;p[y]=92^d,l[y]=54^d}t.call(this,r,e),this.update(l),this.oKeyPad=p,this.inner=!0,this.sharedMemory=e}var h="input is invalid type",s="object"==typeof window?window:{},r=!s.JS_SHA256_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;r&&(s=global);var e=!s.JS_SHA256_NO_COMMON_JS&&"object"==typeof module&&module.exports,n="function"==typeof define&&define.amd,a="undefined"!=typeof ArrayBuffer,o="0123456789abcdef".split(""),f=[-2147483648,8388608,32768,128],u=[24,16,8,0],c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],y=["hex","array","digest","arrayBuffer"],p=[];(s.JS_SHA256_NO_NODE_JS||!Array.isArray)&&(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)});var l=function(i,h){return function(s){return new t(h,!0).update(s)[i]()}},d=function(i){var h=l("hex",i);r&&(h=v(h,i)),h.create=function(){return new t(i)},h.update=function(t){return h.create().update(t)};for(var s=0;so;){if(this.hashed&&(this.hashed=!1,f[0]=this.block,f[16]=f[1]=f[2]=f[3]=f[4]=f[5]=f[6]=f[7]=f[8]=f[9]=f[10]=f[11]=f[12]=f[13]=f[14]=f[15]=0),i)for(n=this.start;r>o&&64>n;++o)f[n>>2]|=t[o]<o&&64>n;++o)128>(e=t.charCodeAt(o))?f[n>>2]|=e<e?(f[n>>2]|=(192|e>>6)<>2]|=(128|63&e)<e||e>=57344?(f[n>>2]|=(224|e>>12)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<>2]|=(240|e>>18)<>2]|=(128|e>>12&63)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<=64?(this.block=f[16],this.start=n-64,this.hash(),this.hashed=!0):this.start=n}return this}},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,i=this.lastByteIndex;t[16]=this.block,t[i>>2]|=f[3&i],this.block=t[16],i>=56&&(this.hashed||this.hash(),t[0]=this.block,t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[15]=this.bytes<<3,this.hash()}},t.prototype.hash=function(){var t,i,h,s,r,e,n,a,o,f,u,y=this.h0,p=this.h1,l=this.h2,d=this.h3,v=this.h4,A=this.h5,w=this.h6,b=this.h7,g=this.blocks;for(t=16;64>t;++t)r=g[t-15],i=(r>>>7|r<<25)^(r>>>18|r<<14)^r>>>3,r=g[t-2],h=(r>>>17|r<<15)^(r>>>19|r<<13)^r>>>10,g[t]=g[t-16]+i+g[t-7]+h<<0;for(u=p&l,t=0;64>t;t+=4)this.first?(this.is224?(a=300032,r=g[0]-1413257819,b=r-150054599<<0,d=r+24177077<<0):(a=704751109,r=g[0]-210244248,b=r-1521486534<<0,d=r+143694565<<0),this.first=!1):(i=(y>>>2|y<<30)^(y>>>13|y<<19)^(y>>>22|y<<10),h=(v>>>6|v<<26)^(v>>>11|v<<21)^(v>>>25|v<<7),a=y&p,s=a^y&l^u,n=v&A^~v&w,r=b+h+n+c[t]+g[t],e=i+s,b=d+r<<0,d=r+e<<0),i=(d>>>2|d<<30)^(d>>>13|d<<19)^(d>>>22|d<<10),h=(b>>>6|b<<26)^(b>>>11|b<<21)^(b>>>25|b<<7),o=d&y,s=o^d&p^a,n=b&v^~b&A,r=w+h+n+c[t+1]+g[t+1],e=i+s,w=l+r<<0,l=r+e<<0,i=(l>>>2|l<<30)^(l>>>13|l<<19)^(l>>>22|l<<10),h=(w>>>6|w<<26)^(w>>>11|w<<21)^(w>>>25|w<<7),f=l&d,s=f^l&y^o,n=w&b^~w&v,r=A+h+n+c[t+2]+g[t+2],e=i+s,A=p+r<<0,p=r+e<<0,i=(p>>>2|p<<30)^(p>>>13|p<<19)^(p>>>22|p<<10),h=(A>>>6|A<<26)^(A>>>11|A<<21)^(A>>>25|A<<7),u=p&l,s=u^p&d^f,n=A&w^~A&b,r=v+h+n+c[t+3]+g[t+3],e=i+s,v=y+r<<0,y=r+e<<0;this.h0=this.h0+y<<0,this.h1=this.h1+p<<0,this.h2=this.h2+l<<0,this.h3=this.h3+d<<0,this.h4=this.h4+v<<0,this.h5=this.h5+A<<0,this.h6=this.h6+w<<0,this.h7=this.h7+b<<0},t.prototype.hex=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,f=o[t>>28&15]+o[t>>24&15]+o[t>>20&15]+o[t>>16&15]+o[t>>12&15]+o[t>>8&15]+o[t>>4&15]+o[15&t]+o[i>>28&15]+o[i>>24&15]+o[i>>20&15]+o[i>>16&15]+o[i>>12&15]+o[i>>8&15]+o[i>>4&15]+o[15&i]+o[h>>28&15]+o[h>>24&15]+o[h>>20&15]+o[h>>16&15]+o[h>>12&15]+o[h>>8&15]+o[h>>4&15]+o[15&h]+o[s>>28&15]+o[s>>24&15]+o[s>>20&15]+o[s>>16&15]+o[s>>12&15]+o[s>>8&15]+o[s>>4&15]+o[15&s]+o[r>>28&15]+o[r>>24&15]+o[r>>20&15]+o[r>>16&15]+o[r>>12&15]+o[r>>8&15]+o[r>>4&15]+o[15&r]+o[e>>28&15]+o[e>>24&15]+o[e>>20&15]+o[e>>16&15]+o[e>>12&15]+o[e>>8&15]+o[e>>4&15]+o[15&e]+o[n>>28&15]+o[n>>24&15]+o[n>>20&15]+o[n>>16&15]+o[n>>12&15]+o[n>>8&15]+o[n>>4&15]+o[15&n];return this.is224||(f+=o[a>>28&15]+o[a>>24&15]+o[a>>20&15]+o[a>>16&15]+o[a>>12&15]+o[a>>8&15]+o[a>>4&15]+o[15&a]),f},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,o=[t>>24&255,t>>16&255,t>>8&255,255&t,i>>24&255,i>>16&255,i>>8&255,255&i,h>>24&255,h>>16&255,h>>8&255,255&h,s>>24&255,s>>16&255,s>>8&255,255&s,r>>24&255,r>>16&255,r>>8&255,255&r,e>>24&255,e>>16&255,e>>8&255,255&e,n>>24&255,n>>16&255,n>>8&255,255&n];return this.is224||o.push(a>>24&255,a>>16&255,a>>8&255,255&a),o},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(this.is224?28:32),i=new DataView(t);return i.setUint32(0,this.h0),i.setUint32(4,this.h1),i.setUint32(8,this.h2),i.setUint32(12,this.h3),i.setUint32(16,this.h4),i.setUint32(20,this.h5),i.setUint32(24,this.h6),this.is224||i.setUint32(28,this.h7),t},(i.prototype=new t).finalize=function(){if(t.prototype.finalize.call(this),this.inner){this.inner=!1;var i=this.array();t.call(this,this.is224,this.sharedMemory),this.update(this.oKeyPad),this.update(i),t.prototype.finalize.call(this)}};var b=d();b.sha256=b,b.sha224=d(!0),b.sha256.hmac=w(),b.sha224.hmac=w(!0),e?module.exports=b:(s.sha256=b.sha256,s.sha224=b.sha224,n&&define(function(){return b}))}();class IDestructible extends IEventHandler{destroy(){this._emit("destroy",this)}constructor(){super()}}class AutoList extends IEventHandler{constructor(){super(),this.list=[]}add(value){value instanceof IDestructible&&value.on("destroy",this._item_destroyed),this.list.push(value),this._emit("add",value)}set(index,value){index>=this.list.length||index<0||(value instanceof IDestructible&&value.on("destroy",this._item_destroyed),this.list[index]instanceof IDestructible&&this.list[index].off("destroy",this._item_destroyed),this.list[index]=value)}remove(value){this.removeAt(this.list.indexOf(value))}contains(value){return this.list.indexOf(value)>-1}removeAt(index){if(!(index>=this.list.length||index<0)){var item=this.list[index];item instanceof IDestructible&&item.off("destroy",this._item_destroyed),this.list.splice(index,1),this._emit("remove",item)}}_item_destroyed(sender){this.remove(sender)}}var ResourceTrigger={Loaded:0,Initialize:1,Terminate:2,Configure:3,SystemInitialized:4,SystemTerminated:5,SystemReload:6};class IResource extends IDestructible{trigger(trigger){}constructor(){super()}static getTemplate(){return{namespace:"Esiur",properties:[],functions:[],events:[]}}}class IStore extends IResource{get(path){}retrieve(iid){}put(resource){}constructor(){super()}}class Structure{getKeys(){var rt=[];for(var i in this)this[i]instanceof Function||rt.push(i);return rt}}class StructureArray extends Array{push(value){value instanceof Structure&&super.push(value)}}class ResourceArray extends Array{push(value){value instanceof IResource&&super.push(value)}}var MemberType={Function:0,Property:1,Event:2};class MemberTemplate{compose(){return DC.stringToBytes(this.name)}}class AsyncReply{then(callback){this.callbacks.push(callback),this.ready&&callback(this.result,this)}trigger(result){this.result=result,this.ready=!0;for(var i=0;i0;){var len=data[offset++];keylist.push(data.getString(offset,len)),offset+=len,typelist.push(data[offset]);rt={};bag.add(Codec.parse(data,offset,rt,connection)),contentLength-=rt.size+len+1,offset+=rt.size}else if(null==types){for(i=0;i0;){typelist.push(data[offset]);rt={};bag.add(Codec.parse(data,offset,rt,connection)),contentLength-=rt.size+1,offset+=rt.size+1}}else{for(i=0;i0;){var rt={};bag.add(Codec.parse(data,offset,rt,connection,types[i])),contentLength-=rt.size,offset+=rt.size,i++}}return bag.seal(),bag.then(function(res){for(var s=new Structure,i=0;i0;){var cs={};if(rt.add(Codec.parse(data,offset,cs,connection)),!(cs.size>0))throw new Exception("Error while parsing structured data");offset+=cs.size,contentLength-=cs.size}return rt.seal(),rt}static compose(value,connection,prependType=!0){var type=Codec.getDataType(value,connection),rt=new BinaryList;switch(type){case DataType.Void:break;case DataType.String:var st=DC.stringToBytes(value);rt.addUint32(st.length).addUint8Array(st);break;case DataType.Resource:case DataType.DistributedResource:rt.addUint32(value.instance.id);break;case DataType.Structure:rt.addUint8Array(Codec.composeStructure(value,connection,!0,!0,!0));break;case DataType.VarArray:rt.addUint8Array(Codec.composeVarArray(value,connection,!0));break;case DataType.ResourceArray:rt.addUint8Array(Codec.composeResourceArray(value,connection,!0));break;case DataType.StructureArray:rt.addUint8Array(Codec.composeStructureArray(value,connection,!0));break;default:rt.add({type:type,value:value}),DataType.isArray(type)&&rt.addUint32(rt.length,0)}return prependType&&rt.addUint8(type,0),rt.toArray()}static composeVarArray(array,connection,prependLength=!1){for(var rt=new BinaryList,i=0;i0?value>255?value>65535?value>4294967295?DataType.UInt64:DataType.UInt32:DataType.UInt16:DataType.UInt8:value<-128?value<-32768?value<-2147483648?DataType.Int64:DataType.Int32:DataType.Int16:DataType.Int8:DataType.Float64;case"string":return DataType.String;case"boolean":return DataType.Bool;case"object":return value instanceof Array?DataType.VarArray:value instanceof IResource?Codec.isLocalResource(value,connection)?DataType.Resource:DataType.DistributedResource:value instanceof Date?DataType.DateTime:value instanceof Uint8Array||value instanceof ArrayBuffer?DataType.UInt8Array:value instanceof Number?DataType.Float64:value instanceof Structure?DataType.Structure:DataType.Void;default:return DataType.Void}}}var UNIX_EPOCH=621355968e9,TWO_PWR_32=4294967296;class DC extends Uint8Array{constructor(bufferOrSize){super(bufferOrSize),this.dv=new DataView(this.buffer)}static boolToBytes(value){var rt=new DC(1);return rt.setBoolean(0,value),rt}static int8ToBytes(value){var rt=new DC(1);return rt.setInt8(0,value),rt}static hexToBytes(value){for(var rt=new DC(value.length/2),i=0;i0}setBoolean(offset,value){this.setUint8(offset,value?1:0)}getBooleanArray(offset,length){for(var rt=[],i=0;i=0?l:TWO_PWR_32+l)}getUint64(offset){var h=this.getUint32(offset),l=this.getUint32(offset+4);return h*TWO_PWR_32+(l>=0?l:TWO_PWR_32+l)}setInt64(offset,value){var l=value%TWO_PWR_32|0,h=value/TWO_PWR_32|0;this.setInt32(offset,h),this.setInt32(offset+4,l)}setUint64(offset,value){var l=value%TWO_PWR_32|0,h=value/TWO_PWR_32|0;this.setInt32(offset,h),this.setInt32(offset+4,l)}setDateTime(offset,value){var ticks=621355968e9+1e4*value.getTime();this.setUint64(offset,ticks)}getDateTime(offset){var ticks=this.getUint64(offset);return new Date(Math.round((ticks-DCStatic.UNIX_EPOCH)/1e4))}getDateTimeArray(offset){for(var rt=[],i=0;i0&&!this.networkBuffer.protected;)self.receive(this.networkBuffer)}}receive(data){for(var msg=data.read(),offset=0,ends=msg.length,packet=this.packet,authPacket=this.authPacket;offsetage){var pv=r[pt.name];sl.addUint8(146).addUint32(callback).addUint8Array(Codec.compose(pv,sl.connection)).done()}else sl.addUint8(146).addUint32(callback).addUint8(DataType.NotModified).done()}})}IIPRequestSetProperty(callback,resourceId,index,content){var sl=this.sendParams();Warehouse.get(resourceId).then(function(r){if(null!=r){var pt=r.instance.template.getPropertyTemplateByIndex(index);null!=pt&&Codec.parse(content,0,this).then(function(value){r instanceof DistributedResource?r._set(index,value).then(function(x){sl.addUint8(147).addUint32(callback).done()}):(r[pt.name]=value,sl.addUint8(147).addUint32(callback).done())})}})}getTemplate(classId){if(this.templates[classId])return new AsyncReply(this.templates[classId]);if(this.templateRequests[classId])return this.templateRequests[classId];var reply=new AsyncReply;this.templateRequests[classId]=reply;var self=this;return this.sendRequest(IIPPacketAction.TemplateFromClassId,BL().addUint8Array(classId.value)).then(function(rt){delete self.templateRequests[classId],self.templates[rt[0].classId]=rt[0],reply.trigger(rt[0])}),reply}get(path){if(this.pathRequests[path])return this.pathRequests[path];var reply=new AsyncReply;this.pathRequests[path]=reply;var bl=new BinaryList;bl.addString(path),bl.addUint16(bl.length,0);var self=this;return this.sendRequest(IIPPacketAction.ResourceIdFromResourceLink,bl).then(function(rt){delete self.pathRequests[path],self.fetch(rt[1]).then(function(r){reply.trigger(r)})}),reply}retrieve(iid){for(var r in this.resources)if(this.resources[r].instance.id==iid)return new AsyncReply(r);return new AsyncReply(null)}fetch(id){if(this.resourceRequests[id]&&this.resources[id])return this.resourceRequests[id];if(this.resourceRequests[id])return this.resourceRequests[id];if(this.resources[id])return new AsyncReply(this.resources[id]);var reply=new AsyncReply,self=this;return this.sendRequest(IIPPacketAction.AttachResource,BL().addUint32(id)).then(function(rt){self.getTemplate(rt[0]).then(function(tmp){var dr=new DistributedResource(self,tmp,id,rt[1],rt[2]);Warehouse.put(dr,id.toString(),self),Codec.parseVarArray(rt[3],0,rt[3].length,self).then(function(ar){dr._attached(ar),delete self.resourceRequests[id],reply.trigger(dr)})})}),reply}instance_resourceDestroyed(resource){this.sendParams().addUint8(1).addUint32(resource.instance.id).done()}instance_propertyModified(resource,name,newValue,oldValue){var pt=resource.instance.template.getPropertyTemplateByName(name);null!=pt&&(newValue instanceof Function?sendParams().addUint8(16).addUint32(resource.instance.id).addUint8(pt.index).addUint8Array(Codec.compose(newValue(this),this)).done():sendParams().addUint8(16).addUint32(resource.instance.id).addUint8(pt.index).addUint8Array(Codec.compose(newValue,this)).done())}instance_eventOccured(resource,name,receivers,args){var et=resource.instance.template.getEventTemplateByName(name);if(null!=et&&!(null!=receivers&&receivers.indexOf(this.remoteUsername)<0)){for(var clientArgs=[],i=0;i=this._p.template.functions.length)throw new Exception("Function index is incorrect");var reply=new AsyncReply,parameters=Codec.composeVarArray(args,this._p.connection,!0),self=this;return this._p.connection.sendRequest(IIPPacketAction.InvokeFunction,BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)).then(function(res){Codec.parse(res[0],0,self._p.connection).then(function(rt){reply.trigger(rt)})}),reply}_get(index){return index>=this._p.properties.length?null:this._p.properties[index]}_updatePropertyByIndex(index,value){var pt=this._p.template.getPropertyTemplateByIndex(index);this._p.properties[index]=value,this.instance.modified(pt.name,value)}_set(index,value){if(index>=this._p.properties.length)return null;var reply=new AsyncReply,parameters=Codec.compose(value,this._p.connection),self=this;return this._p.connection.sendRequest(IIPPacketAction.SetProperty,BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)).then(function(res){reply.trigger(null)}),reply}}var DistributedResourceQueueItemType={Propery:0,Event:1};class DistributedResourceQueueItem{constructor(resource,type,value,index){this.resource=resource,this.index=index,this.type=type,this.value=value}}class EventTemplate extends MemberTemplate{constructor(){super(),this.type=MemberType.Event}compose(){var rt=new BinaryList,name=super.compose();if(null!=this.expansion){var exp=DC.stringToBytes(this.expansion);return rt.addUint8(80).addUint32(exp.length).addUint8Array(exp).addUint8(name.length).addUint8Array(name).toArray()}return rt.addUint8(64).addUint32(name.length).addUint8Array(name).toArray()}}class FunctionTemplate extends MemberTemplate{compose(){var name=super.compose(),rt=new BinaryList;if(null!=this.expansion){var exp=DC.stringToBytes(this.expansion);return rt.addUint8(16|(IsVoid?8:0)).addUint32(exp.length).addUint8Array(exp).addUint8(name.length).addUint8Array(name).toArray()}return rt.addUint8(IsVoid?8:0).addUint8(name.length).addUint8Array(name).toArray()}constructor(){super(),this.type=MemberType.Function}}class Guid{constructor(dc){this.value=dc}valueOf(){return this.value.getHex(0,16)}}var IIPAuthPacketCommand={Action:0,Declare:1,Acknowledge:2,Error:3},IIPAuthPacketAction={AuthenticateHash:0,NewConnection:32,ResumeConnection:33,ConnectionEstablished:40},IIPAuthPacketMethod={None:0,Certificate:1,Credentials:2,Token:3};class IIPAuthPacket{constructor(){this.command=0,this.action=0,this.errorCode=0,this.errorMessage="",this.localMethod=0,this.sourceInfo="",this.hash="",this.sessionId="",this.remoteMethod=0,this.domain="",this.CertificateId=0,this.localUsername="",this.remoteUsername="",this.localPassword="",this.remotePassword="",this.localToken=[],this.reemoteToken=[],this.asymetricEncryptionKey=[],this.localNonce=[],this.remoteNonce=[],this.dataLengthNeeded=0}notEnough(offset,ends,needed){return offset+needed>ends&&(this.dataLengthNeeded=needed-(ends-offset),!0)}parse(data,offset,ends){var oOffset=offset;if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;if(this.command=data.getUint8(offset)>>6,this.command==IIPAuthPacketCommand.Action){if(this.action=63&data[offset++],this.action==IIPAuthPacketAction.AuthenticateHash){if(this.notEnough(offset,ends,32))return-this.dataLengthNeeded;this.hash=data.getUint8Array(offset,32),offset+=32}else if(this.action==IIPAuthPacketAction.NewConnection){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;length=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,length))return-this.dataLengthNeeded;this.sourceInfo=data.clip(offset,length),offset+=32}else if(this.action==IIPAuthPacketAction.ResumeConnection||this.action==IIPAuthPacketAction.ConnectionEstablished){if(this.notEnough(offset,ends,32))return-this.dataLengthNeeded;this.sessionId=data.clip(offset,32),offset+=32}}else if(this.command==IIPAuthPacketCommand.Declare){this.remoteMethod=data.getUint8(offset)>>4&3,this.localMethod=data.getUint8(offset)>>2&3;encrypt=2==(2&data.getUint8(offset++));if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;var domainLength=data.getUint8(offset++);if(this.notEnough(offset,ends,domainLength))return-this.dataLengthNeeded;if(this.domain=data.getString(offset,domainLength),offset+=domainLength,this.remoteMethod==IIPAuthPacketMethod.Credentials&&this.localMethod==IIPAuthPacketMethod.None){if(this.notEnough(offset,ends,33))return-this.dataLengthNeeded;this.remoteNonce=data.clip(offset,32),offset+=32;var length=data.getUint8(offset++);if(this.notEnough(offset,ends,length))return-this.dataLengthNeeded;this.remoteUsername=data.getString(offset,length),offset+=length}if(encrypt){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;keyLength=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,keyLength))return-this.dataLengthNeeded;this.asymetricEncryptionKey=data.clip(offset,keyLength),offset+=keyLength}}else if(this.command==IIPAuthPacketCommand.Acknowledge){this.remoteMethod=data.getUint8(offset)>>4&3,this.localMethod=data.getUint8(offset)>>2&3;var encrypt=2==(2&data.getUint8(offset++));if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;if(this.remoteMethod==IIPAuthPacketMethod.Credentials&&this.localMethod==IIPAuthPacketMethod.None){if(this.notEnough(offset,ends,32))return-this.dataLengthNeeded;this.remoteNonce=data.clip(offset,32),offset+=32}if(encrypt){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;var keyLength=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,keyLength))return-this.dataLengthNeeded;this.asymetricEncryptionKey=data.clip(offset,keyLength),offset+=keyLength}}else if(this.command==IIPAuthPacketCommand.Error){if(this.notEnough(offset,ends,5))return-this.dataLengthNeeded;offset++,this.errorCode=data.getUint8(offset++);var cl=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.errorMessage=data.getString(offset,cl),offset+=cl}return offset-oOffset}}var IIPPacketCommand={Event:0,Request:1,Reply:2,Error:3},IIPPacketEvent={ResourceReassigned:0,ResourceDestroyed:1,PropertyUpdated:16,EventOccured:17},IIPPacketAction={AttachResource:0,ReattachResource:1,DetachResource:2,CreateResource:3,DeleteResource:4,TemplateFromClassName:8,TemplateFromClassId:9,TemplateFromResourceLink:10,TemplateFromResourceId:11,ResourceIdFromResourceLink:12,InvokeFunction:16,GetProperty:17,GetPropertyIfModified:18,SetProperty:19};class IIPPacket{constructor(){this.command=0,this.action=0,this.event=0,this.resourceId=0,this.newResourceId=0,this.resourceAge=0,this.content=[],this.errorCode=0,this.errorMessage="",this.className="",this.resourceLink="",this.classId="",this.methodIndex="",this.methodName="",this.callbackId=0,this.dataLengthNeeded=0}notEnough(offset,ends,needed){return offset+needed>ends&&(this.dataLengthNeeded=needed-(ends-offset),!0)}parse(data,offset,ends){var oOffset=offset;if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;if(this.command=data.getUint8(offset)>>6,this.command==IIPPacketCommand.Event){if(this.event=63&data.getUint8(offset++),this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4}else{if(this.action=63&data.getUint8(offset++),this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.callbackId=data.getUint32(offset),offset+=4}if(this.command==IIPPacketCommand.Event){if(this.event==IIPPacketEvent.ResourceReassigned){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.newResourceId=data.getUint32(offset),offset+=4}else if(this.event==IIPPacketEvent.ResourceDestroyed);else if(this.event==IIPPacketEvent.PropertyUpdated){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;this.methodIndex=data[offset++];dt=data.getUint8(offset++);if((size=DataType.sizeOf(dt))<0){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset-5,cl+5),offset+=cl}else{if(this.notEnough(offset,ends,size))return-this.dataLengthNeeded;this.content=data.clip(offset-1,size+1),offset+=size}}else if(this.event==IIPPacketEvent.EventOccured){if(this.notEnough(offset,ends,5))return-this.dataLengthNeeded;this.methodIndex=data.getUint8(offset++);cl=data.getUint32(offset);offset+=4,this.content=data.clip(offset,cl),offset+=cl}}else if(this.command==IIPPacketCommand.Request){if(this.action==IIPPacketAction.AttachResource){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.ReattachResource){if(this.notEnough(offset,ends,8))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4,this.resourceAge=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.DetachResource){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.CreateResource){if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;cl=data.getUint8(offset++);if(this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.className=data.getString(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.DeleteResource){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.TemplateFromClassName){if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;cl=data.getUint8(offset++);if(this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.className=data.getString(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.TemplateFromClassId){if(this.notEnough(offset,ends,16))return-this.dataLengthNeeded;this.classId=data.getGuid(offset),offset+=16}else if(this.action==IIPPacketAction.TemplateFromResourceLink){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;cl=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.resourceLink=data.getString(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.TemplateFromResourceId){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.ResourceIdFromResourceLink){if(this.notEnough(offset,ends,2))return-this.dataLengthNeeded;cl=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.resourceLink=data.getString(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.InvokeFunction){if(this.notEnough(offset,ends,9))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4,this.methodIndex=data.getUint8(offset++);cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.GetProperty){if(this.notEnough(offset,ends,5))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4,this.methodIndex=data.getUint8(offset++)}else if(this.action==IIPPacketAction.GetPropertyIfModified){if(this.notEnough(offset,ends,9))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4,this.methodIndex=data[offset++],this.resourceAge=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.SetProperty){if(this.notEnough(offset,ends,6))return-this.dataLengthNeeded;this.resourceId=data.getUint32(offset),offset+=4,this.methodIndex=data[offset++];dt=data.getUint8(offset++);if((size=DataType.sizeOf(dt))<0){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset-5,cl+5),offset+=cl}else{if(this.notEnough(offset,ends,size))return-this.dataLengthNeeded;this.content=data.clip(offset-1,size+1),offset+=size}}}else if(this.command==IIPPacketCommand.Reply)if(this.action==IIPPacketAction.AttachResource||this.action==IIPPacketAction.ReattachResource){if(this.notEnough(offset,ends,26))return-this.dataLengthNeeded;this.classId=data.getGuid(offset),offset+=16,this.resourceAge=data.getUint32(offset),offset+=4;cl=data.getUint16(offset);if(offset+=2,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;if(this.resourceLink=data.getString(offset,cl),offset+=cl,this.notEnough(offset,ends,4))return-this.dataLengthNeeded;if(cl=data.getUint32(offset),offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.DetachResource);else if(this.action==IIPPacketAction.CreateResource){if(this.notEnough(offset,ends,20))return-this.dataLengthNeeded;this.classId=data.GetGuid(offset),offset+=16,this.resourceId=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.DetachResource);else if(this.action==IIPPacketAction.TemplateFromClassName||this.action==IIPPacketAction.TemplateFromClassId||this.action==IIPPacketAction.TemplateFromResourceLink||this.action==IIPPacketAction.TemplateFromResourceId){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset,cl),offset+=cl}else if(this.action==IIPPacketAction.ResourceIdFromResourceLink){if(this.notEnough(offset,ends,24))return-this.dataLengthNeeded;this.classId=data.getGuid(offset),offset+=16,this.resourceId=data.getUint32(offset),offset+=4,this.resourceAge=data.getUint32(offset),offset+=4}else if(this.action==IIPPacketAction.InvokeFunction||this.action==IIPPacketAction.GetProperty||this.action==IIPPacketAction.GetPropertyIfModified){if(this.notEnough(offset,ends,1))return-this.dataLengthNeeded;var dt=data.getUint8(offset++),size=DataType.sizeOf(dt);if(size<0){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.content=data.clip(offset-5,cl+5),offset+=cl}else{if(this.notEnough(offset,ends,size))return-this.dataLengthNeeded;this.content=data.clip(offset-1,size+1),offset+=size}}else this.action,IIPPacketAction.SetProperty;else if(this.command==IIPPacketCommand.Error){if(this.notEnough(offset,ends,4))return-this.dataLengthNeeded;if(this.callbackId=data.getUint32(offset),this.notEnough(offset,ends,1))return-this.dataLengthNeeded;if(this.errorCode=data.getUint8(offset++),this.notEnough(offset,ends,4))return-this.dataLengthNeeded;var cl=data.getUint32(offset);if(offset+=4,this.notEnough(offset,ends,cl))return-this.dataLengthNeeded;this.errorMessage=data.getString(offset,cl),offset+=cl}return offset-oOffset}}class Instance extends IEventHandler{getAge(index){return indexthis.data.length}get available(){return this.data.length}holdAllForNextWrite(src){this.holdFor(src,src.length+1)}holdForNextWrite(src,offset,size){this.holdFor(src,offset,size,size+1)}holdFor(src,offset,size,needed){if(size>=needed)throw new Exception("Size >= Needed !");this.data=DC.combine(src,offset,size,this.data,0,this.data.length),this.neededDataLength=needed}holdAllFor(src,needed){this.holdFor(src,0,src.length,needed)}protect(data,offset,needed){var dataLength=data.length-offset;return dataLength=this.neededDataLength?(rt=this.data,this.data=new DC(0),this.neededDataLength=0,rt):null:(rt=this.data,this.data=new DC(0),rt)}}class NotModified{}var PropertyPermission={Read:1,Write:2,ReadWrite:3};class PropertyTemplate extends MemberTemplate{constructor(){super(),this.type=MemberType.Property}compose(){var name=super.compose(),rt=new BinaryList;if(null!=this.writeExpansion&&null!=this.readExpansion){var rexp=DC.stringToBytes(this.readExpansion),wexp=DC.stringToBytes(this.writeExpansion);return rt.addUint8(56|this.permission).addUint32(wexp.length).addUint8Array(wexp).addUint32(rexp.length).addUint8Array(rexp).addUint8(name.length).addUint8Array(name).toArray()}if(null!=this.writeExpansion){wexp=DC.stringToBytes(this.writeExpansion);return rt.addUint8(48|this.permission).addUint32(wexp.length).addUint8Array(wexp).addUint8(name.length).addUint8Array(name).toArray()}if(null!=this.readExpansion){rexp=DC.stringToBytes(this.readExpansion);return rt.addUint8(40|this.permission).addUint32(rexp.length).addUint8Array(rexp).addUint8(name.length).addUint8Array(name).toArray()}return rt.addUint8(32|this.permission).addUint32(name.length).addUint8Array(name).toArray()}}class ResourceTemplate{getMemberTemplate(member){return member instanceof MethodInfo?this.getFunctionTemplate(member.name):member instanceof EventInfo?this.getEventTemplate(member.name):member instanceof PropertyInfo?this.getPropertyTemplate(member.name):null}getEventTemplateByName(eventName){for(var i=0;i>5;if(0==type){var ft=new FunctionTemplate;ft.index=functionIndex++;expansion=16==(16&data.getUint8(offset));if(ft.isVoid=8==(8&data.getUint8(offset++)),ft.name=data.getString(offset+1,data.getUint8(offset)),offset+=data.getUint8(offset)+1,expansion){cs=data.getUint32(offset);offset+=4,ft.expansion=data.getString(offset,cs),offset+=cs}od.functions.push(ft)}else if(1==type){var pt=new PropertyTemplate;pt.index=propertyIndex++;var readExpansion=8==(8&data.getUint8(offset)),writeExpansion=16==(16&data.getUint8(offset));if(pt.permission=data.getUint8(offset++)>>1&3,pt.name=data.getString(offset+1,data.getUint8(offset)),offset+=data.getUint8(offset)+1,readExpansion){cs=data.getUint32(offset);offset+=4,pt.readExpansion=data.getString(offset,cs),offset+=cs}if(writeExpansion){cs=data.getUint32(offset);offset+=4,pt.writeExpansion=data.getString(offset,cs),offset+=cs}od.properties.push(pt)}else if(2==type){var et=new EventTemplate;et.index=eventIndex++;var expansion=16==(16&data.getUint8(offset++));if(et.name=data.getString(offset+1,data.getUint8(offset)),offset+=data.getUint8(offset)+1,expansion){var cs=data.getUint32(offset);offset+=4,et.expansion=data.getString(offset,cs),offset+=cs}od.events.push(et)}}for(i=0;i + + + + + + + + + \ No newline at end of file diff --git a/examples/test-plain.html b/examples/test-plain.html new file mode 100644 index 0000000..8200ab9 --- /dev/null +++ b/examples/test-plain.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/test.html b/examples/test.html new file mode 100644 index 0000000..f14a845 --- /dev/null +++ b/examples/test.html @@ -0,0 +1,37 @@ + + + + + + + + + + \ No newline at end of file diff --git a/external/sha256.min.js b/external/sha256.min.js new file mode 100644 index 0000000..449dcc8 --- /dev/null +++ b/external/sha256.min.js @@ -0,0 +1,9 @@ +/** + * [js-sha256]{@link https://github.com/emn178/js-sha256} + * + * @version 0.6.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2014-2017 + * @license MIT + */ +!function(){"use strict";function t(t,i){i?(p[0]=p[16]=p[1]=p[2]=p[3]=p[4]=p[5]=p[6]=p[7]=p[8]=p[9]=p[10]=p[11]=p[12]=p[13]=p[14]=p[15]=0,this.blocks=p):this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],t?(this.h0=3238371032,this.h1=914150663,this.h2=812702999,this.h3=4144912697,this.h4=4290775857,this.h5=1750603025,this.h6=1694076839,this.h7=3204075428):(this.h0=1779033703,this.h1=3144134277,this.h2=1013904242,this.h3=2773480762,this.h4=1359893119,this.h5=2600822924,this.h6=528734635,this.h7=1541459225),this.block=this.start=this.bytes=0,this.finalized=this.hashed=!1,this.first=!0,this.is224=t}function i(i,r,e){var n="string"!=typeof i;if(n){if(null===i||void 0===i)throw h;i.constructor===s.ArrayBuffer&&(i=new Uint8Array(i))}var o=i.length;if(n){if("number"!=typeof o||!Array.isArray(i)&&(!a||!ArrayBuffer.isView(i)))throw h}else{for(var f,u=[],o=i.length,c=0,y=0;o>y;++y)f=i.charCodeAt(y),128>f?u[c++]=f:2048>f?(u[c++]=192|f>>6,u[c++]=128|63&f):55296>f||f>=57344?(u[c++]=224|f>>12,u[c++]=128|f>>6&63,u[c++]=128|63&f):(f=65536+((1023&f)<<10|1023&i.charCodeAt(++y)),u[c++]=240|f>>18,u[c++]=128|f>>12&63,u[c++]=128|f>>6&63,u[c++]=128|63&f);i=u}i.length>64&&(i=new t(r,!0).update(i).array());for(var p=[],l=[],y=0;64>y;++y){var d=i[y]||0;p[y]=92^d,l[y]=54^d}t.call(this,r,e),this.update(l),this.oKeyPad=p,this.inner=!0,this.sharedMemory=e}var h="input is invalid type",s="object"==typeof window?window:{},r=!s.JS_SHA256_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;r&&(s=global);var e=!s.JS_SHA256_NO_COMMON_JS&&"object"==typeof module&&module.exports,n="function"==typeof define&&define.amd,a="undefined"!=typeof ArrayBuffer,o="0123456789abcdef".split(""),f=[-2147483648,8388608,32768,128],u=[24,16,8,0],c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],y=["hex","array","digest","arrayBuffer"],p=[];(s.JS_SHA256_NO_NODE_JS||!Array.isArray)&&(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)});var l=function(i,h){return function(s){return new t(h,!0).update(s)[i]()}},d=function(i){var h=l("hex",i);r&&(h=v(h,i)),h.create=function(){return new t(i)},h.update=function(t){return h.create().update(t)};for(var s=0;so;){if(this.hashed&&(this.hashed=!1,f[0]=this.block,f[16]=f[1]=f[2]=f[3]=f[4]=f[5]=f[6]=f[7]=f[8]=f[9]=f[10]=f[11]=f[12]=f[13]=f[14]=f[15]=0),i)for(n=this.start;r>o&&64>n;++o)f[n>>2]|=t[o]<o&&64>n;++o)e=t.charCodeAt(o),128>e?f[n>>2]|=e<e?(f[n>>2]|=(192|e>>6)<>2]|=(128|63&e)<e||e>=57344?(f[n>>2]|=(224|e>>12)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<>2]|=(240|e>>18)<>2]|=(128|e>>12&63)<>2]|=(128|e>>6&63)<>2]|=(128|63&e)<=64?(this.block=f[16],this.start=n-64,this.hash(),this.hashed=!0):this.start=n}return this}},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,i=this.lastByteIndex;t[16]=this.block,t[i>>2]|=f[3&i],this.block=t[16],i>=56&&(this.hashed||this.hash(),t[0]=this.block,t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[15]=this.bytes<<3,this.hash()}},t.prototype.hash=function(){var t,i,h,s,r,e,n,a,o,f,u,y=this.h0,p=this.h1,l=this.h2,d=this.h3,v=this.h4,A=this.h5,w=this.h6,b=this.h7,g=this.blocks;for(t=16;64>t;++t)r=g[t-15],i=(r>>>7|r<<25)^(r>>>18|r<<14)^r>>>3,r=g[t-2],h=(r>>>17|r<<15)^(r>>>19|r<<13)^r>>>10,g[t]=g[t-16]+i+g[t-7]+h<<0;for(u=p&l,t=0;64>t;t+=4)this.first?(this.is224?(a=300032,r=g[0]-1413257819,b=r-150054599<<0,d=r+24177077<<0):(a=704751109,r=g[0]-210244248,b=r-1521486534<<0,d=r+143694565<<0),this.first=!1):(i=(y>>>2|y<<30)^(y>>>13|y<<19)^(y>>>22|y<<10),h=(v>>>6|v<<26)^(v>>>11|v<<21)^(v>>>25|v<<7),a=y&p,s=a^y&l^u,n=v&A^~v&w,r=b+h+n+c[t]+g[t],e=i+s,b=d+r<<0,d=r+e<<0),i=(d>>>2|d<<30)^(d>>>13|d<<19)^(d>>>22|d<<10),h=(b>>>6|b<<26)^(b>>>11|b<<21)^(b>>>25|b<<7),o=d&y,s=o^d&p^a,n=b&v^~b&A,r=w+h+n+c[t+1]+g[t+1],e=i+s,w=l+r<<0,l=r+e<<0,i=(l>>>2|l<<30)^(l>>>13|l<<19)^(l>>>22|l<<10),h=(w>>>6|w<<26)^(w>>>11|w<<21)^(w>>>25|w<<7),f=l&d,s=f^l&y^o,n=w&b^~w&v,r=A+h+n+c[t+2]+g[t+2],e=i+s,A=p+r<<0,p=r+e<<0,i=(p>>>2|p<<30)^(p>>>13|p<<19)^(p>>>22|p<<10),h=(A>>>6|A<<26)^(A>>>11|A<<21)^(A>>>25|A<<7),u=p&l,s=u^p&d^f,n=A&w^~A&b,r=v+h+n+c[t+3]+g[t+3],e=i+s,v=y+r<<0,y=r+e<<0;this.h0=this.h0+y<<0,this.h1=this.h1+p<<0,this.h2=this.h2+l<<0,this.h3=this.h3+d<<0,this.h4=this.h4+v<<0,this.h5=this.h5+A<<0,this.h6=this.h6+w<<0,this.h7=this.h7+b<<0},t.prototype.hex=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,f=o[t>>28&15]+o[t>>24&15]+o[t>>20&15]+o[t>>16&15]+o[t>>12&15]+o[t>>8&15]+o[t>>4&15]+o[15&t]+o[i>>28&15]+o[i>>24&15]+o[i>>20&15]+o[i>>16&15]+o[i>>12&15]+o[i>>8&15]+o[i>>4&15]+o[15&i]+o[h>>28&15]+o[h>>24&15]+o[h>>20&15]+o[h>>16&15]+o[h>>12&15]+o[h>>8&15]+o[h>>4&15]+o[15&h]+o[s>>28&15]+o[s>>24&15]+o[s>>20&15]+o[s>>16&15]+o[s>>12&15]+o[s>>8&15]+o[s>>4&15]+o[15&s]+o[r>>28&15]+o[r>>24&15]+o[r>>20&15]+o[r>>16&15]+o[r>>12&15]+o[r>>8&15]+o[r>>4&15]+o[15&r]+o[e>>28&15]+o[e>>24&15]+o[e>>20&15]+o[e>>16&15]+o[e>>12&15]+o[e>>8&15]+o[e>>4&15]+o[15&e]+o[n>>28&15]+o[n>>24&15]+o[n>>20&15]+o[n>>16&15]+o[n>>12&15]+o[n>>8&15]+o[n>>4&15]+o[15&n];return this.is224||(f+=o[a>>28&15]+o[a>>24&15]+o[a>>20&15]+o[a>>16&15]+o[a>>12&15]+o[a>>8&15]+o[a>>4&15]+o[15&a]),f},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,i=this.h1,h=this.h2,s=this.h3,r=this.h4,e=this.h5,n=this.h6,a=this.h7,o=[t>>24&255,t>>16&255,t>>8&255,255&t,i>>24&255,i>>16&255,i>>8&255,255&i,h>>24&255,h>>16&255,h>>8&255,255&h,s>>24&255,s>>16&255,s>>8&255,255&s,r>>24&255,r>>16&255,r>>8&255,255&r,e>>24&255,e>>16&255,e>>8&255,255&e,n>>24&255,n>>16&255,n>>8&255,255&n];return this.is224||o.push(a>>24&255,a>>16&255,a>>8&255,255&a),o},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(this.is224?28:32),i=new DataView(t);return i.setUint32(0,this.h0),i.setUint32(4,this.h1),i.setUint32(8,this.h2),i.setUint32(12,this.h3),i.setUint32(16,this.h4),i.setUint32(20,this.h5),i.setUint32(24,this.h6),this.is224||i.setUint32(28,this.h7),t},i.prototype=new t,i.prototype.finalize=function(){if(t.prototype.finalize.call(this),this.inner){this.inner=!1;var i=this.array();t.call(this,this.is224,this.sharedMemory),this.update(this.oKeyPad),this.update(i),t.prototype.finalize.call(this)}};var b=d();b.sha256=b,b.sha224=d(!0),b.sha256.hmac=w(),b.sha224.hmac=w(!0),e?module.exports=b:(s.sha256=b.sha256,s.sha224=b.sha224,n&&define(function(){return b}))}(); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..87c7a9d --- /dev/null +++ b/index.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AsyncBag.js b/src/AsyncBag.js new file mode 100644 index 0000000..3df9d38 --- /dev/null +++ b/src/AsyncBag.js @@ -0,0 +1,61 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +class AsyncBag extends AsyncReply +{ + constructor() { + super(); + this.replies = []; + this.results = []; + this.count = 0; + this.sealedBag = false; + } + + seal() + { + this.sealedBag = true; + + if (this.results.length == 0) + this.trigger([]); + + var self = this; + + for(var i = 0; i < this.results.length; i++) + this.replies[i].then(function(r, reply){ + self.results[self.replies.indexOf(reply)] = r; + self.count++; + if (self.count == self.results.length) + self.trigger(self.results); + }); + } + + add(reply) + { + if (!this.sealedBag) { + this.replies.push(reply); + this.results.push(null); + } + } +} \ No newline at end of file diff --git a/src/AsyncQueue.js b/src/AsyncQueue.js new file mode 100644 index 0000000..4bc8bfa --- /dev/null +++ b/src/AsyncQueue.js @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +class AsyncQueue extends AsyncReply +{ + + constructor() + { + super(); + this.list = []; + + var self = this; + + this.processQueue = function () + { + for (var i = 0; i < self.list.length; i++) + if (self.list[i].ready) + { + self.trigger(self.list[i].result); + self.list.splice(i, 1); + i--; + } + else + break; + + self.ready = (self.list.length == 0); + } + } + + add(reply) + { + this.list.push(reply); + this.ready = false; + reply.then(this.processQueue); + } + + remove(reply) + { + this.list.splice(this.list.indexOf(reply), 1); + this.processQueue(); + } + + + +} \ No newline at end of file diff --git a/src/AsyncReply.js b/src/AsyncReply.js new file mode 100644 index 0000000..2487b17 --- /dev/null +++ b/src/AsyncReply.js @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +class AsyncReply +{ + then(callback) + { + this.callbacks.push(callback); + if (this.ready) + callback(this.result, this); + } + + trigger(result) + { + this.result = result; + this.ready = true; + + for(var i = 0; i < this.callbacks.length; i++) + this.callbacks[i](result, this); + } + + constructor(result) + { + this.callbacks = []; + + if (result) { + this.result = result; + this.ready = true; + } + } +} \ No newline at end of file diff --git a/src/AutoList.js b/src/AutoList.js new file mode 100644 index 0000000..d7d1976 --- /dev/null +++ b/src/AutoList.js @@ -0,0 +1,88 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 05/09/2017. + */ + +class AutoList extends IEventHandler +{ + constructor() + { + super(); + this.list = []; + } + + add(value) + { + if (value instanceof IDestructible) + value.on("destroy", this._item_destroyed); + + this.list.push(value); + + this._emit("add", value); + } + + set(index, value) + { + if (index >= this.list.length || index < 0) + return; + + if (value instanceof IDestructible) + value.on("destroy", this._item_destroyed); + + if (this.list[index] instanceof IDestructible) + this.list[index].off("destroy", this._item_destroyed); + + this.list[index] = value; + } + + remove(value) + { + this.removeAt(this.list.indexOf(value)); + } + + contains(value) + { + return this.list.indexOf(value) > -1; + } + + removeAt(index) + { + if (index >= this.list.length || index < 0) + return; + + var item = this.list[index]; + + if (item instanceof IDestructible) + item.off("destroy", this._item_destroyed); + + this.list.splice(index, 1); + + this._emit("remove", item); + } + + _item_destroyed(sender) + { + this.remove(sender); + } +} \ No newline at end of file diff --git a/src/AutoMap.js b/src/AutoMap.js new file mode 100644 index 0000000..7871ed6 --- /dev/null +++ b/src/AutoMap.js @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 05/09/2017. + */ + +class AutoMap extends IEventHandler +{ + constructor() + { + super(); + this.dic = {}; + } + + add(key, value) + { + if (value instanceof IDestructible) + value.on("destroy", this._item_destroyed); + + this.dic[key] = value; + + this._emit("add", key, value); + } + + set(key, value) + { + if (this.dic[key] !== undefined) + this.remove(key); + + this.add(key, value); + } + + remove(key) + { + if (this.dic[key] !== undefined) { + if (this.dic[key] instanceof IDestructible) + this.dic[key].off("destroy", this._item_destroyed); + + delete this.dic[key]; + } + } + + _item_destroyed(sender) + { + this.remove(sender); + } +} \ No newline at end of file diff --git a/src/BinaryList.js b/src/BinaryList.js new file mode 100644 index 0000000..4bb5594 --- /dev/null +++ b/src/BinaryList.js @@ -0,0 +1,214 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/08/2017. + */ + +var BL = function(){ + return new BinaryList(); +}; + +class BinaryList +{ + + constructor() + { + this.list = []; + } + + + addRange(bl) + { + for(var i = 0; i < bl.list.length; i++) + this.list.push(bl.list[i]); + + return this; + } + + add(typedValue, position) + { + if (position !== undefined) + this.list.splice(position, 0, typedValue); + else + this.list.push(typedValue); + return this; + } + + get length() + { + return this.toArray().length; + } + + toArray() + { + var ars = []; + // calculate length + for(var i = 0; i < this.list.length; i++) + { + switch (this.list[i].type) + { + case DataType.Bool: + ars.push(DC.boolToBytes(this.list[i].value)); + break; + case DataType.UInt8: + ars.push(DC.uint8ToBytes(this.list[i].value)); + break; + case DataType.Int8: + ars.push(DC.int8ToBytes(this.list[i].value)); + break; + case DataType.Char: + ars.push(DC.charToBytes(this.list[i].value)); + break; + case DataType.UInt16: + ars.push(DC.uint16ToBytes(this.list[i].value)); + break; + case DataType.Int16: + ars.push(DC.int16ToBytes(this.list[i].value)); + break; + case DataType.UInt32: + ars.push(DC.uint32ToBytes(this.list[i].value)); + break; + case DataType.Int32: + ars.push(DC.int32ToBytes(this.list[i].value)); + break; + case DataType.UInt64: + ars.push(DC.uint64ToBytes(this.list[i].value)); + break; + case DataType.Int64: + ars.push(DC.int64ToBytes(this.list[i].value)); + break; + case DataType.Float32: + ars.push(DC.float32ToBytes(this.list[i].value)); + break; + case DataType.Float64: + ars.push(DC.float64ToBytes(this.list[i].value)); + break; + case DataType.String: + ars.push(DC.stringToBytes(this.list[i].value)); + break; + case DataType.DateTime: + ars.push(DC.dateTimeToBytes(this.list[i].value)); + break; + case DataType.UInt8Array: + ars.push(this.list[i].value); + + //case DataType.Resource: + // ars.push(DC.uint32ToBytes(this.list[i].value.instance.id)); + // break; + //case DataType.DistributedResource: + // ars.push(DC.int8ToBytes(this.list[i].value)); + // break; + + + + } + } + + var length = 0; + ars.forEach(function(a){ + length += a.length; + }); + + var rt = new Uint8Array(length); + + var offset = 0; + for(var i = 0; i < ars.length; i++) { + rt.set(ars[i], offset); + offset+=ars[i].length; + } + + return rt; + } + + addUint8Array(value, position) + { + return this.add({type: DataType.UInt8Array, value: value}, position); + } + + + addHex(value, position) + { + return this.addUint8Array(DC.hexToBytes(value), position); + } + + addString(value, position) + { + return this.add({type: DataType.String, value: value}, position); + } + + addUint8(value, position) + { + return this.add({type: DataType.UInt8, value: value}, position); + } + + addInt8(value, position) + { + return this.add({type: DataType.Int8, value: value}, position); + } + + addChar(value, position) + { + return this.add({type: DataType.Char, value: value}, position); + } + + addUint16(value, position) + { + return this.add({type: DataType.UInt16, value: value}, position); + } + + addInt16(value, position) + { + return this.add({type: DataType.Int16, value: value}, position); + } + + addUint32(value, position) + { + return this.add({type: DataType.UInt32, value: value}, position); + } + + addInt32(value, position) + { + return this.add({type: DataType.Int32, value: value}, position); + } + + addUint64(value, position) + { + return this.add({type: DataType.UInt64, value: value}, position); + } + + addInt64(value, position) + { + return this.add({type: DataType.Int64, value: value}, position); + } + + addFloat32(value, position) + { + return this.add({type: DataType.Float32, value: value}, position); + } + + addFloat64(value, position) + { + return this.add({type: DataType.Float64, value: value}, position); + } + +} \ No newline at end of file diff --git a/src/Codec.js b/src/Codec.js new file mode 100644 index 0000000..9d99ce6 --- /dev/null +++ b/src/Codec.js @@ -0,0 +1,622 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var ResourceComparisonResult = + { + Null: 0, + Distributed: 1, + DistributedSameClass: 2, + Local: 3, + Same: 4 + }; + +var StructureComparisonResult = + { + Null: 0, + Structure: 1, + StructureSameKeys: 2, + StructureSameTypes: 3, + Same: 4 + }; + +class Codec { + + static parse(data, offset, sizeObject, connection, dataType = DataType.Unspecified) { + + var size; + + var reply = new AsyncReply(); + + var isArray; + var t; + + if (dataType == DataType.Unspecified) { + size = 1; + dataType = data[offset++]; + } + else + size = 0; + + t = dataType & 0x7F; + + isArray = (dataType & 0x80) == 0x80; + + var payloadSize = DataType.sizeOf(dataType); + + var contentLength = 0; + + // check if we have the enough data + if (payloadSize == -1) { + contentLength = data.getUint32(offset); + offset += 4; + size += 4 + contentLength; + } + else + size += payloadSize; + + + sizeObject.size = size; + + if (isArray) { + switch (t) { + // VarArray ? + case DataType.Void: + return Codec.parseVarArray(data, offset, contentLength, connection); + + case DataType.Bool: + return new AsyncReply(data.getBooleanArray(offset, contentLength)); + + case DataType.UInt8: + return new AsyncReply(data.getUint8Array(offset, contentLength)); + + case DataType.Int8: + return new AsyncReply(data.getInt8Array(offset, contentLength)); + + case DataType.Char: + return new AsyncReply(data.getCharArray(offset, contentLength)); + + case DataType.Int16: + return new AsyncReply(data.getInt16Array(offset, contentLength)); + + case DataType.UInt16: + return new AsyncReply(data.getUint16Array(offset, contentLength)); + + case DataType.Int32: + return new AsyncReply(data.getInt32Array(offset, contentLength)); + + case DataType.UInt32: + return new AsyncReply(data.getUint32Array(offset, contentLength)); + + case DataType.Int64: + return new AsyncReply(data.getInt64Array(offset, contentLength)); + + case DataType.UInt64: + return new AsyncReply(data.getUint64Array(offset, contentLength)); + + case DataType.Float32: + return new AsyncReply(data.getFloat32Array(offset, contentLength)); + + case DataType.Float64: + return new AsyncReply(data.getFloat64Array(offset, contentLength)); + + case DataType.String: + return new AsyncReply(data.getStringArray(offset, contentLength)); + + case DataType.Resource: + case DataType.DistributedResource: + return Codec.parseResourceArray(data, offset, contentLength, connection); + + case DataType.DateTime: + return new AsyncReply(data.getDateTimeArray(offset, contentLength)); + + case DataType.Structure: + return Codec.parseStructureArray(data, offset, contentLength, connection); + } + } + else { + switch (t) { + case DataType.NotModified: + return new AsyncReply(new NotModified()); + + case DataType.Void: + return new AsyncReply(null); + + case DataType.Bool: + return new AsyncReply(data.getBoolean(offset)); + + case DataType.UInt8: + return new AsyncReply(data[offset]); + + case DataType.Int8: + return new AsyncReply(data.getInt8(offset)); + + case DataType.Char: + return new AsyncReply(data.getChar(offset)); + + case DataType.Int16: + return new AsyncReply(data.getInt16(offset)); + + case DataType.UInt16: + return new AsyncReply(data.getUint16(offset)); + + case DataType.Int32: + return new AsyncReply(data.getInt32(offset)); + + case DataType.UInt32: + return new AsyncReply(data.getUint32(offset)); + + case DataType.Int64: + return new AsyncReply(data.getInt64(offset)); + + case DataType.UInt64: + return new AsyncReply(data.getUint64(offset)); + + case DataType.Float32: + return new AsyncReply(data.getFloat32(offset)); + + case DataType.Float64: + return new AsyncReply(data.getFloat64(offset)); + + case DataType.String: + return new AsyncReply(data.getString(offset, contentLength)); + + case DataType.Resource: + return Codec.parseResource(data, offset); + + case DataType.DistributedResource: + return Codec.parseDistributedResource(data, offset, connection); + + case DataType.DateTime: + return new AsyncReply(data.getDateTime(offset)); + + case DataType.Structure: + return Codec.parseStructure(data, offset, contentLength, connection); + } + } + + + return null; + } + + static parseResource(data, offset) { + return Warehouse.get(data.getUint32(offset)); + } + + static parseDistributedResource(data, offset, connection) { + //var g = data.getGuid(offset); + //offset += 16; + + // find the object + var iid = data.getUint32(offset); + + return connection.fetch(iid);// Warehouse.Get(iid); + } + + + static parseStructure(data, offset, contentLength, connection, keylist = null, typelist = null, keys = null, types = null) { + var reply = new AsyncReply(); + var bag = new AsyncBag(); + + + if (keylist == null) + keylist = []; + if (typelist == null) + typelist = []; + + if (keys == null) { + while (contentLength > 0) { + var len = data[offset++]; + keylist.push(data.getString(offset, len)); + offset += len; + + typelist.push(data[offset]); + + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection)); + contentLength -= rt.size + len + 1; + offset += rt.size; + } + } + else if (types == null) { + for (var i = 0; i < keys.length; i++) + keylist.push(keys[i]); + + while (contentLength > 0) { + typelist.push(data[offset]); + + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection)); + contentLength -= rt.size + 1; + offset += rt.size + 1; + } + } + else { + for (var i = 0; i < keys.length; i++) { + keylist.push(keys[i]); + typelist.push(types[i]); + } + + var i = 0; + while (contentLength > 0) { + var rt = {}; + bag.add(Codec.parse(data, offset, rt, connection, types[i])); + contentLength -= rt.size; + offset += rt.size; + i++; + } + } + + bag.seal(); + + bag.then(function (res) { + // compose the list + var s = new Structure(); + for (var i = 0; i < keylist.length; i++) + s[keylist[i]] = res[i]; + reply.trigger(s); + }); + + + return reply; + } + + + static parseVarArray(data, offset, contentLength, connection) { + var rt = new AsyncBag(); + + while (contentLength > 0) { + var cs = {}; + + rt.add(Codec.parse(data, offset, cs, connection)); + + if (cs.size > 0) { + offset += cs.size; + contentLength -= cs.size; + } + else + throw new Exception("Error while parsing structured data"); + + } + + rt.seal(); + return rt; + } + + + static compose(value, connection, prependType = true) { + + var type = Codec.getDataType(value, connection); + var rt = new BinaryList(); + + switch (type) { + case DataType.Void: + // nothing to do; + break; + + case DataType.String: + var st = DC.stringToBytes(value); + rt.addUint32(st.length).addUint8Array(st); + break; + + case DataType.Resource: + rt.addUint32(value.instance.id); + break; + + case DataType.DistributedResource: +// rt.addUint8Array(DC.stringToBytes(value.instance.template.classId)).addUint32(value.instance.id); + rt.addUint32(value.instance.id); + break; + + case DataType.Structure: + rt.addUint8Array(Codec.composeStructure(value, connection, true, true, true)); + break; + + case DataType.VarArray: + rt.addUint8Array(Codec.composeVarArray(value, connection, true)); + break; + + case DataType.ResourceArray: + rt.addUint8Array(Codec.composeResourceArray(value, connection, true)); + break; + + case DataType.StructureArray: + rt.addUint8Array(Codec.composeStructureArray(value, connection, true)); + break; + + default: + rt.add({type: type, value: value}); + if (DataType.isArray(type)) + rt.addUint32(rt.length, 0); + + break; + } + + if (prependType) + rt.addUint8(type, 0); + + return rt.toArray(); + } + + static composeVarArray(array, connection, prependLength = false) { + var rt = new BinaryList(); + + for (var i = 0; i < array.length; i++) + rt.addUint8Array(Codec.compose(array[i], connection)); + + if (prependLength) + rt.addUint32(rt.length, 0); + return rt.toArray(); + } + + static composeStructure(value, connection, includeKeys = true, includeTypes = true, prependLength = false) { + var rt = new BinaryList(); + + var keys = value.getKeys(); + + if (includeKeys) { + for (var i = 0; i < keys.length; i++) { + var key = DC.stringToBytes(keys[i]); + rt.addUint8(key.length).addString(key).addUint8Array(DC.compose(value[i], connection)); + } + } + else { + for (var i = 0; i < keys.length; i++) + rt.addUint8Array(DC.compose(value[keys[i]], connection, includeTypes)); + } + + if (prependLength) + rt.addUint32(rt.length, 0); + + return rt.toArray(); + } + + static composeStructureArray(structures, connection, prependLength = false) { + if (structures == null || structures.length == 0 || !(structures instanceof StructureArray)) + return new DC(0); + + var rt = new BinaryList(); + var comparision = StructureComparisonResult.Structure; + + rt.addUint8(comparision); + rt.addUint8Array(Codec.composeStructure(structures[0], connection)); + + for (var i = 1; i < structures.Length; i++) { + comparision = Codec.compareStructure(structures[i - 1], structures[i], connection); + rt.addUint8(comparision); + + if (comparision == StructureComparisonResult.Structure) + rt.addUint8Array(Codec.composeStructure(structures[i], connection)); + else if (comparision == StructureComparisonResult.StructureSameKeys) + rt.addUint8Array(Codec.composeStructure(structures[i], connection, false)); + else if (comparision == StructureComparisonResult.StructureSameTypes) + rt.addUint8Array(Codec.composeStructure(structures[i], connection, false, false)); + } + + if (prependLength) + rt.addUint32(rt.length, 0); + + return rt.toArray(); + } + + static compareStructure(previous, next, connection) { + if (next == null) + return StructureComparisonResult.Null; + + if (previous == null) + return StructureComparisonResult.Structure; + + if (next == previous) + return StructureComparisonResult.Same; + + if (previous.length != next.length) + return StructureComparisonResult.Structure; + + var previousKeys = previous.getKeys(); + var nextKeys = next.getKeys(); + + for (var i = 0; i < previousKeys.length; i++) + if (previousKeys[i] != nextKeys[i]) + return StructureComparisonResult.Structure; + + var previousTypes = Codec.getStructureDateTypes(previous, connection); + var nextTypes = Codec.getStructureDateTypes(next, connection); + + for (var i = 0; i < previousTypes.length; i++) + if (previousTypes[i] != nextTypes[i]) + return StructureComparisonResult.StructureSameKeys; + + return StructureComparisonResult.StructureSameTypes; + } + + static getStructureDateTypes(structure, connection) { + var keys = structure.getKeys(); + var types = []; + + for (var i = 0; i < keys.length; i++) + types.push(Codec.getDataType(structure[keys[i]], connection)); + return types; + } + +static isLocalResource(resource, connection) { + if (resource instanceof DistributedResource) + if (resource.connection == connection) + return true; + + return false; +} + + static composeResource(resource, connection) { + if (Codec.isLocalResource(resource, connection)) + return BL().addUint32(resource.id); + else { + return BL().addUint8Array(resource.instance.template.classId.value).addUint32(resource.instance.id); + } + } + + static compareResource(previous, next, connection) { + if (next == null) + return ResourceComparisonResult.Null; + + if (next == previous) + return ResourceComparisonResult.Same; + + if (Codec.isLocalResource(next, connection)) + return ResourceComparisonResult.Local; + + if (previous == null) + return ResourceComparisonResult.Distributed; + + if (previous.instance.template.classId.valueOf() == next.instance.template.classId.valueOf()) + return ResourceComparisonResult.DistributedSameClass; + + return ResourceComparisonResult.Distributed; + } + + static composeResourceArray(resources, connection, prependLength = false) { + if (resources == null || resources.length == 0 || !(resources instanceof ResourceArray)) + return new DC(0); + + var rt = new BinaryList(); + var comparsion = Codec.compareResource(null, resources[0], connection); + + rt.addUint8(comparsion); + + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32(resources[0].id); + else if (comparsion == ResourceComparisonResult.Distributed) { + rt.addUint8Array(resources[0].instance.template.classId.value); + rt.addUint32(resources[0].instance.id); + } + + for (var i = 1; i < resources.length; i++) { + comparsion = Codec.compareResource(resources[i - 1], resources[i], connection); + rt.addUint8(comparsion); + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32(resources[0].id); + else if (comparsion == ResourceComparisonResult.Distributed) { + rt.addUint8Array(resources[0].instance.template.classId.value); + rt.addUint32(resources[0].instance.id); + } + else if (comparsion == ResourceComparisonResult.DistributedSameClass) { + rt.addUint32(resources[0].instance.id); + } + } + + if (prependLength) + rt.addUint32(0, rt.length); + + return rt.toArray(); + } + + + +static getDataType(value) { + switch (typeof value) { + case "number": + // float or ? + if (Math.floor(value) == value) { + if (value > 0) { + // larger than byte ? + if (value > 0xFF) { + // larger than short ? + if (value > 0xFFFF) { + // larger than int ? + if (value > 0xFFFFFFFF) { + return DataType.UInt64; + } + else { + return DataType.UInt32; + } + } + else { + return DataType.UInt16; + } + } + else { + return DataType.UInt8; + } + } + else { + if (value < -128) { + if (value < -32768) { + if (value < -2147483648) { + return DataType.Int64; + } + else { + return DataType.Int32; + } + } + else { + return DataType.Int16; + } + } + else { + return DataType.Int8; + } + } + } + else { + // float or double + return DataType.Float64; + } + break; + + case "string": + return DataType.String; + case "boolean": + return DataType.Bool; + case "object": + if (value instanceof Array) { + return DataType.VarArray; + } + else if (value instanceof IResource) { + return Codec.isLocalResource(value, connection) ? DataType.Resource : DataType.DistributedResource; + } + else if (value instanceof Date) { + return DataType.DateTime; + } + else if (value instanceof Uint8Array + || value instanceof ArrayBuffer) { + return DataType.UInt8Array; + } + else if (value instanceof Number) { + // JS numbers are always 64-bit float + return DataType.Float64; + } + else if (value instanceof Structure) { + return DataType.Structure; + } + else { + return DataType.Void + } + + break; + + default: + return DataType.Void; + } + } +} \ No newline at end of file diff --git a/src/DataConverter.js b/src/DataConverter.js new file mode 100644 index 0000000..a884a0b --- /dev/null +++ b/src/DataConverter.js @@ -0,0 +1,490 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var UNIX_EPOCH = 621355968000000000; +var TWO_PWR_32 = (1 << 16) * (1 << 16); + +class DC extends Uint8Array// extends DataView // Data Converter +{ + constructor(bufferOrSize) { + super(bufferOrSize); + + //if (bufferOrSize instanceof ArrayBuffer) { + // this.buffer = bufferOrSize; + //} + //else + //{ + // this.buffer = new Uint8Array(bufferOrSize); + //} + + this.dv = new DataView(this.buffer); + } + + + static boolToBytes(value) + { + var rt = new DC(1); + rt.setBoolean(0, value); + return rt; + } + + static int8ToBytes(value) + { + var rt = new DC(1); + rt.setInt8(0, value); + return rt; + } + + static hexToBytes(value) + { + // convert hex to Uint8Array + var rt = new DC(value.length/2); + for(var i = 0; i < ar.length; i++) + rt[i] = parseInt(value.substr(i*2, 2), 16); + return rt; + } + + static uint8ToBytes(value) + { + var rt = new DC(1); + rt.setUint8(0, value); + return rt; + } + + static charToBytes(value) + { + var rt = new DC(2); + rt.setChar(0, value); + return rt; + } + + static int16ToBytes(value) + { + var rt = new DC(2); + rt.setInt16(0, value); + return rt; + } + + static uint16ToBytes(value) + { + var rt = new DC(2); + rt.setUint16(0, value); + return rt; + } + + static int32ToBytes(value) + { + var rt = new DC(4); + rt.setInt32(0, value); + return rt; + } + + static uint32ToBytes(value) + { + var rt = new DC(4); + rt.setUint32(0, value); + return rt; + } + + static float32ToBytes(value) + { + var rt = new DC(4); + rt.setFloat32(0, value); + return rt; + } + + static int64ToBytes(value) + { + var rt = new DC(8); + rt.setInt64(0, value); + return rt; + } + + static uint64ToBytes(value) + { + var rt = new DC(8); + rt.setUint64(0, value); + return rt; + } + + static float64ToBytes(value) + { + var rt = new DC(8); + rt.setFloat64(0, value); + return rt; + } + + static dateTimeToBytes(value) + { + var rt = new DC(8); + rt.setDateTime(0, value); + return rt; + } + + static stringToBytes(value) + { + var utf8 = unescape(encodeURIComponent(value)); + var rt = []; + + for (var i = 0; i < utf8.length; i++) + rt.push(utf8.charCodeAt(i)); + + return new DC(rt); + } + + + + append(src, offset, length) + { + if (!(src instanceof DC)) + src = new DC(src); + + var appendix = src.clip(offset, length); + var rt = new DC(this.length + appendix.length); + rt.set(this, 0); + rt.set(appendix, this.length); + return rt; + } + + static combine(a, aOffset, aLength, b, bOffset, bLength) + { + if (!(a instanceof DC)) + a = new DC(a); + if (!(b instanceof DC)) + b = new DC(b); + + a = a.clip(aOffset, aLength); + b = b.clip(bOffset, bLength); + + var rt = new DC(a.length + b.length); + rt.set(a, 0); + rt.set(b, a.length); + return rt; + } + + clip(offset, length) + { + return this.slice(offset, offset+length); + } + + getInt8(offset) + { + return this.dv.getUint8(offset); + } + + getUint8(offset) + { + return this[offset];// this.dv.getUint8(offset); + } + + getInt16(offset) + { + return this.dv.getInt16(offset); + } + + getUint16(offset) + { + return this.dv.getUint16(offset); + } + + getInt32(offset) + { + return this.dv.getInt32(offset); + } + + getUint32(offset) + { + return this.dv.getUint32(offset); + } + + getFloat32(offset) + { + return this.dv.getFloat32(offset); + } + + getFloat64(offset) + { + return this.dv.getFloat64(offset); + } + + setInt8(offset, value) + { + return this.dv.setInt8(offset, value); + } + + setUint8(offset, value) + { + return this.dv.setUint8(offset, value); + } + + setInt16(offset, value) + { + return this.dv.setInt16(offset, value); + } + + setUint16(offset, value) + { + return this.dv.setUint16(offset, value); + } + + setInt32(offset, value) + { + return this.dv.setInt32(offset, value); + } + + setUint32(offset, value) + { + return this.dv.setUint32(offset, value); + } + + setFloat32(offset, value) + { + return this.dv.setFloat32(offset, value); + } + + setFloat64(offset, value) + { + return this.dv.setFloat64(offset, value); + } + + getInt8Array(offset, length) + { + return new Int8Array(this.buffer, offset, length); + } + + getUint8Array(offset, length) + { + return new Uint8Array(this.buffer, offset, length); + } + + getInt16Array(offset, length) + { + return new Int16Array(this.buffer, offset, length); + } + + getUint16Array(offset, length) + { + return new Uint16Array(this.buffer, offset, length); + } + + getInt32Array(offset, length) + { + return new Int32Array(this.buffer, offset, length); + } + + getUint32Array(offset, length) + { + return new Uint32Array(this.buffer, offset, length); + } + + getFloat32Array(offset, length) + { + return new Float32Array(this.buffer, offset, length); + } + + getFloat64Array(offset, length) + { + return new Float64Array(this.buffer, offset, length); + } + + getInt64Array(offset, length) + { + return new Int64Array(this.buffer, offset, length); + } + + + getUint64Array(offset, length) + { + return new Uint64Array(this.buffer, offset, length); + } + + getBoolean(offset) + { + return this.getUint8(offset) > 0; + } + + setBoolean(offset, value) + { + this.setUint8(offset, value ? 1: 0); + } + + getBooleanArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i++) + rt.push(this.getBoolean(offset+i)); + return rt; + } + + getChar(offset) + { + return String.fromCharCode(this.getUint16(offset)); + } + + setChar(offset, value) + { + this.setUint16(offset, value.charCodeAt(0)); + } + + getCharArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i+=2) + rt.push(this.getChar(offset+i)); + return rt; + } + + getHex(offset, length) + { + var rt = ""; + for(var i = offset; i < offset + length; i++) { + var h = this[i].toString(16); + rt += h.length == 1 ? "0" + h : h; + } + + return rt; + } + + getString(offset, length) + { + if (typeof StringView != "undefined") + return new StringView(this.buffer, "UTF-8", offset, length); + else + { + var bytes = this.getUint8Array(offset, length); + var encodedString = String.fromCharCode.apply(null, bytes), + decodedString = decodeURIComponent(escape(encodedString)); + return decodedString; + } + } + + getStringArray(offset, length) + { + var rt = []; + var i = 0; + + while (i < length) + { + var cl = this.getUint32(offset + i); + i += 4; + rt.push(this.getString(offset + i, cl)); + i += cl; + } + + return rt; + } + + getInt64(offset) + { + var h = this.getInt32(offset); + var l = this.getInt32(offset + 4); + + return h * TWO_PWR_32 + ((l >= 0) ? l : TWO_PWR_32 + l); + } + + getUint64(offset) + { + var h = this.getUint32(offset); + var l = this.getUint32(offset + 4); + return h * TWO_PWR_32 + ((l >= 0) ? l : TWO_PWR_32 + l); + } + + setInt64(offset, value) + { + var l = (value % TWO_PWR_32) | 0; + var h = (value / TWO_PWR_32) | 0; + this.setInt32(offset, h); + this.setInt32(offset + 4, l); + } + + setUint64(offset, value) + { + var l = (value % TWO_PWR_32) | 0; + var h = (value / TWO_PWR_32) | 0; + this.setInt32(offset, h); + this.setInt32(offset + 4, l); + } + + setDateTime(offset, value) + { + // Unix Epoch + var ticks = 621355968000000000 + (value.getTime() * 10000); + this.setUint64(offset, ticks); + } + + getDateTime(offset) + { + var ticks = this.getUint64(offset); + return new Date(Math.round((ticks-DCStatic.UNIX_EPOCH)/10000)); + } + + getDateTimeArray(offset) + { + var rt = []; + for(var i = 0; i < length; i+=8) + rt.push(this.getDateTime(offset+i)); + return rt; + } + + getGuid(offset) + { + return new Guid(this.getUint8Array(offset, 16)); + + /* + var d = this.getUint8Array(offset, 16); + var rt = ""; + for (var i = 0; i < 16; i++) { + rt += String.fromCharCode(d[i]); + } + + return btoa(rt); + */ + } + + getGuidArray(offset, length) + { + var rt = []; + for(var i = 0; i < length; i+=16) + rt.push(this.getGuid(offset+i)); + return rt; + } + + sequenceEqual(ar) + { + if (ar.length != this.length) + return false; + else + { + for(var i = 0; i < this.length; i++) + if (ar[i] != this[i]) + return false; + } + + return true; + } +} + + diff --git a/src/DataType.js b/src/DataType.js new file mode 100644 index 0000000..28c51ba --- /dev/null +++ b/src/DataType.js @@ -0,0 +1,110 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +DataType = { + Void: 0x0, + //Variant, + Bool: 1, + Int8: 2, + UInt8: 3, + Char: 4, + Int16: 5, + UInt16: 6, + Int32: 7, + UInt32: 8, + Int64: 9, + UInt64: 10, + Float32: 11, + Float64: 12, + Decimal: 13, + DateTime: 14, + Resource: 15, + DistributedResource: 16, + ResourceLink: 17, + String: 18, + Structure: 19, + //Stream, + //Array = 0x80, + VarArray: 0x80, + BoolArray: 0x81, + UInt8Array: 0x82, + Int8Array: 0x83, + CharArray: 0x84, + Int16Array: 0x85, + UInt16Array: 0x86, + Int32Array: 0x87, + UInt32Array: 0x88, + Int64Array: 0x89, + UInt64Array: 0x8A, + Float32Array: 0x8B, + Float64Array: 0x8C, + DecimalArray: 0x8D, + DateTimeArray: 0x8E, + ResourceArray: 0x8F, + DistributedResourceArray: 0x90, + ResourceLinkArray: 0x91, + StringArray: 0x92, + StructureArray: 0x93, + NotModified: 0x7f, + Unspecified: 0xff, + + isArray: function(type) + { + return ((type & 0x80) == 0x80) && (type != DataType.NotModified); + }, + + sizeOf: function(type) + { + switch (type) + { + case DataType.Void: + case DataType.NotModified: + return 0; + case DataType.Bool: + case DataType.Int8: + case DataType.UInt8: + return 1; + case DataType.Char: + case DataType.Int16: + case DataType.UInt16: + return 2; + case DataType.Int32: + case DataType.UInt32: + case DataType.Float32: + case DataType.Resource: + return 4; + case DataType.Int64: + case DataType.UInt64: + case DataType.Float64: + case DataType.DateTime: + return 8; + case DataType.DistributedResource: + return 4; + + default: + return -1; + } + } +}; diff --git a/src/DistributedConnection.js b/src/DistributedConnection.js new file mode 100644 index 0000000..954dae2 --- /dev/null +++ b/src/DistributedConnection.js @@ -0,0 +1,860 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var AuthenticationType = +{ + Host: 0, + CoHost: 1, + Client: 2, + Alien: 3 +}; + +class DistributedConnection extends IStore { + + send(data) { + this.socket.send(data.buffer); + } + + sendParams() { + return new SendList(this); + } + + constructor(url, domain, username, password, checkInterval = 30, connectionTimeout = 600, revivingTime = 120) { + + super(); + + //Instance.Name = Global.GenerateCode(12); + this.hostType = AuthenticationType.Client; + this.domain = domain; + this.localUsername = username; + this.localPassword = DC.stringToBytes(password); + + this.socket = new WebSocket(url, "iip"); + this.socket.binaryType = "arraybuffer"; + this.socket.connection = this; + this.socket.networkBuffer = new NetworkBuffer(); + + this.debug = false; + this.totalReceived = 0; + this.totalSent = 0; + + this.checkInterval = checkInterval * 1000; // check every 30 seconds + this.connectionTimeout = connectionTimeout * 1000; // 10 minutes (4 pings failed) + this.revivingTime = revivingTime * 1000; // 2 minutes + this.lastAction = Date.now(); + + this.packet = new IIPPacket(); + this.authPacket = new IIPAuthPacket(); + + this.resources = {}; + this.templates = {}; + this.requests = {}; + this.pathRequests = {}; + this.templateRequests = {}; + this.resourceRequests = {}; + this.callbackCounter = 0; + + this.queue = new AsyncQueue(); + + this.queue.then(function (x) { + if (x.type == DistributedResourceQueueItemType.Event) { + x.resource._emitEventByIndex(x.index, x.value); + } + else { + x.resource._updatePropertyByIndex(x.index, x.value); + } + }); + + this.localNonce = new Uint8Array(32); + window.crypto.getRandomValues(this.localNonce); + + // declare (Credentials -> No Auth, No Enctypt) + var un = DC.stringToBytes(username); + var dmn = DC.stringToBytes(domain); + var self = this; + + this.socket.onopen = function () { + var bl = new BinaryList(); + bl.addUint8(0x60).addUint8(dmn.length).addUint8Array(dmn).addUint8Array(self.localNonce).addUint8(un.length).addUint8Array(un); + self.send(bl.toArray()); + }; + + this.socket.onmessage = function (msg) { + + //console.log(msg); + + this.networkBuffer.writeAll(msg.data); + + self.lastAction = new Date(); + + while (this.networkBuffer.available > 0 && !this.networkBuffer.protected) + self.receive(this.networkBuffer); + + + }; + } + + + receive(data) { + var msg = data.read(); + var offset = 0; + var ends = msg.length; + var packet = this.packet; + var authPacket = this.authPacket; + + //console.log("Data"); + + while (offset < ends) { + + if (this.ready) { + var rt = packet.parse(msg, offset, ends); + if (rt <= 0) { + data.holdFor(msg, offset, ends - offset, -rt); + return; + } + else { + offset += rt; + + if (packet.command == IIPPacketCommand.Event) { + switch (packet.event) { + case IIPPacketEvent.ResourceReassigned: + this.IIPEventResourceReassigned(packet.resourceId, packet.newResourceId); + break; + case IIPPacketEvent.ResourceDestroyed: + this.IIPEventResourceDestroyed(packet.resourceId); + break; + case IIPPacketEvent.PropertyUpdated: + this.IIPEventPropertyUpdated(packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketEvent.EventOccured: + this.IIPEventEventOccured(packet.resourceId, packet.methodIndex, packet.content); + break; + } + } + else if (packet.command == IIPPacketCommand.Request) { + switch (packet.action) { + case IIPPacketAction.AttachResource: + this.IIPRequestAttachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ReattachResource: + this.IIPRequestReattachResource(packet.callbackId, packet.resourceId, packet.resourceAge); + break; + case IIPPacketAction.DetachResource: + this.IIPRequestDetachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.CreateResource: + this.IIPRequestCreateResource(packet.callbackId, packet.className); + break; + case IIPPacketAction.DeleteResource: + this.IIPRequestDeleteResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.TemplateFromClassName: + this.IIPRequestTemplateFromClassName(packet.callbackId, packet.className); + break; + case IIPPacketAction.TemplateFromClassId: + this.IIPRequestTemplateFromClassId(packet.callbackId, packet.classId); + break; + case IIPPacketAction.TemplateFromResourceLink: + this.IIPRequestTemplateFromResourceLink(packet.callbackId, packet.resourceLink); + break; + case IIPPacketAction.TemplateFromResourceId: + this.IIPRequestTemplateFromResourceId(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ResourceIdFromResourceLink: + this.IIPRequestResourceIdFromResourceLink(packet.callbackId, packet.resourceLink); + break; + case IIPPacketAction.InvokeFunction: + this.IIPRequestInvokeFunction(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketAction.GetProperty: + this.IIPRequestGetProperty(packet.callbackId, packet.resourceId, packet.methodIndex); + break; + case IIPPacketAction.GetPropertyIfModified: + this.IIPRequestGetPropertyIfModifiedSince(packet.callbackId, packet.resourceId, packet.methodIndex, packet.resourceAge); + break; + case IIPPacketAction.SetProperty: + this.IIPRequestSetProperty(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); + break; + } + } + else if (packet.command == IIPPacketCommand.Reply) { + switch (packet.action) { + case IIPPacketAction.AttachResource: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceAge, packet.resourceLink, packet.content); + break; + case IIPPacketAction.ReattachResource: + this.IIPReply(packet.callbackId, packet.resourceAge, packet.content); + break; + case IIPPacketAction.DetachResource: + this.IIPReply(packet.callbackId); + break; + case IIPPacketAction.CreateResource: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceId); + break; + case IIPPacketAction.DeleteResource: + this.IIPReply(packet.callbackId); + break; + case IIPPacketAction.TemplateFromClassName: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromClassId: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromResourceLink: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.TemplateFromResourceId: + this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content)); + break; + case IIPPacketAction.ResourceIdFromResourceLink: + this.IIPReply(packet.callbackId, packet.classId, packet.resourceId, packet.resourceAge); + break; + case IIPPacketAction.InvokeFunction: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.GetProperty: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.GetPropertyIfModified: + this.IIPReply(packet.callbackId, packet.content); + break; + case IIPPacketAction.SetProperty: + this.IIPReply(packet.callbackId); + break; + } + + } + + } + } + + else { + var rt = authPacket.parse(msg, offset, ends); + + + if (rt <= 0) { + data.holdAllFor(msg, ends - rt); + return; + } + else { + offset += rt; + + if (this.hostType == AuthenticationType.Host) { + if (authPacket.command == IIPAuthPacketCommand.Declare) { + if (authPacket.remoteMethod == IIPAuthPacketMethod.credentials + && authPacket.localMethod == IIPAuthPacketMethod.None) { + this.remoteUsername = authPacket.remoteUsername; + this.remoteNonce = authPacket.remoteNonce; + this.domain = authPacket.domain; + this.sendParams().addUint8(0xa0).addUint8Array(this.localNonce).done(); + } + } + else if (authPacket.command == IIPAuthPacketCommand.Action) { + if (authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + var remoteHash = authPacket.hash; + + this.server.membership.getPassword(this.remoteUsername, this.domain).then(function (pw) { + if (pw != null) { + + var hash = new DC(sha256.arrayBuffer(BL().addString(pw).addUint8Array(remoteNonce).addUint8Array(this.localNonce).toArray())); + + + if (hash.sequenceEqual(remoteHash)) { + // send our hash + var localHash = new DC(sha256.arrayBuffer((new BinaryList()).addUint8Array(this.localNonce).addUint8Array(remoteNonce).addUint8Array(pw).toArray())); + this.sendParams().addUint8(0).addUint8Array(localHash).done(); + + this.readyToEstablish = true; + } + else { + // incorrect password + this.sendParams().addUint8(0xc0).addInt32(1).addUint16(5).addString("Error").done(); + } + } + }); + } + else if (authPacket.action == IIPAuthPacketAction.NewConnection) { + if (readyToEstablish) { + this.sessionId = new DC(32); + window.crypto.getRandomValues(this.sessionId); + + this.sendParams().addUint8(0x28).addUint8Array(this.sessionId).done(); + this.ready = true; + this._emit("ready", this); + } + } + } + } + else if (this.hostType == AuthenticationType.Client) { + if (authPacket.command == IIPAuthPacketCommand.Acknowledge) { + this.remoteNonce = authPacket.remoteNonce; + + // send our hash + + var localHash = new DC(sha256.arrayBuffer(BL().addUint8Array(this.localPassword) + .addUint8Array(this.localNonce) + .addUint8Array(this.remoteNonce).toArray())); + this.sendParams().addUint8(0).addUint8Array(localHash).done(); + } + else if (authPacket.command == IIPAuthPacketCommand.Action) { + if (authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + // check if the server knows my password + var remoteHash = new DC(sha256.arrayBuffer(BL().addUint8Array(this.remoteNonce) + .addUint8Array(this.localNonce) + .addUint8Array(this.localPassword).toArray() + )); + + if (remoteHash.sequenceEqual(authPacket.hash)) { + // send establish request + this.sendParams().addUint8(0x20).addUint16(0).done(); + } + else { + this.sendParams().addUint8(0xc0).addUint32(1).addUint16(5).addString("Error").done(); + } + } + else if (authPacket.action == IIPAuthPacketAction.ConnectionEstablished) { + this.sessionId = authPacket.sessionId; + this.ready = true; + this._emit("ready", this); + } + } + else if (authPacket.command == IIPAuthPacketCommand.Error) + { + this._emit("error", this, authPacket.errorCode, authPacket.errorMessage); + this.close(); + } + } + } + } + } + + } + + close() + { + this.socket.close(); + } + + trigger(trigger) { + return true; + } + + put(resource) { + this.resources[parseInt(resource.instance.name)] = resource; + return true; + } + + + // Protocol Implementation + + sendRequest(action, binaryList) { + var reply = new AsyncReply(); + this.callbackCounter++; + this.sendParams().addUint8(0x40 | action).addUint32(this.callbackCounter).addRange(binaryList).done(); + this.requests[this.callbackCounter] = reply; + return reply; + } + + IIPReply(callbackId) { + var results = Array.prototype.slice.call(arguments, 1); + var req = this.requests[callbackId]; + delete this.requests[callbackId]; + req.trigger(results); + } + + IIPEventResourceReassigned(resourceId, newResourceId) { + + } + + IIPEventResourceDestroyed(resourceId) { + if (this.resources[resourceId]) { + var r = this.resources[resourceId]; + delete this.resources[resourceId]; + r.destroy(); + } + } + + IIPEventPropertyUpdated(resourceId, index, content) { + if (this.resources[resourceId]) { + // push to the queue to gaurantee serialization + var reply = new AsyncReply(); + this.queue.add(reply); + + var r = this.resources[resourceId]; + Codec.parse(content, 0, this).then(function (args) { + var pt = r._p.template.getPropertyTemplateByIndex(index); + if (pt != null) { + reply.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Propery, args, index)); + } + else { // ft found, fi not found, this should never happen + this.queue.remove(reply); + } + }); + } + } + + + IIPEventEventOccured(resourceId, index, content) { + if (this.resources[resourceId]) { + // push to the queue to guarantee serialization + var reply = new AsyncReply(); + var r = this.resources[resourceId]; + + this.queue.add(reply); + + Codec.parseVarArray(content, 0, content.length, this).then(function (args) { + var et = r._p.template.getEventTemplateByIndex(index); + if (et != null) { + reply.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Event, args, index)); + } + else { // ft found, fi not found, this should never happen + this.queue.remove(reply); + } + }); + } + } + + IIPRequestAttachResource(callback, resourceId) { + + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + r.instance.on("ResourceEventOccured", this.instance_eventOccured); + r.instance.on("ResourceModified", this.instance_propertyModified); + r.instance.on("ResourceDestroyed", this.instance_resourceDestroyed); + // reply ok + + var link = DC.stringToBytes(r.instance.link); + + sl.addUint8(0x80) + .addUint32(callback) + .addUint8Array(r.instance.template.classId.value) + .addUint32(r.instance.age) + .addUint16(link.length) + .addUint8Array(link) + .addUint8Array(Codec.composeVarArray(r.instance.serialize(), this, true)) + .done(); + } + else { + // reply failed + //SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this)); + } + }); + } + + IIPRequestReattachResource(callback, resourceId, resourceAge) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (res != null) { + r.instance.on("ResourceEventOccured", this.instance_eventOccured); + r.instance.on("ResourceModified", this.instance_propertyModified); + r.instance.on("ResourceDestroyed", this.instance_resourceDestroyed); + // reply ok + sl.addUint8(0x81) + .addUint32(callback) + .addUint32(r.instance.age) + .addUint8Array(Codec.composeVarArray(r.instance.serialize(), this, true)) + .done(); + } + else { + // reply failed + } + }); + } + + IIPRequestDetachResource(callback, resourceId) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + r.instance.off("ResourceEventOccured", this.instance_eventOccured); + r.instance.off("ResourceModified", this.instance_propertyModified); + r.instance.off("ResourceDestroyed", this.instance_resourceDestroyed); + + // reply ok + sl.addUint8(0x82).addUint32(callback).done(); + } + else { + // reply failed + } + }); + } + + IIPRequestCreateResource(callback, className) { + // not implemented + } + + IIPRequestDeleteResource(callback, resourceId) { + // not implemented + } + + IIPRequestTemplateFromClassName(callback, className) { + var sl = this.sendParams(); + + Warehouse.getTemplateByClassName(className).then(function (t) { + if (t != null) + sl.addUint8(0x88).addUint32(callback).addUint8Array(t.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromClassId(callback, classId) { + var sl = this.sendParams(); + + Warehouse.getTemplateByClassId(classId).then(function (t) { + if (t != null) + sl.addUint8(0x89) + .addUint32(callback) + .addUint32(t.content.length) + .addUint8Array(t.content) + .done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromResourceLink(callback, resourceLink) { + var sl = this.sendParams(); + + Warehouse.getTemplate(resourceLink).then(function (t) { + if (t != null) + sl.addUint8(0x8a).addUint32(callback).addUint8Array(t.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestTemplateFromResourceId(callback, resourceId) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) + sl.addUint8(0x8b).addUint32(callback).addUint8Array(r.instance.template.content).done(); + else { + // reply failed + } + }); + } + + IIPRequestResourceIdFromResourceLink(callback, resourceLink) { + + var sl = this.sendParams(); + + Warehouse.get(resourceLink).then(function (r) { + if (r != null) + sl.addUint8(0x8c) + .addUint32(callback) + .addUint8Array(r.instance.template.classId.value) + .addUint32(r.instance.id) + .addUint32(r.instance.age).done(); + else { + // reply failed + } + }); + } + + IIPRequestInvokeFunction(callback, resourceId, index, content) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + Codec.parseVarArray(content, 0, content.length, sl.connection).then(function (args) { + var ft = r.instance.template.getFunctionTemplateByIndex(index); + if (ft != null) { + if (r instanceof DistributedResource) { + var rt = r._invoke(index, args); + if (rt != null) { + rt.then(function (res) { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(res, sl.connection)).done(); + }); + } + else { + // function not found on a distributed object + } + } + else { + + var fi = r[ft.name]; + if (fi instanceof Function) { + args.push(sl.connection); + + var rt = fi.apply(r, args); + + + if (rt instanceof AsyncReply) { + rt.then(function (res) { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(res, sl.connection)).done(); + }); + } + else { + sl.addUint8(0x90).addUint32(callback).addUint8Array(Codec.compose(rt, sl.connection)).done(); + } + } + else { + // ft found, fi not found, this should never happen + } + } + } + else { + // no function at this index + } + }); + } + else { + // no resource with this id + } + }); + } + + IIPRequestGetProperty(callback, resourceId, index) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + var pt = r.instance.template.getFunctionTemplateByIndex(index); + if (pt != null) { + if (r instanceof DistributedResource) { + sl.addUint8(0x91).addUint32(callback).addUint8Array(Codec.compose(r._get(pt.index), sl.connection)).done(); + } + else { + var pv = r[pt.name]; + sl.addUint8(0x91).addUint32(callback).addUint8Array(Codec.compose(pv, sl.connection)).done(); + } + } + else { + // pt not found + } + } + else { + // resource not found + } + }); + } + + IIPRequestGetPropertyIfModifiedSince(callback, resourceId, index, age) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + var pt = r.instance.template.getFunctionTemplateByIndex(index); + if (pt != null) { + if (r.instance.getAge(index) > age) { + var pv = r[pt.name]; + sl.addUint8(0x92).addUint32(callback).addUint8Array(Codec.compose(pv, sl.connection)).done(); + } + else { + sl.addUint8(0x92).addUint32(callback).addUint8(DataType.NotModified).done(); + } + } + else { + // pt not found + } + } + else { + // resource not found + } + }); + } + + IIPRequestSetProperty(callback, resourceId, index, content) { + var sl = this.sendParams(); + + Warehouse.get(resourceId).then(function (r) { + if (r != null) { + + + var pt = r.instance.template.getPropertyTemplateByIndex(index); + if (pt != null) { + Codec.parse(content, 0, this).then(function (value) { + if (r instanceof DistributedResource) { + // propagation + r._set(index, value).then(function (x) { + sl.addUint8(0x93).addUint32(callback).done(); + }); + } + else { + r[pt.name] = value; + sl.addUint8(0x93).addUint32(callback).done(); + } + + }); + } + else { + // property not found + } + } + else { + // resource not found + } + }); + } + + + getTemplate(classId) { + if (this.templates[classId]) + return new AsyncReply(this.templates[classId]); + else if (this.templateRequests[classId]) + return this.templateRequests[classId]; + + var reply = new AsyncReply(); + this.templateRequests[classId] = reply; + + var self = this; + + this.sendRequest(IIPPacketAction.TemplateFromClassId, BL().addUint8Array(classId.value)).then(function (rt) { + delete self.templateRequests[classId]; + self.templates[rt[0].classId] = rt[0]; + reply.trigger(rt[0]); + }); + + return reply; + } + +// IStore interface + get(path) { + if (this.pathRequests[path]) + return this.pathRequests[path]; + + var reply = new AsyncReply(); + this.pathRequests[path] = reply; + + var bl = new BinaryList(); + bl.addString(path); + bl.addUint16(bl.length, 0); + + var self = this; + + this.sendRequest(IIPPacketAction.ResourceIdFromResourceLink, bl).then(function (rt) { + delete self.pathRequests[path]; + + self.fetch(rt[1]).then(function (r) { + reply.trigger(r); + }); + }); + + + return reply; + } + + retrieve(iid) { + for (var r in this.resources) + if (this.resources[r].instance.id == iid) + return new AsyncReply(r); + return new AsyncReply(null); + } + +// Get a resource from the other end + fetch(id) { + if (this.resourceRequests[id] && this.resources[id]) { + // dig for dead locks + return this.resourceRequests[id]; + } + else if (this.resourceRequests[id]) + return this.resourceRequests[id]; + else if (this.resources[id]) + return new AsyncReply(this.resources[id]); + + var reply = new AsyncReply(); + + var self = this; + + this.sendRequest(IIPPacketAction.AttachResource, BL().addUint32(id)).then(function (rt) { + self.getTemplate(rt[0]).then(function (tmp) { + + var dr = new DistributedResource(self, tmp, id, rt[1], rt[2]); + Warehouse.put(dr, id.toString(), self); + + Codec.parseVarArray(rt[3], 0, rt[3].length, self).then(function (ar) { + dr._attached(ar); + delete self.resourceRequests[id]; + reply.trigger(dr); + }); + }); + }); + + return reply; + } + + instance_resourceDestroyed(resource) { + // compose the packet + this.sendParams().addUint8(0x1).addUint32(resource.instance.id).done(); + } + + instance_propertyModified(resource, name, newValue, oldValue) { + var pt = resource.instance.template.getPropertyTemplateByName(name); + + if (pt == null) + return; + + // compose the packet + if (newValue instanceof Function) + sendParams().addUint8(0x10) + .addUint32(resource.instance.id) + .addUint8(pt.index) + .addUint8Array(Codec.compose(newValue(this), this)) + .done(); + else + sendParams().addUint8(0x10) + .addUint32(resource.instance.id) + .addUint8(pt.index) + .addUint8Array(Codec.compose(newValue, this)) + .done(); + } + + instance_eventOccured(resource, name, receivers, args) { + var et = resource.instance.template.getEventTemplateByName(name); + + if (et == null) + return; + + if (receivers != null) + if (receivers.indexOf(this.remoteUsername) < 0) + return; + + var clientArgs = [];//new object[args.Length]; + for (var i = 0; i < args.Length; i++) + if (args[i] instanceof Function) + clientArgs[i] = args[i](this); + else + clientArgs[i] = args[i]; + + + // compose the packet + sendParams().addUint8(0x11) + .addUint32(resource.instance.id) + .addUint8(et.index) + .addUint8Array(Codec.composeVarArray(args, this, true)) + .done(); + + } + +} diff --git a/src/DistributedResource.js b/src/DistributedResource.js new file mode 100644 index 0000000..e85668e --- /dev/null +++ b/src/DistributedResource.js @@ -0,0 +1,180 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + + +class DistributedResource extends IResource +{ + destroy() + { + this.destroyed = true; + this._emit("destroy"); + } + + + + constructor(connection, template, instanceId, age) + { + super(); + + this._p = { + isAttached: false, + connection: connection, + instanceId: instanceId, + age: age, + template: template + }; + } + + _attached(properties) + { + + if (this._isAttached) + return false; + else + { + this._p.properties = properties; + this._p.ages = new Uint32Array(properties.length); + //this.events = [];//new [this.template.events.length]; + this._p.isAttached = true; + + var self = this; + + var makeFunc = function(index) + { + return function () { + return self._invoke(index, arguments); + }; + }; + + var makeGetter = function(index) + { + return function () { + return self._get(index); + }; + }; + + var makeSetter = function(index) + { + return function (value) { + self._set(index, value); + }; + }; + + for(var i = 0; i < this._p.template.functions.length; i++) + { + var ft = this._p.template.functions[i]; + this[ft.name] = makeFunc(ft.index); + } + + for(var i = 0; i < this._p.template.properties.length; i++) + { + var pt = this._p.template.properties[i]; + + Object.defineProperty(this, pt.name, { + get: makeGetter(pt.index), + set: makeSetter(pt.index), + enumerable: true, + configurable: true + }); + + } + } + return true; + } + + _emitEventByIndex(index, args) + { + var et = this._p.template.getEventTemplateByIndex(index); + this._emit(et.name, args); + this.instance.emitResourceEvent(et.name, null, args); + } + + _invoke(index, args) { + if (this.destroyed) + throw new Exception("Trying to access destroyed object"); + + if (index >= this._p.template.functions.length) + throw new Exception("Function index is incorrect"); + + var reply = new AsyncReply(); + + var parameters = Codec.composeVarArray(args, this._p.connection, true); + + var self = this; + + this._p.connection.sendRequest(IIPPacketAction.InvokeFunction, + BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)) + .then(function (res) { + Codec.parse(res[0], 0, self._p.connection).then(function (rt) { + reply.trigger(rt); + }); + }); + + + return reply; + + } + + + _get(index) + { + if (index >= this._p.properties.length) + return null; + return this._p.properties[index]; + } + + + + _updatePropertyByIndex(index, value) + { + var pt = this._p.template.getPropertyTemplateByIndex(index); + this._p.properties[index] = value; + this.instance.modified(pt.name, value); + } + + _set(index, value) + { + if (index >= this._p.properties.length) + return null; + + var reply = new AsyncReply(); + + var parameters = Codec.compose(value, this._p.connection); + var self = this; + + this._p.connection.sendRequest(IIPPacketAction.SetProperty, + BL().addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)) + .then(function(res) + { + // not really needed, server will always send property modified, this only happens if the programmer forgot to emit in property setter + //Update(index, value); + reply.trigger(null); + // nothing to do here + }); + + return reply; + } +} \ No newline at end of file diff --git a/src/DistributedResourceQueueItem.js b/src/DistributedResourceQueueItem.js new file mode 100644 index 0000000..5d7b922 --- /dev/null +++ b/src/DistributedResourceQueueItem.js @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var DistributedResourceQueueItemType = + { + Propery: 0, + Event: 1 + }; + +class DistributedResourceQueueItem { + constructor(resource, type, value, index) { + this.resource = resource; + this.index = index; + this.type = type; + this.value = value; + } +} + diff --git a/src/EventTemplate.js b/src/EventTemplate.js new file mode 100644 index 0000000..c31c3dc --- /dev/null +++ b/src/EventTemplate.js @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 24/08/2017. + */ + +class EventTemplate extends MemberTemplate +{ + + constructor() + { + super(); + this.type = MemberType.Event; + } + + compose() + { + var rt = new BinaryList(); + + var name = super.compose(); + if (this.expansion != null) { + var exp = DC.stringToBytes(this.expansion); + return rt.addUint8(0x50).addUint32(exp.length).addUint8Array(exp).addUint8(name.length).addUint8Array(name).toArray(); + } + else + return rt.addUint8(0x40).addUint32(name.length).addUint8Array(name).toArray(); + } + +} diff --git a/src/FunctionTemplate.js b/src/FunctionTemplate.js new file mode 100644 index 0000000..124203f --- /dev/null +++ b/src/FunctionTemplate.js @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 27/08/2017. + */ + +class FunctionTemplate extends MemberTemplate { + compose() { + var name = super.compose(); + var rt = new BinaryList(); + + if (this.expansion != null) { + var exp = DC.stringToBytes(this.expansion); + + return rt.addUint8(0x10 | (IsVoid ? 0x8 : 0x0)) + .addUint32(exp.length).addUint8Array(exp) + .addUint8(name.length).addUint8Array(name).toArray(); + } + else + return rt.addUint8(IsVoid ? 0x8 : 0x0).addUint8(name.length).addUint8Array(name).toArray(); + } + + + constructor() { + super(); + this.type = MemberType.Function; + } +} diff --git a/src/Guid.js b/src/Guid.js new file mode 100644 index 0000000..5104fac --- /dev/null +++ b/src/Guid.js @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 02/09/2017. + */ +class Guid +{ + constructor(dc) + { + this.value = dc; + } + + valueOf() + { + return this.value.getHex(0, 16); + } +} \ No newline at end of file diff --git a/src/IDestructible.js b/src/IDestructible.js new file mode 100644 index 0000000..58a46da --- /dev/null +++ b/src/IDestructible.js @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 31/08/2017. + */ +class IDestructible extends IEventHandler +{ + destroy() + { + this._emit("destroy", this); + } + + constructor() + { + super(); + } +} diff --git a/src/IEventHandler.js b/src/IEventHandler.js new file mode 100644 index 0000000..2379caf --- /dev/null +++ b/src/IEventHandler.js @@ -0,0 +1,78 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 30/08/2017. + */ + +class IEventHandler +{ + _register(event) + { + this._events[event] = []; + } + + constructor() + { + this._events = {}; + } + + _emit(event) + { + event = event.toLowerCase(); + var args = Array.prototype.slice.call(arguments, 1); + if (this._events[event]) + for(var i = 0; i < this._events[event].length; i++) + if (this._events[event][i].apply(this, args)) + return true; + + return false; + } + + on(event, fn) + { + event = event.toLowerCase(); + // add + if (!this._events[event]) + this._events[event] = []; + this._events[event].push(fn); + return this; + } + + off(event, fn) + { + event = event.toLocaleString(); + if (this._events[event]) + { + if (fn) + { + var index = this._events[event].indexOf(fn); + if (index > -1) + this._events[event].splice(index, 1); + } + else + { + this._events[event] = []; + } + } + } +} \ No newline at end of file diff --git a/src/IIPAuthPacket.js b/src/IIPAuthPacket.js new file mode 100644 index 0000000..8e2d7e0 --- /dev/null +++ b/src/IIPAuthPacket.js @@ -0,0 +1,264 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var IIPAuthPacketCommand = +{ + Action: 0, + Declare: 1, + Acknowledge: 2, + Error: 3 +}; + +var IIPAuthPacketAction = +{ + // Authenticate + AuthenticateHash: 0, + NewConnection: 0x20, + ResumeConnection: 0x21, + ConnectionEstablished: 0x28 +}; + + +var IIPAuthPacketMethod = +{ + None: 0, + Certificate: 1, + Credentials: 2, + Token: 3 +}; + +class IIPAuthPacket +{ + constructor() + { + this.command = 0; + this.action = 0; + this.errorCode = 0; + this.errorMessage = ""; + this.localMethod = 0; + this.sourceInfo = ""; + this.hash = ""; + this.sessionId = ""; + this.remoteMethod = 0; + this.domain = ""; + this.CertificateId = 0; + this.localUsername = ""; + this.remoteUsername = ""; + this.localPassword = ""; + this.remotePassword = ""; + this.localToken = []; + this.reemoteToken = []; + this.asymetricEncryptionKey = []; + this.localNonce = []; + this.remoteNonce = []; + this.dataLengthNeeded = 0; + } + + notEnough(offset, ends, needed) + { + if (offset + needed > ends) + { + this.dataLengthNeeded = needed - (ends - offset); + return true; + } + else + return false; + } + + parse(data, offset, ends) + { + var oOffset = offset; + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.command = data.getUint8(offset) >> 6; + + if (this.command == IIPAuthPacketCommand.Action) + { + this.action = data[offset++] & 0x3f; + + if (this.action == IIPAuthPacketAction.AuthenticateHash) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.hash = data.getUint8Array(offset, 32); + + offset += 32; + } + else if (this.action == IIPAuthPacketAction.NewConnection) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var length = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, length)) + return -this.dataLengthNeeded; + + this.sourceInfo = data.clip(offset, length); + + offset += 32; + } + else if (this.action == IIPAuthPacketAction.ResumeConnection + || this.action == IIPAuthPacketAction.ConnectionEstablished) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.sessionId = data.clip(offset, 32); + + offset += 32; + } + } + else if (this.command == IIPAuthPacketCommand.Declare) + { + this.remoteMethod = ((data.getUint8(offset) >> 4) & 0x3); + this.localMethod = ((data.getUint8(offset) >> 2) & 0x3); + + var encrypt = ((data.getUint8(offset++) & 0x2) == 0x2); + + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var domainLength = data.getUint8(offset++); + if (this.notEnough(offset, ends, domainLength)) + return -this.dataLengthNeeded; + + this.domain = data.getString(offset, domainLength); + + offset += domainLength; + + + if (this.remoteMethod == IIPAuthPacketMethod.Credentials) + { + if (this.localMethod == IIPAuthPacketMethod.None) + { + if (this.notEnough(offset, ends, 33)) + return -this.dataLengthNeeded; + + this.remoteNonce = data.clip(offset, 32); + + offset += 32; + + var length = data.getUint8(offset++); + + if (this.notEnough(offset, ends, length)) + return -this.dataLengthNeeded; + + this.remoteUsername = data.getString(offset, length); + + + offset += length; + } + } + + if (encrypt) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var keyLength = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, keyLength)) + return -this.dataLengthNeeded; + + this.asymetricEncryptionKey = data.clip(offset, keyLength); + + offset += keyLength; + } + } + else if (this.command == IIPAuthPacketCommand.Acknowledge) + { + this.remoteMethod = (data.getUint8(offset) >> 4) & 0x3; + this.localMethod = (data.getUint8(offset) >> 2) & 0x3; + var encrypt = ((data.getUint8(offset++) & 0x2) == 0x2); + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + + if (this.remoteMethod == IIPAuthPacketMethod.Credentials) + { + if (this.localMethod == IIPAuthPacketMethod.None) + { + if (this.notEnough(offset, ends, 32)) + return -this.dataLengthNeeded; + + this.remoteNonce = data.clip(offset, 32); + + offset += 32; + + } + } + + if (encrypt) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var keyLength = data.getUint16(offset); + + offset += 2; + + if (this.notEnough(offset, ends, keyLength)) + return -this.dataLengthNeeded; + + this.asymetricEncryptionKey = data.clip(offset, keyLength); + + offset += keyLength; + } + } + else if (this.command == IIPAuthPacketCommand.Error) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + offset++; + this.errorCode = data.getUint8(offset++); + + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.errorMessage = data.getString(offset, cl); + offset += cl; + + } + + + return offset - oOffset; + + } +} diff --git a/src/IIPPacket.js b/src/IIPPacket.js new file mode 100644 index 0000000..40a6a67 --- /dev/null +++ b/src/IIPPacket.js @@ -0,0 +1,544 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + + +var IIPPacketCommand = +{ + Event: 0, + Request: 1, + Reply: 2, + Error: 3 +}; + +var IIPPacketEvent = +{ + // Event Manage + ResourceReassigned : 0, + ResourceDestroyed: 1, + + // Event Invoke + PropertyUpdated : 0x10, + EventOccured: 0x11 +}; + +var IIPPacketAction = +{ + // Request Manage + AttachResource: 0, + ReattachResource: 1, + DetachResource: 2, + CreateResource: 3, + DeleteResource: 4, + + // Request Inquire + TemplateFromClassName: 0x8, + TemplateFromClassId: 0x9, + TemplateFromResourceLink: 0xA, + TemplateFromResourceId: 0xB, + ResourceIdFromResourceLink: 0xC, + + // Request Invoke + InvokeFunction: 0x10, + GetProperty: 0x11, + GetPropertyIfModified: 0x12, + SetProperty: 0x13 +}; + + + + + +class IIPPacket +{ + constructor() + { + this.command = 0; + this.action = 0; + this.event = 0; + this.resourceId = 0; + this.newResourceId = 0; + this.resourceAge = 0; + this.content = []; + this.errorCode = 0; + this.errorMessage = ""; + this.className = ""; + this.resourceLink = ""; + this.classId = ""; + this.methodIndex = ""; + this.methodName = ""; + this.callbackId = 0; + this.dataLengthNeeded = 0; + } + + notEnough(offset, ends, needed) + { + if (offset + needed > ends) + { + this.dataLengthNeeded = needed - (ends - offset); + return true; + } + else + return false; + } + + parse(data, offset, ends) + { + var oOffset = offset; + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.command = (data.getUint8(offset) >> 6); + + if (this.command == IIPPacketCommand.Event) + { + this.event = (data.getUint8(offset++) & 0x3f); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else + { + this.action = (data.getUint8(offset++) & 0x3f); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.callbackId = data.getUint32(offset); + offset += 4; + } + + if (this.command == IIPPacketCommand.Event) + { + if (this.event == IIPPacketEvent.ResourceReassigned) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.newResourceId = data.getUint32( offset); + offset += 4; + + } + else if (this.event == IIPPacketEvent.ResourceDestroyed) + { + // nothing to parse + } + else if (this.event == IIPPacketEvent.PropertyUpdated) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + this.methodIndex = data[offset++]; + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 1, size + 1); + offset += size; + } + } + else if (this.event == IIPPacketEvent.EventOccured) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + this.methodIndex = data.getUint8(offset++); + + var cl = data.getUint32(offset); + offset += 4; + + this.content = data.clip(offset, cl); + offset += cl; + } + } + else if (this.command == IIPPacketCommand.Request) + { + if (this.action == IIPPacketAction.AttachResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.ReattachResource) + { + if (this.notEnough(offset, ends, 8)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.resourceAge = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.DetachResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.CreateResource) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var cl = data.getUint8(offset++); + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.className = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.DeleteResource) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.TemplateFromClassName) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var cl = data.getUint8(offset++); + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.className = data.getString(offset, cl); + offset += cl; + + } + else if (this.action == IIPPacketAction.TemplateFromClassId) + { + if (this.notEnough(offset, ends, 16)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + } + else if (this.action == IIPPacketAction.TemplateFromResourceLink) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.TemplateFromResourceId) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.ResourceIdFromResourceLink) + { + if (this.notEnough(offset, ends, 2)) + return -this.dataLengthNeeded; + + var cl = data.getUint16(offset); + offset += 2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.InvokeFunction) + { + if (this.notEnough(offset, ends, 9)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data.getUint8(offset++); + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + + } + else if (this.action == IIPPacketAction.GetProperty) + { + if (this.notEnough(offset, ends, 5)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data.getUint8(offset++); + + } + else if (this.action == IIPPacketAction.GetPropertyIfModified) + { + if (this.notEnough(offset, ends, 9)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data[offset++]; + + this.resourceAge = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.SetProperty) + { + if (this.notEnough(offset, ends, 6)) + return -this.dataLengthNeeded; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.methodIndex = data[offset++]; + + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset-5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset-1, size + 1); + offset += size; + } + } + } + else if (this.command == IIPPacketCommand.Reply) + { + if (this.action == IIPPacketAction.AttachResource + || this.action == IIPPacketAction.ReattachResource) + { + if (this.notEnough(offset, ends, 26)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + + this.resourceAge = data.getUint32(offset); + offset += 4; + + var cl = data.getUint16(offset); + offset+=2; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.resourceLink = data.getString(offset, cl); + offset += cl; + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.DetachResource) + { + // nothing to do + } + else if (this.action == IIPPacketAction.CreateResource) + { + if (this.notEnough(offset, ends, 20)) + return -this.dataLengthNeeded; + + this.classId = data.GetGuid(offset); + offset += 16; + + this.resourceId = data.getUint32(offset); + offset += 4; + + } + else if (this.action == IIPPacketAction.DetachResource) + { + // nothing to do + } + else if (this.action == IIPPacketAction.TemplateFromClassName + || this.action == IIPPacketAction.TemplateFromClassId + || this.action == IIPPacketAction.TemplateFromResourceLink + || this.action == IIPPacketAction.TemplateFromResourceId) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset, cl); + offset += cl; + } + else if (this.action == IIPPacketAction.ResourceIdFromResourceLink) + { + if (this.notEnough(offset, ends, 24)) + return -this.dataLengthNeeded; + + this.classId = data.getGuid(offset); + offset += 16; + + this.resourceId = data.getUint32(offset); + offset += 4; + + this.resourceAge = data.getUint32(offset); + offset += 4; + } + else if (this.action == IIPPacketAction.InvokeFunction + || this.action == IIPPacketAction.GetProperty + || this.action == IIPPacketAction.GetPropertyIfModified) + { + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + var dt = data.getUint8(offset++); + var size = DataType.sizeOf(dt); + + if (size < 0) + { + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 5, cl + 5); + offset += cl; + } + else + { + if (this.notEnough(offset, ends, size)) + return -this.dataLengthNeeded; + + this.content = data.clip(offset - 1, size + 1); + offset += size; + } + } + else if (this.action == IIPPacketAction.SetProperty) + { + // nothing to do + } + } + else if (this.command == IIPPacketCommand.Error) + { + // Error + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + this.callbackId = data.getUint32(offset); + + if (this.notEnough(offset, ends, 1)) + return -this.dataLengthNeeded; + + this.errorCode = data.getUint8(offset++); + + if (this.notEnough(offset, ends, 4)) + return -this.dataLengthNeeded; + + var cl = data.getUint32(offset); + offset += 4; + + if (this.notEnough(offset, ends, cl)) + return -this.dataLengthNeeded; + + this.errorMessage = data.getString(offset, cl); + offset += cl; + } + + return offset - oOffset; + } +} \ No newline at end of file diff --git a/src/IResource.js b/src/IResource.js new file mode 100644 index 0000000..bd009b0 --- /dev/null +++ b/src/IResource.js @@ -0,0 +1,59 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +var ResourceTrigger = +{ + Loaded : 0, + Initialize: 1, + Terminate: 2, + Configure: 3, + SystemInitialized: 4, + SystemTerminated: 5, + SystemReload: 6 +}; + +class IResource extends IDestructible +{ + trigger(trigger) + { + + } + + constructor() + { + super(); + } + + static getTemplate() + { + return { + namespace: "Esiur", + properties: [], + functions: [], + events: [] + } + } +} diff --git a/src/IStore.js b/src/IStore.js new file mode 100644 index 0000000..2b45765 --- /dev/null +++ b/src/IStore.js @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ + +class IStore extends IResource { + get(path) { + + } + + retrieve(iid) { + + } + + put(resource) { + + } + + constructor() + { + super(); + } +} diff --git a/src/Instance.js b/src/Instance.js new file mode 100644 index 0000000..5233d85 --- /dev/null +++ b/src/Instance.js @@ -0,0 +1,142 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 29/08/2017. + */ +class Instance extends IEventHandler +{ + + getAge(index) + { + if (index < this.ages.Count) + return this.ages[index]; + else + return 0; + } + + + deserialize(properties) + { + for(var i = 0; i < this.template.properties.length; i++) + this.resource[this.template.properties[i].name] = properties[i]; + return true; + } + + serialize() + { + var props = []; + + for (var i = 0; i < this.template.properties.length; i++) + props.push(this.resource[this.template.properties[i].name]); + + return props; + } + + isStorable() + { + return resource instanceof Storable; + } + + + modified(propertyName = null, newValue = null, oldValue = null) + { + if (propertyName == null) + propertyName = modified.caller.name; + + if (newValue == null) + { + var val = {}; + if (this.getPropertyValue(propertyName, val)) + super._emit("ResourceModified", this.resource, propertyName, val.value, oldValue); + } + else + super._emit("ResourceModified", this.resource, propertyName, newValue, oldValue); + } + + emitResourceEvent(name, receivers, args) + { + super._emit("ResourceEventOccured", this.resource, name, receivers, args); + } + + getPropertyValue(name, resultObject) + { + for (var i = 0; i < this.template.properties.length; i++) + if (this.template.properties[i].name == name) + { + resultObject.value = this.resource[name]; + return true; + } + + return false; + } + + + + constructor(id, name, resource, store) + { + super(); + + this.store = store; + this.resource = resource; + this.id = id; + this.name = name; + + this.children = new AutoList(); + this.parents = new AutoList(); + + var self = this; + + this.children.on("add", function(value){ + value.instance.parents.add(self.resource); + }); + + this.children.on("remove", function(value){ + value.instance.parents.remove(self.resource); + }); + + + this.resource.on("Destroy", function(sender){ + self._emit("ResourceDestroyed", sender); + }); + + this.template = Warehouse.getTemplateByType(this.resource.constructor); + + // set ages + this.ages = new Uint32Array(this.template.properties.length); + + + // connect events + var makeHandler = function(name, receivers, args) + { + return new function(receivers, args) + { + self.emitResourceEvent(name, receivers, args); + }; + }; + + for (var i = 0; i < this.template.events.length; i++) + this.resource.on(this.template.events[i].name, makeHandler(this.template.events[i].name)); + + } + +} diff --git a/src/MemberTemplate.js b/src/MemberTemplate.js new file mode 100644 index 0000000..e94bc21 --- /dev/null +++ b/src/MemberTemplate.js @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 24/08/2017. + */ + + +var MemberType = { + Function: 0, + Property: 1, + Event: 2 +}; + +class MemberTemplate { + compose() { + return DC.stringToBytes(this.name); + } +} \ No newline at end of file diff --git a/src/NetworkBuffer.js b/src/NetworkBuffer.js new file mode 100644 index 0000000..18e75dd --- /dev/null +++ b/src/NetworkBuffer.js @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 01/09/2017. + */ + +class NetworkBuffer { + constructor() { + this.neededDataLength = 0; + this.data = new DC(0); + } + + get protected() { + return this.neededDataLength > this.data.length; + } + + get available() { + + return this.data.length; + } + + holdAllForNextWrite(src) { + this.holdFor(src, src.length + 1); + } + + holdForNextWrite(src, offset, size) { + this.holdFor(src, offset, size, size + 1); + } + + + holdFor(src, offset, size, needed) { + if (size >= needed) + throw new Exception("Size >= Needed !"); + + this.data = DC.combine(src, offset, size, this.data, 0, this.data.length); + this.neededDataLength = needed; + } + + holdAllFor(src, needed) { + this.holdFor(src, 0, src.length, needed); + } + + protect(data, offset, needed) { + var dataLength = data.length - offset; + + // protection + if (dataLength < needed) { + this.holdFor(data, offset, dataLength, needed); + return true; + } + else + return false; + } + + writeAll(src) { + this.write(src, 0, src.length ? src.length : src.byteLength); + } + + write(src, offset, length) { + this.data = this.data.append(src, offset, length); + } + + get canRead() { + if (this.data.length == 0) + return false; + else if (this.data.length < this.neededDataLength) + return false; + return true; + } + + read() { + if (this.data.length == 0) + return null; + + var rt = null; + + if (this.neededDataLength == 0) { + rt = this.data; + this.data = new DC(0); + } + else { + if (this.data.length >= this.neededDataLength) { + rt = this.data; + this.data = new DC(0); + this.neededDataLength = 0; + return rt; + } + else { + return null; + } + } + + return rt; + } +} diff --git a/src/NotModified.js b/src/NotModified.js new file mode 100644 index 0000000..76bad0d --- /dev/null +++ b/src/NotModified.js @@ -0,0 +1,30 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class NotModified +{ + +} \ No newline at end of file diff --git a/src/PropertyTemplate.js b/src/PropertyTemplate.js new file mode 100644 index 0000000..b7cc79c --- /dev/null +++ b/src/PropertyTemplate.js @@ -0,0 +1,83 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 27/08/2017. + */ + +var PropertyPermission = { + Read: 1, + Write: 2, + ReadWrite: 3 +}; + + +class PropertyTemplate extends MemberTemplate +{ + + constructor() + { + super(); + this.type = MemberType.Property; + } + + compose() + { + var name = super.compose(); + var rt = new BinaryList(); + + if (this.writeExpansion != null && this.readExpansion != null) + { + var rexp = DC.stringToBytes(this.readExpansion); + var wexp = DC.stringToBytes(this.writeExpansion); + return rt.addUint8(0x38 | this.permission) + .addUint32(wexp.length) + .addUint8Array(wexp) + .addUint32(rexp.length) + .addUint8Array(rexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else if (this.writeExpansion != null) + { + var wexp = DC.stringToBytes(this.writeExpansion); + return rt.addUint8(0x30 | this.permission) + .addUint32(wexp.length) + .addUint8Array(wexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else if (this.readExpansion != null) + { + var rexp = DC.stringToBytes(this.readExpansion); + return rt.addUint8(0x28 | this.permission) + .addUint32(rexp.length) + .addUint8Array(rexp) + .addUint8(name.length) + .addUint8Array(name).toArray(); + } + else + return rt.addUint8(0x20 | this.permission) + .addUint32(name.length) + .addUint8Array(name).toArray(); + } +} diff --git a/src/ResourceArray.js b/src/ResourceArray.js new file mode 100644 index 0000000..fc358a9 --- /dev/null +++ b/src/ResourceArray.js @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class ResourceArray extends Array +{ + push(value) + { + if (value instanceof IResource) + super.push(value); + else + return; + } +} \ No newline at end of file diff --git a/src/ResourceTemplate.js b/src/ResourceTemplate.js new file mode 100644 index 0000000..c3e1344 --- /dev/null +++ b/src/ResourceTemplate.js @@ -0,0 +1,284 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +class ResourceTemplate { + + getMemberTemplate(member) { + if (member instanceof MethodInfo) + return this.getFunctionTemplate(member.name); + else if (member instanceof EventInfo) + return this.getEventTemplate(member.name); + else if (member instanceof PropertyInfo) + return this.getPropertyTemplate(member.name); + else + return null; + } + + getEventTemplateByName(eventName) { + for (var i = 0; i < this.events.length; i++) + if (this.events[i].name == eventName) + return this.events[i]; + return null; + } + + getEventTemplateByIndex(index) { + for (var i = 0; i < this.events.length; i++) + if (this.events[i].index == index) + return this.events[i]; + return null; + } + + getFunctionTemplateByName(functionName) { + for (var i = 0; i < this.functions.length; i++) + if (this.functions[i].name == functionName) + return this.functions[i]; + return null; + } + + getFunctionTemplateByIndex(index) { + for (var i = 0; i < this.functions.length; i++) + if (this.functions[i].index == index) + return this.functions[i]; + return null; + } + + getPropertyTemplateByName(propertyName) { + for (var i = 0; i < this.properties.length; i++) + if (this.properties[i].name == propertyName) + return this.properties[i]; + return null; + } + + getPropertyTemplateByIndex(index) { + for (var i = 0; i < this.properties.length; i++) + if (this.properties[i].index == index) + return this.properties[i]; + return null; + } + + + /* + + template: { + properties: [ + {name: 'size', read: null, write: null} + ], + functions: [ + + ], + events: [ + + ] + } + */ + + constructor(type) { + + + this.properties = []; + this.events = []; + this.functions = []; + this.members = []; + + if (type === undefined) + return; + + var template = type.getTemplate(); + + // set guid + this.className = template.namespace + "." + type.prototype.constructor.name; + + this.classId = (new DC(sha256.arrayBuffer(this.className))).getGuid(0); + + //byte currentIndex = 0; + + for (var i = 0; i < template.properties.length; i++) { + var pt = new PropertyTemplate(); + pt.name = template.properties[i].name; + pt.index = i; + pt.readExpansion = template.properties[i].read; + pt.writeExpansion = template.properties[i].write; + this.properties.push(pt); + } + + for (var i = 0; i < template.events.length; i++) { + var et = new EventTemplate(); + et.name = template.events[i].name; + et.index = i; + et.expansion = template.events[i].expansion; + this.events.push(et); + } + + for (var i = 0; i < template.functions.length; i++) { + var ft = new FunctionTemplate(); + ft.name = template.functions[i].name; + ft.index = i; + ft.isVoid = template.functions[i].void; + ft.expansion = template.functions[i].expansion; + this.functions.push(ft); + } + + + // append signals + for (var i = 0; i < this.events.length; i++) + this.members.push(this.events[i]); + // append slots + for (var i = 0; i < this.functions.length; i++) + this.members.push(this.functions[i]); + // append properties + for (var i = 0; i < this.properties.length; i++) + this.members.push(this.properties[i]); + + // bake it binarily + var b = new BinaryList(); + var cls = DC.stringToBytes(this.className); + b.addUint8Array(this.classId.value) + .addUint8(cls.length).addUint8Array(cls).addUint32(template.version).addUint16(this.members.length); + + for (var i = 0; i < this.functions.length; i++) + b.addUint8Array(this.functions[i].compose()); + + for (var i = 0; i < this.properties.length; i++) + b.addUint8Array(this.properties[i].compose()); + + for (var i = 0; i < this.events.length; i++) + b.addUint8Array(this.events[i].compose()); + + this.content = b.toArray(); + } + + static parse(data, offset = 0, contentLength = -1) { + + if (contentLength == -1) + contentLength = data.length; + + var ends = offset + contentLength; + + var oOffset = offset; + + // start parsing... + + var od = new ResourceTemplate(); + od.content = data.clip(offset, contentLength); + + od.classId = data.getGuid(offset); + offset += 16; + od.className = data.getString(offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + od.version = data.getInt32(offset); + offset += 4; + + var methodsCount = data.getUint16(offset); + offset += 2; + + var functionIndex = 0; + var propertyIndex = 0; + var eventIndex = 0; + + for (var i = 0; i < methodsCount; i++) { + var type = data.getUint8(offset) >> 5; + + if (type == 0) // function + { + var ft = new FunctionTemplate(); + ft.index = functionIndex++; + var expansion = ((data.getUint8(offset) & 0x10) == 0x10); + ft.isVoid = ((data.getUint8(offset++) & 0x08) == 0x08); + ft.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (expansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + ft.expansion = data.getString(offset, cs); + offset += cs; + } + + od.functions.push(ft); + } + else if (type == 1) // property + { + + var pt = new PropertyTemplate(); + pt.index = propertyIndex++; + var readExpansion = ((data.getUint8(offset) & 0x8) == 0x8); + var writeExpansion = ((data.getUint8(offset) & 0x10) == 0x10); + pt.permission = ((data.getUint8(offset++) >> 1) & 0x3); + pt.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (readExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + pt.readExpansion = data.getString(offset, cs); + offset += cs; + } + + if (writeExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + pt.writeExpansion = data.getString(offset, cs); + offset += cs; + } + + od.properties.push(pt); + } + else if (type == 2) // Event + { + var et = new EventTemplate(); + et.index = eventIndex++; + var expansion = ((data.getUint8(offset++) & 0x10) == 0x10); + + et.name = data.getString(offset + 1, data.getUint8(offset));// Encoding.ASCII.getString(data, (int)offset + 1, (int)data.getUint8(offset)); + offset += data.getUint8(offset) + 1; + + if (expansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + et.expansion = data.getString(offset, cs); + offset += cs; + } + + od.events.push(et); + + } + } + + // append signals + for (var i = 0; i < od.events.length; i++) + od.members.push(od.events[i]); + // append slots + for (var i = 0; i < od.functions.length; i++) + od.members.push(od.functions[i]); + // append properties + for (var i = 0; i < od.properties.length; i++) + od.members.push(od.properties[i]); + + + return od; + } +} \ No newline at end of file diff --git a/src/SendList.js b/src/SendList.js new file mode 100644 index 0000000..33a42ef --- /dev/null +++ b/src/SendList.js @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 02/09/2017. + */ + +class SendList extends BinaryList +{ + constructor(connection) + { + super(); + this.connection = connection; + } + + done() + { + this.connection.send(this.toArray()); + } +} \ No newline at end of file diff --git a/src/Structure.js b/src/Structure.js new file mode 100644 index 0000000..c059623 --- /dev/null +++ b/src/Structure.js @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 26/08/2017. + */ + +class Structure +{ + getKeys() { + var rt = []; + for (var i in this) + if (!(this[i] instanceof Function)) + rt.push(i); + + return rt; + } +} \ No newline at end of file diff --git a/src/StructureArray.js b/src/StructureArray.js new file mode 100644 index 0000000..73e1c91 --- /dev/null +++ b/src/StructureArray.js @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 06/09/2017. + */ + +class StructureArray extends Array +{ + push(value) + { + if (value instanceof Structure) + super.push(value); + else + return; + } +} \ No newline at end of file diff --git a/src/Warehouse.js b/src/Warehouse.js new file mode 100644 index 0000000..e9532f1 --- /dev/null +++ b/src/Warehouse.js @@ -0,0 +1,129 @@ +/* +* Copyright (c) 2017 Ahmed Kh. Zamil +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/** + * Created by Ahmed Zamil on 25/07/2017. + */ +var Warehouse = { + + stores: [], + resources: {}, + resourceCounter: 0, + templates: {}, + + new(type, name, store = null, parent = null) + { + var res = type(); + Warehouse.put(res, name, store, parent); + return res; + }, + +get: function(id) + { + if (Warehouse.resources[id]) + return new AsyncReply(Warehouse.resources[id]); + else + return null; + }, + + put: function(resource, name, store, parent){ + resource.instance = new Instance(Warehouse.resourceCounter++, name, resource, store); + //resource.instance.children.on("add", Warehouse._onChildrenAdd).on("remove", Warehouse._onChildrenRemove); + //resource.instance.parents.on("add", Warehouse._onParentsAdd).on("remove", Warehouse._onParentsRemove); + + if (parent) + { + parent.instance.children.add(resource); + } + else + { + if (!(resource instanceof IStore)) + store.instance.children.add(resource); + } + + if (resource instanceof IStore) + Warehouse.stores.push(resource); + else + store.put(resource); + + Warehouse.resources[resource.instance.id] = resource; + }, + + _onParentsRemove: function(value) + { + if (value.instance.children.contains(value)) + value.instance.children.remove(value); + }, + + _onParentsAdd: function(value) + { + if (!value.instance.children.contains(value)) + value.instance.children.add(value); + }, + + _onChildrenRemove: function(value) + { + if (value.instance.parents.contains(value)) + value.instance.parents.remove(value); + }, + + _onChildrenAdd: function(value) + { + if (!value.instance.parents.contains(value)) + value.instance.parents.add(value); + }, + + putTemplate: function(template) + { + if (Warehouse.templates[template.classId]) + Warehouse.templates[template.classId] = template; + }, + + getTemplateByType: function(type) + { + // loaded ? + for (var t in Warehouse.templates) + if (Warehouse.templates[t].className == typeof(type)) + return t; + + var template = new ResourceTemplate(type); + Warehouse.templates[template.classId] = template; + + return template; + }, + + getTemplateByClassId: function(classId) + { + if (Warehouse.templates[classId]) + return new AsyncReply(Warehouse.templates[classId]); + return null; + }, + + getTemplateByClassName: function(className) + { + for(var t in Warehouse.templates) + if (Warehouse.templates[t].className == className) + return new AsyncReply(t); + + return null; + } +}; \ No newline at end of file