mirror of
https://github.com/esiur/esiur-js.git
synced 2025-05-06 12:32:58 +00:00
7653 lines
238 KiB
JavaScript
7653 lines
238 KiB
JavaScript
/*
|
|
* Copyright (c) 2017-2018 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 10/11/2018.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class CustomResourceEvent
|
|
{
|
|
constructor(issuer, receivers, params)
|
|
{
|
|
this.issuer = issuer;
|
|
this.receivers = receivers;
|
|
this.params = params;
|
|
}
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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 18/11/2017.
|
|
*/
|
|
"use strict";
|
|
|
|
const ExceptionCode =
|
|
{
|
|
HostNotReachable: 0,
|
|
AccessDenied: 1,
|
|
ResourceNotFound: 2,
|
|
AttachDenied: 3,
|
|
InvalidMethod: 4,
|
|
InvokeDenied: 5,
|
|
CreateDenied: 6,
|
|
AddParentDenied: 7,
|
|
AddChildDenied: 8,
|
|
ViewAttributeDenied: 9,
|
|
UpdateAttributeDenied: 10,
|
|
StoreNotFound: 11,
|
|
ParentNotFound: 12,
|
|
ChildNotFound: 13,
|
|
ResourceIsNotStore: 14,
|
|
DeleteDenied: 15,
|
|
DeleteFailed: 16,
|
|
UpdateAttributeFailed: 17,
|
|
GetAttributesFailed: 18,
|
|
ClearAttributesFailed: 19,
|
|
TemplateNotFound: 20,
|
|
RenameDenied: 21,
|
|
ClassNotFound: 22,
|
|
MethodNotFound: 23,
|
|
PropertyNotFound: 24,
|
|
SetPropertyDenied: 25,
|
|
ReadOnlyProperty: 26
|
|
};
|
|
|
|
class AsyncException extends Error
|
|
{
|
|
constructor()
|
|
{
|
|
super();
|
|
this.raised = false;
|
|
}
|
|
|
|
raise(type, code, message)
|
|
{
|
|
this.type = (type == 0 ? "Management" : "Execusion");
|
|
this.code = code;
|
|
|
|
if (type == 0)
|
|
for(var i in ExceptionCode)
|
|
if (ExceptionCode[i] == code)
|
|
{
|
|
this.message = i;
|
|
break;
|
|
}
|
|
else
|
|
this.message = message;
|
|
|
|
this.raised = true;
|
|
}
|
|
|
|
toString()
|
|
{
|
|
return this.type + " " + this.code + " " + this.message;
|
|
}
|
|
}
|
|
/*
|
|
* 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 16/11/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const AuthenticationType = {
|
|
Host: 0,
|
|
CoHost: 1,
|
|
Client: 2,
|
|
Alien: 3
|
|
};
|
|
|
|
class Authentication
|
|
{
|
|
constructor(type)
|
|
{
|
|
this.type = type;
|
|
this.state = 0;
|
|
this.domain = null;
|
|
this.username = null;
|
|
}
|
|
|
|
get fullName()
|
|
{
|
|
return this.domain + "@" + this.username;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 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 16/11/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class Session
|
|
{
|
|
constructor(localAuthentication, remoteAuthentication)
|
|
{
|
|
|
|
this.localAuthentication = localAuthentication;
|
|
this.remoteAuthentication = remoteAuthentication;
|
|
this.id = null;
|
|
this.creation = null;
|
|
this.modification = null;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copyright (c) 2017-2018 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/10/2018.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class DistributedPropertyContext
|
|
{
|
|
constructor(p1, p2)
|
|
{
|
|
if(arguments.length == 1)
|
|
{
|
|
this.method = p1;
|
|
}
|
|
else if (arguments.length == 2)
|
|
{
|
|
this.connection = p1;
|
|
this.value = p2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 16/11/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const ActionType =
|
|
{
|
|
Attach: 0,
|
|
Delete: 1,
|
|
Execute: 2,
|
|
GetProperty: 3,
|
|
SetProperty: 4,
|
|
CreateResource: 5,
|
|
UpdateAttributes: 6,
|
|
InquireAttributes: 7,
|
|
AddParent: 8,
|
|
RemoveParent: 9,
|
|
AddChild: 10,
|
|
RemoveChild: 11,
|
|
Rename: 12,
|
|
ReceiveEvent: 13
|
|
};
|
|
|
|
const Ruling = {
|
|
Denied: 0,
|
|
Allowed: 1,
|
|
DontCare: 2,
|
|
};
|
|
|
|
class IPermissionsManager
|
|
{
|
|
/// <summary>
|
|
/// Check for permission.
|
|
/// </summary>
|
|
/// <param name="resource">IResource.</param>
|
|
/// <param name="session">Caller sessions.</param>
|
|
/// <param name="action">Action type</param>
|
|
/// <param name="member">Function or property to check for permission.</param>
|
|
/// <returns>Allowed or denined.</returns>
|
|
applicable(resource, session, action, member, inquirer)
|
|
{
|
|
|
|
}
|
|
|
|
initialize(settings, resource)
|
|
{
|
|
|
|
}
|
|
|
|
get settings()
|
|
{
|
|
|
|
}
|
|
}
|
|
/*
|
|
* 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/11/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class KeyList
|
|
{
|
|
constructor()
|
|
{
|
|
this.keys = [];
|
|
this.values = [];
|
|
}
|
|
|
|
at(index)
|
|
{
|
|
return this.values[index];
|
|
}
|
|
|
|
item(key)
|
|
{
|
|
for(var i = 0; i < this.keys.length; i++)
|
|
if (this.keys[i] == key)
|
|
return this.values[i];
|
|
}
|
|
|
|
get(key)
|
|
{
|
|
for(var i = 0; i < this.keys.length; i++)
|
|
if (this.keys[i] == key)
|
|
return this.values[i];
|
|
}
|
|
|
|
_item_destroyed(sender)
|
|
{
|
|
for(var i = 0; i < this.values.length; i++)
|
|
if (sender == this.values[i])
|
|
{
|
|
this.removeAt(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
add(key, value)
|
|
{
|
|
this.remove(key);
|
|
|
|
if (value instanceof IDestructible)
|
|
value.on("destroy", this._item_destroyed, this);
|
|
|
|
this.keys.push(key);
|
|
this.values.push(value);
|
|
}
|
|
|
|
contains(key)
|
|
{
|
|
for(var i = 0; i < this.keys.length; i++)
|
|
if (this.keys[i] == key)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
set(key, value)
|
|
{
|
|
this.remove(key);
|
|
this.add(key, value);
|
|
}
|
|
|
|
remove(key)
|
|
{
|
|
for(var i = 0; i < this.keys.length; i++)
|
|
if (key == this.keys[i])
|
|
{
|
|
this.removeAt(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
removeAt(index)
|
|
{
|
|
if (this.values[index] instanceof IDestructible)
|
|
this.values[index].off("destroy", this._item_destroyed);
|
|
|
|
this.keys.splice(index, 1);
|
|
this.values.splice(index, 1);
|
|
}
|
|
|
|
get length()
|
|
{
|
|
return this.keys.length;
|
|
}
|
|
}
|
|
/*
|
|
* 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/11/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class PropertyValue
|
|
{
|
|
constructor(value, age, date)
|
|
{
|
|
this.value = value;
|
|
this.age = age;
|
|
this.date = date;
|
|
}
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
"use strict";
|
|
|
|
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].f.apply(this._events[event][i].i, args))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
_emitArgs(event, args)
|
|
{
|
|
event = event.toLowerCase();
|
|
if (this._events[event])
|
|
for(var i = 0; i < this._events[event].length; i++)
|
|
if (this._events[event][i].f.apply(this._events[event][i].i, args))
|
|
return true;
|
|
return this;
|
|
}
|
|
|
|
on(event, fn, issuer)
|
|
{
|
|
if (!(fn instanceof Function))
|
|
return this;
|
|
|
|
event = event.toLowerCase();
|
|
// add
|
|
if (!this._events[event])
|
|
this._events[event] = [];
|
|
this._events[event].push({f: fn, i: issuer == null ? this: issuer});
|
|
return this;
|
|
}
|
|
|
|
off(event, fn)
|
|
{
|
|
event = event.toLocaleString();
|
|
if (this._events[event])
|
|
{
|
|
if (fn)
|
|
{
|
|
for(var i = 0; i < this._events[event].length; i++)
|
|
if (this._events[event][i].f == fn)
|
|
this._events[event].splice(i--, 1);
|
|
|
|
//var index = this._events[event].indexOf(fn);
|
|
//if (index > -1)
|
|
//this._events[event].splice(index, 1);
|
|
}
|
|
else
|
|
{
|
|
this._events[event] = [];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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/12/2017.
|
|
* Ref: https://en.wikipedia.org/wiki/SHA-2
|
|
*/
|
|
|
|
class SHA256
|
|
{
|
|
|
|
static RROT(n, d)
|
|
{
|
|
return (n >>> d)|(n << (32 - d));
|
|
}
|
|
|
|
static compute(msg)
|
|
{
|
|
/*
|
|
Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 2^32
|
|
Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
|
|
Note 3: The compression function uses 8 working variables, a through h
|
|
Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
|
|
and when parsing message block data from bytes to words, for example,
|
|
the first word of the input message "abc" after padding is 0x61626380
|
|
*/
|
|
|
|
// Initialize hash values:
|
|
// (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
|
|
|
const hash = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);
|
|
|
|
// Initialize array of round constants:
|
|
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
|
|
const k = new Uint32Array([
|
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]);
|
|
|
|
|
|
|
|
// Pre-processing:
|
|
// begin with the original message of length L bits
|
|
var L = msg.length * 8;
|
|
|
|
// append a single '1' bit
|
|
// append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
|
|
|
|
var K = 512 - ((L + 1 + 64) % 512);
|
|
|
|
if (K == 512)
|
|
K = 0;
|
|
|
|
var paddingLength = (K + 1) / 8;
|
|
var paddingBytes = new Uint8Array(paddingLength);
|
|
paddingBytes[0] = 0x80;
|
|
|
|
var data = new DC(BL().addUint8Array(msg).addUint8Array(paddingBytes).addUint64(L).toArray());
|
|
|
|
|
|
|
|
// append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
|
|
|
|
// Process the message in successive 512-bit chunks:
|
|
// break message into 512-bit chunks
|
|
// for each chunk
|
|
|
|
for(var chunk = 0; chunk < data.length; chunk+=64)
|
|
{
|
|
// create a 64-entry message schedule array w[0..63] of 32-bit words
|
|
// (The initial values in w[0..63] don't matter, so many implementations zero them here)
|
|
// copy chunk into first 16 words w[0..15] of the message schedule array
|
|
|
|
var w = new Uint32Array(64);
|
|
for(var i = 0; i < 16; i++)
|
|
w[i] = data.getInt32(chunk + (i * 4));
|
|
|
|
//for(var i = 16; i < 64; i++)
|
|
// w[i] = 0;
|
|
|
|
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
|
|
// for i from 16 to 63
|
|
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
|
|
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
|
|
// w[i] := w[i-16] + s0 + w[i-7] + s1
|
|
|
|
for (var i = 16; i < 64; i++)
|
|
{
|
|
var s0 = SHA256.RROT(w[i-15], 7) ^ SHA256.RROT(w[i-15], 18) ^ (w[i-15] >>> 3);
|
|
var s1 = SHA256.RROT(w[i-2], 17) ^ SHA256.RROT(w[i-2], 19) ^ (w[i-2] >>> 10);
|
|
w[i] = w[i-16] + s0 + w[i-7] + s1;
|
|
}
|
|
|
|
// Initialize working variables to current hash value:
|
|
var a = hash[0];
|
|
var b = hash[1];
|
|
var c = hash[2];
|
|
var d = hash[3];
|
|
var e = hash[4];
|
|
var f = hash[5];
|
|
var g = hash[6];
|
|
var h = hash[7];
|
|
|
|
|
|
// Compression function main loop:
|
|
for (var i = 0; i < 64; i++)
|
|
{
|
|
var S1 = SHA256.RROT(e, 6) ^ SHA256.RROT(e, 11) ^ SHA256.RROT(e, 25);
|
|
var ch = (e & f) ^ ((~e) & g);
|
|
var temp1 = h + S1 + ch + k[i] + w[i];
|
|
var S0 = SHA256.RROT(a, 2) ^ SHA256.RROT(a, 13) ^ SHA256.RROT(a, 22);
|
|
var maj = (a & b) ^ (a & c) ^ (b & c);
|
|
var temp2 = S0 + maj;
|
|
|
|
h = g;
|
|
g = f;
|
|
f = e;
|
|
e = (d + temp1) >>> 0;
|
|
d = c;
|
|
c = b;
|
|
b = a;
|
|
a = (temp1 + temp2) >>> 0;
|
|
}
|
|
|
|
// Add the compressed chunk to the current hash value:
|
|
|
|
hash[0] = (hash[0] + a) >>> 0;
|
|
hash[1] = (hash[1] + b) >>> 0;
|
|
hash[2] = (hash[2] + c) >>> 0;
|
|
hash[3] = (hash[3] + d) >>> 0;
|
|
hash[4] = (hash[4] + e) >>> 0;
|
|
hash[5] = (hash[5] + f) >>> 0;
|
|
hash[6] = (hash[6] + g) >>> 0;
|
|
hash[7] = (hash[7] + h) >>> 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Produce the final hash value (big-endian):
|
|
//digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
|
|
|
|
var results = new BinaryList();
|
|
for(var i = 0; i < 8; i++)
|
|
results.addUint32(hash[i]);
|
|
|
|
|
|
return results.toDC();
|
|
}
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class AutoList extends IEventHandler
|
|
{
|
|
constructor()
|
|
{
|
|
super();
|
|
this.list = [];
|
|
}
|
|
|
|
get length()
|
|
{
|
|
return this.list.length;
|
|
}
|
|
|
|
add(value)
|
|
{
|
|
if (value instanceof IDestructible)
|
|
value.on("destroy", this._item_destroyed, this);
|
|
|
|
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, this);
|
|
|
|
if (this.list[index] instanceof IDestructible)
|
|
this.list[index].off("destroy", this._item_destroyed);
|
|
|
|
this.list[index] = value;
|
|
}
|
|
|
|
at(index)
|
|
{
|
|
return this.list[index];
|
|
}
|
|
|
|
item(index)
|
|
{
|
|
return this.list[index];
|
|
}
|
|
|
|
remove(value)
|
|
{
|
|
this.removeAt(this.list.indexOf(value));
|
|
}
|
|
|
|
contains(value)
|
|
{
|
|
return this.list.indexOf(value) > -1;
|
|
}
|
|
|
|
toArray()
|
|
{
|
|
return this.list.slice(0);
|
|
}
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class IStore extends IResource {
|
|
get(path) {
|
|
|
|
}
|
|
|
|
retrieve(iid) {
|
|
|
|
}
|
|
|
|
put(resource) {
|
|
|
|
}
|
|
|
|
record(resource, propertyName, value, age, dateTime)
|
|
{
|
|
|
|
}
|
|
|
|
getRecord(resource, fromDate, toDate)
|
|
{
|
|
|
|
}
|
|
|
|
remove(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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const ErrorType = {
|
|
Management: 0,
|
|
Exception: 1
|
|
};
|
|
|
|
const ProgressType = {
|
|
Execution: 0,
|
|
Network: 1
|
|
};
|
|
|
|
class AsyncReply
|
|
{
|
|
then(callback)
|
|
{
|
|
this.callbacks.push(callback);
|
|
|
|
if (this.ready)
|
|
{
|
|
callback(this.result, this);
|
|
|
|
if (!this.taskExpired)
|
|
{
|
|
this.taskExpired = true;
|
|
this.resolveTask(this.result);
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
catch(callback)
|
|
{
|
|
return error(callback);
|
|
}
|
|
|
|
error(callback)
|
|
{
|
|
this.errorCallbacks.push(callback);
|
|
|
|
if (this.exception.raised)
|
|
{
|
|
callback(this.exception);
|
|
|
|
if (!this.taskExpired)
|
|
{
|
|
this.taskExpired = true;
|
|
this.rejectTask(this.exception);
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
progress(callback)
|
|
{
|
|
this.progressCallbacks.push(callback);
|
|
return this;
|
|
}
|
|
|
|
chunk(callback)
|
|
{
|
|
this.chunkCallbacks.push(callback);
|
|
return this;
|
|
}
|
|
|
|
trigger(result)
|
|
{
|
|
this.result = result;
|
|
this.ready = true;
|
|
|
|
for(var i = 0; i < this.callbacks.length; i++)
|
|
this.callbacks[i](result, this);
|
|
|
|
|
|
if (!this.taskExpired)
|
|
{
|
|
this.taskExpired = true;
|
|
this.resolveTask(this.result);
|
|
}
|
|
}
|
|
|
|
|
|
triggerError(type, code, message)//exception)
|
|
{
|
|
if (this.ready)
|
|
return;
|
|
|
|
this.exception.raise(type, code, message);// = exception;
|
|
|
|
for(var i = 0; i < this.errorCallbacks.length; i++)
|
|
this.errorCallbacks[i](this.exception, this);
|
|
|
|
|
|
if (!this.taskExpired)
|
|
{
|
|
this.taskExpired = true;
|
|
this.rejectTask(this.exception);
|
|
}
|
|
}
|
|
|
|
triggerProgress(type, value, max)
|
|
{
|
|
if (this.ready)
|
|
return;
|
|
|
|
for(var i = 0; i < this.progressCallbacks.length; i++)
|
|
this.progressCallbacks[i](type, value, max, this);
|
|
}
|
|
|
|
triggerChunk(value)
|
|
{
|
|
if (this.ready)
|
|
return;
|
|
|
|
for(var i = 0; i < this.chunkCallbacks.length; i++)
|
|
this.chunkCallbacks[i](value, this);
|
|
}
|
|
|
|
constructor(result)
|
|
{
|
|
this.callbacks = [];
|
|
this.errorCallbacks = [];
|
|
this.progressCallbacks = [];
|
|
this.chunkCallbacks = [];
|
|
this.exception = new AsyncException();// null;
|
|
|
|
var self = this;
|
|
|
|
this.task = new Promise(function(resolve, reject){
|
|
self.resolveTask = resolve;
|
|
self.rejectTask = reject;
|
|
});
|
|
|
|
|
|
if (result !== undefined) {
|
|
this.result = result;
|
|
this.ready = true;
|
|
this.taskExpired = true;
|
|
this.resolveTask(result);
|
|
}
|
|
else
|
|
{
|
|
this.taskExpired = false;
|
|
this.ready = false;
|
|
this.result = 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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;
|
|
|
|
var singleTaskCompleted = function(taskIndex)
|
|
{
|
|
return function(results, reply){
|
|
self.results[taskIndex] = results;
|
|
self.count++;
|
|
if (self.count == self.results.length)
|
|
self.trigger(self.results);
|
|
};
|
|
};
|
|
|
|
for(var i = 0; i < this.results.length; i++)
|
|
this.replies[i].then(singleTaskCompleted(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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
function BL(){
|
|
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;
|
|
}
|
|
|
|
toDC()
|
|
{
|
|
return new DC(this.toArray());
|
|
}
|
|
|
|
addDateTime(value, position)
|
|
{
|
|
return this.add({type: DataType.DateTime, value: value}, position);
|
|
}
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const ResourceComparisonResult =
|
|
{
|
|
Null: 0,
|
|
Distributed: 1,
|
|
Local: 2,
|
|
Same: 3
|
|
};
|
|
|
|
const 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse an array of bytes into array of resources
|
|
/// </summary>
|
|
/// <param name="data">Array of bytes.</param>
|
|
/// <param name="length">Number of bytes to parse.</param>
|
|
/// <param name="offset">Zero-indexed offset.</param>
|
|
/// <param name="connection">DistributedConnection is required to fetch resources.</param>
|
|
/// <returns>Array of resources.</returns>
|
|
static parseResourceArray(data, offset, length, connection)
|
|
{
|
|
var reply = new AsyncBag();
|
|
if (length == 0)
|
|
{
|
|
reply.seal();
|
|
return reply;
|
|
}
|
|
|
|
var end = offset + length;
|
|
|
|
//
|
|
var result = data[offset++];
|
|
|
|
var previous = null;
|
|
|
|
if (result == ResourceComparisonResult.Null)
|
|
previous = new AsyncReply(null);
|
|
else if (result == ResourceComparisonResult.Local)
|
|
{
|
|
previous = Warehouse.get(data.getUint32(offset));
|
|
offset += 4;
|
|
}
|
|
else if (result == ResourceComparisonResult.Distributed)
|
|
{
|
|
previous = connection.fetch(data.getUint32(offset));
|
|
offset += 4;
|
|
}
|
|
|
|
reply.add(previous);
|
|
|
|
|
|
while (offset < end)
|
|
{
|
|
result = data[offset++];
|
|
|
|
var current = null;
|
|
|
|
if (result == ResourceComparisonResult.Null)
|
|
{
|
|
current = new AsyncReply(null);
|
|
}
|
|
else if (result == ResourceComparisonResult.Same)
|
|
{
|
|
current = previous;
|
|
}
|
|
else if (result == ResourceComparisonResult.Local)
|
|
{
|
|
current = Warehouse.get(data.getUint32(offset));
|
|
offset += 4;
|
|
}
|
|
else if (result == ResourceComparisonResult.Distributed)
|
|
{
|
|
current = connection.fetch(data.getUint32(offset));
|
|
offset += 4;
|
|
}
|
|
|
|
reply.add(current);
|
|
|
|
previous = current;
|
|
}
|
|
|
|
reply.seal();
|
|
return reply;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compose an array of property values.
|
|
/// </summary>
|
|
/// <param name="array">PropertyValue array.</param>
|
|
/// <param name="connection">DistributedConnection is required to check locality.</param>
|
|
/// <param name="prependLength">If True, prepend the length as UInt32 at the beginning of the output.</param>
|
|
/// <returns>Array of bytes in the network byte order.</returns>
|
|
|
|
static composePropertyValueArray(array, connection, prependLength = false)
|
|
{
|
|
var rt = BL();
|
|
for (var i = 0; i < array.Length; i++)
|
|
rt.addUint8Array(Codec.composePropertyValue(array[i], connection));
|
|
if (prependLength)
|
|
rt.addUint32(rt.length, 0);
|
|
return rt.toArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compose a property value.
|
|
/// </summary>
|
|
/// <param name="propertyValue">Property value</param>
|
|
/// <param name="connection">DistributedConnection is required to check locality.</param>
|
|
/// <returns>Array of bytes in the network byte order.</returns>
|
|
static composePropertyValue(propertyValue, connection)
|
|
{
|
|
// age, date, value
|
|
return BL().addUint64(propertyValue.age)
|
|
.addDateTime(propertyValue.date)
|
|
.addUint8Array(Codec.compose(propertyValue.value, connection))
|
|
.toArray();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Parse property value.
|
|
/// </summary>
|
|
/// <param name="data">Array of bytes.</param>
|
|
/// <param name="offset">Zero-indexed offset.</param>
|
|
/// <param name="connection">DistributedConnection is required to fetch resources.</param>
|
|
/// <param name="cs">Output content size.</param>
|
|
/// <returns>PropertyValue.</returns>
|
|
static parsePropertyValue(data, offset, sizeObject, connection)
|
|
{
|
|
var reply = new AsyncReply();
|
|
|
|
var age = data.getUint64(offset);
|
|
offset += 8;
|
|
|
|
var date = data.getDateTime(offset);
|
|
offset += 8;
|
|
|
|
var cs = {};
|
|
|
|
Codec.parse(data, offset, cs, connection).then(function(value)
|
|
{
|
|
reply.trigger(new PropertyValue(value, age, date));
|
|
});
|
|
|
|
sizeObject.size = 16 + cs.size;
|
|
return reply;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Parse resource history
|
|
/// </summary>
|
|
/// <param name="data">Array of bytes.</param>
|
|
/// <param name="offset">Zero-indexed offset.</param>
|
|
/// <param name="length">Number of bytes to parse.</param>
|
|
/// <param name="resource">Resource</param>
|
|
/// <param name="fromAge">Starting age.</param>
|
|
/// <param name="toAge">Ending age.</param>
|
|
/// <param name="connection">DistributedConnection is required to fetch resources.</param>
|
|
/// <returns></returns>
|
|
static parseHistory(data, offset, length, resource, connection)
|
|
{
|
|
var list = new KeyList();
|
|
|
|
var reply = new AsyncReply();
|
|
|
|
var bagOfBags = new AsyncBag();
|
|
|
|
var ends = offset + length;
|
|
while (offset < ends)
|
|
{
|
|
var index = data[offset++];
|
|
var pt = resource.instance.template.getPropertyTemplateByIndex(index);
|
|
|
|
list.add(pt, null);
|
|
|
|
|
|
var cs = data.getUint32(offset);
|
|
offset += 4;
|
|
bagOfBags.add(Codec.parsePropertyValueArray(data, offset, cs, connection));
|
|
offset += cs;
|
|
}
|
|
|
|
bagOfBags.seal();
|
|
|
|
bagOfBags.then(x =>
|
|
{
|
|
for(var i = 0; i < list.length; i++)
|
|
list.values[i] = x[i];
|
|
|
|
reply.trigger(list);
|
|
});
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compose resource history
|
|
/// </summary>
|
|
/// <param name="history">History</param>
|
|
/// <param name="connection">DistributedConnection is required to fetch resources.</param>
|
|
/// <returns></returns>
|
|
static composeHistory(history, connection, prependLength = false)
|
|
{
|
|
var rt = new BinaryList();
|
|
|
|
for (var i = 0; i < history.length; i++)
|
|
rt.addUint8(history.keys[i].index).addUint8Array(Codec.composePropertyValueArray(history.values[i], connection, true));
|
|
|
|
if (prependLength)
|
|
rt.addUint32(rt.length, 0);
|
|
|
|
return rt.toArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse an array of ProperyValue.
|
|
/// </summary>
|
|
/// <param name="data">Array of bytes.</param>
|
|
/// <param name="offset">Zero-indexed offset.</param>
|
|
/// <param name="length">Number of bytes to parse.</param>
|
|
/// <param name="connection">DistributedConnection is required to fetch resources.</param>
|
|
/// <returns></returns>
|
|
static parsePropertyValueArray(data, offset, length, connection)
|
|
{
|
|
var rt = new AsyncBag();
|
|
|
|
while (length > 0)
|
|
{
|
|
var cs = {};
|
|
|
|
rt.add(Codec.parsePropertyValue(data, offset, cs, connection));
|
|
|
|
if (cs.size > 0)
|
|
{
|
|
offset += cs.size;
|
|
length -= cs.size;
|
|
}
|
|
else
|
|
throw new Exception("Error while parsing ValueInfo structured data");
|
|
}
|
|
|
|
rt.seal();
|
|
return rt;
|
|
}
|
|
|
|
static parseStructure(data, offset, contentLength, connection, metadata = null, keys = null, types = null)
|
|
{
|
|
var reply = new AsyncReply();
|
|
var bag = new AsyncBag();
|
|
|
|
|
|
var keylist = [];
|
|
var 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;
|
|
offset += rt.size;
|
|
}
|
|
}
|
|
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);
|
|
});
|
|
|
|
if (metadata != null)
|
|
{
|
|
metadata.keys = keylist;
|
|
metadata.types = typelist;
|
|
}
|
|
|
|
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) {
|
|
|
|
if (value instanceof Function)
|
|
value = value(connection);
|
|
else if (value instanceof DistributedPropertyContext)
|
|
value = value.method(this);
|
|
|
|
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._p.instanceId);
|
|
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._p.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;
|
|
else if (next == previous)
|
|
return ResourceComparisonResult.Same;
|
|
else if (Codec.isLocalResource(next, connection))
|
|
return ResourceComparisonResult.Local;
|
|
else
|
|
return ResourceComparisonResult.Distributed;
|
|
}
|
|
|
|
static composeResourceArray(resources, connection, prependLength = false) {
|
|
|
|
if (resources == null || resources.length == 0)// || !(resources instanceof ResourceArray))
|
|
return prependLength ? new DC(4) : 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]._p.instanceId);
|
|
else if (comparsion == ResourceComparisonResult.Distributed)
|
|
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[i]._p.instanceId);
|
|
else if (comparsion == ResourceComparisonResult.Distributed)
|
|
rt.addUint32(resources[i].instance.id);
|
|
}
|
|
|
|
if (prependLength)
|
|
rt.addUint32(rt.length, 0);
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Parse an array of structures
|
|
/// </summary>
|
|
/// <param name="data">Bytes array</param>
|
|
/// <param name="offset">Zero-indexed offset</param>
|
|
/// <param name="length">Number of bytes to parse</param>
|
|
/// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end</param>
|
|
/// <returns>Array of structures</returns>
|
|
static parseStructureArray(data, offset, length, connection)
|
|
{
|
|
var reply = new AsyncBag();
|
|
if (length == 0)
|
|
{
|
|
reply.seal();
|
|
return reply;
|
|
}
|
|
|
|
var end = offset + length;
|
|
|
|
var result = data[offset++];
|
|
|
|
var previous = null;
|
|
//var previousKeys = [];
|
|
//var previousTypes = [];
|
|
|
|
var metadata = {keys: null, types: null};
|
|
|
|
|
|
if (result == StructureComparisonResult.Null)
|
|
previous = new AsyncReply(null);
|
|
else if (result == StructureComparisonResult.Structure)
|
|
{
|
|
var cs = data.getUint32(offset);
|
|
offset += 4;
|
|
previous = this.parseStructure(data, offset, cs, connection, metadata);
|
|
offset += cs;
|
|
}
|
|
|
|
reply.add(previous);
|
|
|
|
|
|
while (offset < end)
|
|
{
|
|
result = data[offset++];
|
|
|
|
if (result == StructureComparisonResult.Null)
|
|
previous = new AsyncReply(null);
|
|
else if (result == StructureComparisonResult.Structure)
|
|
{
|
|
var cs = data.getUint32(offset);
|
|
offset += 4;
|
|
previous = this.parseStructure(data, offset, cs, connection, metadata);
|
|
offset += cs;
|
|
}
|
|
else if (result == StructureComparisonResult.StructureSameKeys)
|
|
{
|
|
var cs = data.getUint32(offset);
|
|
offset += 4;
|
|
previous = this.parseStructure(data, offset, cs, connection, metadata, metadata.keys);
|
|
offset += cs;
|
|
}
|
|
else if (result == StructureComparisonResult.StructureSameTypes)
|
|
{
|
|
var cs = data.getUint32(offset);
|
|
offset += 4;
|
|
previous = this.parseStructure(data, offset, cs, connection, metadata, metadata.keys, metadata.types);
|
|
offset += cs;
|
|
}
|
|
|
|
reply.add(previous);
|
|
}
|
|
|
|
reply.seal();
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const UNIX_EPOCH = 621355968000000000;
|
|
const 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);
|
|
}
|
|
|
|
static stringArrayToBytes(values)
|
|
{
|
|
var list = new BinaryList();
|
|
for(var i = 0; i < values.length; i++)
|
|
{
|
|
var s = DC.stringToBytes(values[i]);
|
|
list.addUint32(s.length).addUint8Array(s);
|
|
}
|
|
|
|
return list.toArray();
|
|
}
|
|
|
|
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-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.clip(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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class DistributedConnection extends IStore {
|
|
|
|
send(data) {
|
|
console.log("Send", data.length);
|
|
this.socket.send(data.buffer);
|
|
}
|
|
|
|
sendParams(doneReply) {
|
|
return new SendList(this, doneReply);
|
|
}
|
|
|
|
generateNonce(length)
|
|
{
|
|
var rt = new Uint8Array(length);
|
|
for(var i = 0; i < length; i++)
|
|
rt[i] = Math.random() * 255;
|
|
|
|
return rt;
|
|
}
|
|
|
|
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._register("ready");
|
|
this._register("error");
|
|
this._register("close");
|
|
|
|
this.session = new Session(new Authentication(AuthenticationType.Client), new Authentication(AuthenticationType.Host));
|
|
|
|
this.session.localAuthentication.domain = domain;
|
|
this.session.localAuthentication.username = 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 = new KeyList();
|
|
this.requests = {};
|
|
this.pathRequests = {};
|
|
this.templateRequests = new KeyList();
|
|
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 = this.generateNonce(32);// 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("Rec", msg.data.byteLength);
|
|
|
|
this.networkBuffer.writeAll(msg.data);
|
|
|
|
self.lastAction = new Date();
|
|
|
|
while (this.networkBuffer.available > 0 && !this.networkBuffer.protected)
|
|
self.receive(this.networkBuffer);
|
|
|
|
|
|
};
|
|
|
|
this.socket.onclose = function(event)
|
|
{
|
|
self.close(event);
|
|
};
|
|
|
|
//this.socket.onerror = function(event)
|
|
//{
|
|
// self.close(event);
|
|
//};
|
|
}
|
|
|
|
|
|
processPacket(msg, offset, ends, data)
|
|
{
|
|
|
|
|
|
var authPacket = this.authPacket;
|
|
|
|
if (this.ready) {
|
|
var packet = new IIPPacket();
|
|
|
|
var rt = packet.parse(msg, offset, ends);
|
|
if (rt <= 0) {
|
|
data.holdFor(msg, offset, ends - offset, -rt);
|
|
return ends;
|
|
}
|
|
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.EventOccurred:
|
|
this.IIPEventEventOccurred(packet.resourceId, packet.methodIndex, packet.content);
|
|
break;
|
|
|
|
case IIPPacketEvent.ChildAdded:
|
|
this.IIPEventChildAdded(packet.resourceId, packet.childId);
|
|
break;
|
|
case IIPPacketEvent.ChildRemoved:
|
|
this.IIPEventChildRemoved(packet.resourceId, packet.childId);
|
|
break;
|
|
case IIPPacketEvent.Renamed:
|
|
this.IIPEventRenamed(packet.resourceId, packet.content);
|
|
break;
|
|
case IIPPacketEvent.AttributesUpdated:
|
|
this.IIPEventAttributesUpdated(packet.resourceId, packet.content);
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if (packet.command == IIPPacketCommand.Request) {
|
|
switch (packet.action) {
|
|
|
|
// Manage
|
|
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.storeId, packet.resourceId, packet.content);
|
|
break;
|
|
case IIPPacketAction.DeleteResource:
|
|
this.IIPRequestDeleteResource(packet.callbackId, packet.resourceId);
|
|
break;
|
|
case IIPPacketAction.AddChild:
|
|
this.IIPRequestAddChild(packet.callbackId, packet.resourceId, packet.childId);
|
|
break;
|
|
case IIPPacketAction.RemoveChild:
|
|
this.IIPRequestRemoveChild(packet.callbackId, packet.resourceId, packet.childId);
|
|
break;
|
|
case IIPPacketAction.RenameResource:
|
|
this.IIPRequestRenameResource(packet.callbackId, packet.resourceId, packet.content);
|
|
break;
|
|
|
|
// Inquire
|
|
case IIPPacketAction.TemplateFromClassName:
|
|
this.IIPRequestTemplateFromClassName(packet.callbackId, packet.className);
|
|
break;
|
|
case IIPPacketAction.TemplateFromClassId:
|
|
this.IIPRequestTemplateFromClassId(packet.callbackId, packet.classId);
|
|
break;
|
|
case IIPPacketAction.TemplateFromResourceId:
|
|
this.IIPRequestTemplateFromResourceId(packet.callbackId, packet.resourceId);
|
|
break;
|
|
case IIPPacketAction.QueryLink:
|
|
this.IIPRequestQueryResources(packet.callbackId, packet.resourceLink);
|
|
break;
|
|
case IIPPacketAction.ResourceChildren:
|
|
this.IIPRequestResourceChildren(packet.callbackId, packet.resourceId);
|
|
break;
|
|
case IIPPacketAction.ResourceParents:
|
|
this.IIPRequestResourceParents(packet.callbackId, packet.resourceId);
|
|
break;
|
|
case IIPPacketAction.ResourceHistory:
|
|
this.IIPRequestInquireResourceHistory(packet.callbackId, packet.resourceId, packet.fromDate, packet.toDate);
|
|
break;
|
|
|
|
// Invoke
|
|
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;
|
|
case IIPPacketAction.ResourceHistory:
|
|
this.IIPRequestInquireResourceHistory(packet.callbackId, packet.resourceId, packet.fromDate, packet.toDate);
|
|
break;
|
|
case IIPPacketAction.QueryLink:
|
|
this.IIPRequestQueryResources(packet.callbackId, packet.resourceLink);
|
|
break;
|
|
|
|
// Attribute
|
|
case IIPPacketAction.GetAllAttributes:
|
|
this.IIPRequestGetAttributes(packet.callbackId, packet.resourceId, packet.content, true);
|
|
break;
|
|
case IIPPacketAction.UpdateAllAttributes:
|
|
this.IIPRequestUpdateAttributes(packet.callbackId, packet.resourceId, packet.content, true);
|
|
break;
|
|
case IIPPacketAction.ClearAllAttributes:
|
|
this.IIPRequestClearAttributes(packet.callbackId, packet.resourceId, packet.content, true);
|
|
break;
|
|
case IIPPacketAction.GetAttributes:
|
|
this.IIPRequestGetAttributes(packet.callbackId, packet.resourceId, packet.content, false);
|
|
break;
|
|
case IIPPacketAction.UpdateAttributes:
|
|
this.IIPRequestUpdateAttributes(packet.callbackId, packet.resourceId, packet.content, false);
|
|
break;
|
|
case IIPPacketAction.ClearAttributes:
|
|
this.IIPRequestClearAttributes(packet.callbackId, packet.resourceId, packet.content, false);
|
|
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.resourceId);
|
|
break;
|
|
case IIPPacketAction.DeleteResource:
|
|
case IIPPacketAction.AddChild:
|
|
case IIPPacketAction.RemoveChild:
|
|
case IIPPacketAction.RenameResource:
|
|
this.IIPReply(packet.callbackId);
|
|
break;
|
|
case IIPPacketAction.TemplateFromClassName:
|
|
case IIPPacketAction.TemplateFromClassId:
|
|
case IIPPacketAction.TemplateFromResourceId:
|
|
this.IIPReply(packet.callbackId, ResourceTemplate.parse(packet.content));
|
|
break;
|
|
|
|
case IIPPacketAction.QueryLink:
|
|
case IIPPacketAction.ResourceChildren:
|
|
case IIPPacketAction.ResourceParents:
|
|
case IIPPacketAction.ResourceHistory:
|
|
this.IIPReply(packet.callbackId, packet.content);
|
|
break;
|
|
|
|
case IIPPacketAction.InvokeFunction:
|
|
this.IIPReplyInvoke(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;
|
|
|
|
// Attribute
|
|
case IIPPacketAction.GetAllAttributes:
|
|
case IIPPacketAction.GetAttributes:
|
|
this.IIPReply(packet.callbackId, packet.content);
|
|
break;
|
|
|
|
case IIPPacketAction.UpdateAllAttributes:
|
|
case IIPPacketAction.UpdateAttributes:
|
|
case IIPPacketAction.ClearAllAttributes:
|
|
case IIPPacketAction.ClearAttributes:
|
|
this.IIPReply(packet.callbackId);
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
else if (packet.command == IIPPacketCommand.Report)
|
|
{
|
|
switch (packet.report)
|
|
{
|
|
case IIPPacketReport.ManagementError:
|
|
this.IIPReportError(packet.callbackId, ErrorType.Management, packet.errorCode, null);
|
|
break;
|
|
case IIPPacketReport.ExecutionError:
|
|
this.IIPReportError(packet.callbackId, ErrorType.Exception, packet.errorCode, packet.errorMessage);
|
|
break;
|
|
case IIPPacketReport.ProgressReport:
|
|
this.IIPReportProgress(packet.callbackId, ProgressType.Execution, packet.progressValue, packet.progressMax);
|
|
break;
|
|
case IIPPacketReport.ChunkStream:
|
|
this.IIPReportChunk(packet.callbackId, packet.content);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
else {
|
|
var rt = authPacket.parse(msg, offset, ends);
|
|
|
|
|
|
if (rt <= 0) {
|
|
data.holdAllFor(msg, ends - rt);
|
|
return ends;
|
|
}
|
|
else {
|
|
offset += rt;
|
|
|
|
if (this.session.localAuthentication.type == AuthenticationType.Host) {
|
|
if (authPacket.command == IIPAuthPacketCommand.Declare) {
|
|
if (authPacket.remoteMethod == IIPAuthPacketMethod.credentials
|
|
&& authPacket.localMethod == IIPAuthPacketMethod.None) {
|
|
this.session.remoteAuthentication.username = 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.session.remoteAuthentication.username, this.domain).then(function (pw) {
|
|
if (pw != null) {
|
|
|
|
//var hash = new DC(sha256.arrayBuffer(BL().addString(pw).addUint8Array(remoteNonce).addUint8Array(this.localNonce).toArray()));
|
|
var hash = SHA256.compute(BL().addString(pw).addUint8Array(remoteNonce).addUint8Array(this.localNonce).toDC());
|
|
|
|
|
|
if (hash.sequenceEqual(remoteHash)) {
|
|
// send our hash
|
|
//var localHash = new DC(sha256.arrayBuffer((new BinaryList()).addUint8Array(this.localNonce).addUint8Array(remoteNonce).addUint8Array(pw).toArray()));
|
|
var localHash = SHA256.compute(BL().addUint8Array(this.localNonce).addUint8Array(remoteNonce).addUint8Array(pw).toDC());
|
|
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.session.id = this.generateNonce(32);// new DC(32);
|
|
//window.crypto.getRandomValues(this.session.id);
|
|
|
|
this.sendParams().addUint8(0x28).addUint8Array(this.session.id).done();
|
|
this.ready = true;
|
|
this._emit("ready", this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (this.session.localAuthentication.type == 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()));
|
|
|
|
var localHash = SHA256.compute(BL().addUint8Array(this.localPassword)
|
|
.addUint8Array(this.localNonce)
|
|
.addUint8Array(this.remoteNonce).toDC());
|
|
|
|
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()
|
|
//));
|
|
|
|
var remoteHash = SHA256.compute(BL().addUint8Array(this.remoteNonce)
|
|
.addUint8Array(this.localNonce)
|
|
.addUint8Array(this.localPassword).toDC());
|
|
|
|
|
|
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.session.id = 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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return offset;
|
|
|
|
//if (offset < ends)
|
|
// this.processPacket(msg, offset, ends, data);
|
|
}
|
|
|
|
receive(data) {
|
|
var msg = data.read();
|
|
var offset = 0;
|
|
var ends = msg.length;
|
|
var packet = this.packet;
|
|
|
|
//console.log("Data");
|
|
|
|
while (offset < ends) {
|
|
offset = this.processPacket(msg, offset, ends, data);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
close(event)
|
|
{
|
|
this._emit("close", event);
|
|
|
|
Warehouse.remove(this);
|
|
|
|
if (this.socket.readyState != this.socket.CLOSED)
|
|
{
|
|
this.socket.close();
|
|
}
|
|
}
|
|
|
|
trigger(trigger) {
|
|
return true;
|
|
}
|
|
|
|
put(resource) {
|
|
this.resources[parseInt(resource.instance.name)] = resource;
|
|
return true;
|
|
}
|
|
|
|
remove(resource)
|
|
{
|
|
// nothing to do (IStore interface)
|
|
}
|
|
|
|
// Protocol Implementation
|
|
|
|
sendRequest2(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;
|
|
}
|
|
|
|
sendRequest(action) {
|
|
var reply = new AsyncReply();
|
|
this.callbackCounter++;
|
|
this.requests[this.callbackCounter] = reply;
|
|
return this.sendParams(reply).addUint8(0x40 | action).addUint32(this.callbackCounter);
|
|
}
|
|
|
|
sendInvoke(instanceId, index, parameters)
|
|
{
|
|
var reply = new AsyncReply();
|
|
|
|
var pb = Codec.composeVarArray(parameters, this, true);
|
|
|
|
this.callbackCounter++;
|
|
this.sendParams()
|
|
.addUint8(0x40 | IIPPacketAction.InvokeFunction)
|
|
.addUint32(this.callbackCounter)
|
|
.addUint32(instanceId)
|
|
.addUint8(index)
|
|
.addUint8Array(pb)
|
|
.done();
|
|
|
|
this.requests[this.callbackCounter] = reply;
|
|
|
|
return reply;
|
|
}
|
|
|
|
sendError(type, callbackId, errorCode, errorMessage = "")
|
|
{
|
|
var msg = DC.stringToBytes(errorMessage);
|
|
if (type == ErrorType.Management)
|
|
this.sendParams()
|
|
.addUint8(0xC0 | IIPPacketReport.ManagementError)
|
|
.addUint32(callbackId)
|
|
.addUint16(errorCode)
|
|
.done();
|
|
else if (type == ErrorType.Exception)
|
|
this.sendParams()
|
|
.addUint8(0xC0 | IIPPacketReport.ExecutionError)
|
|
.addUint32(callbackId)
|
|
.addUint16(errorCode)
|
|
.addUint16(msg.length)
|
|
.addUint8Array(msg)
|
|
.done();
|
|
}
|
|
|
|
sendProgress(callbackId, value, max)
|
|
{
|
|
this.sendParams()
|
|
.addUint8(0xC0 | IIPPacketReport.ProgressReport)
|
|
.addUint32(callbackId)
|
|
.addInt32(value)
|
|
.addInt32(max)
|
|
.done();
|
|
}
|
|
|
|
sendChunk(callbackId, chunk)
|
|
{
|
|
var c = Codec.compose(chunk, this, true);
|
|
this.sendParams()
|
|
.addUint8(0xC0 | IIPPacketReport.ChunkStream)
|
|
.addUint32(callbackId)
|
|
.addUint8Array(c)
|
|
.done();
|
|
}
|
|
|
|
IIPReply(callbackId) {
|
|
|
|
var results = Array.prototype.slice.call(arguments, 1);
|
|
var req = this.requests[callbackId];
|
|
|
|
//console.log("Reply " + callbackId, req);
|
|
|
|
delete this.requests[callbackId];
|
|
req.trigger(results);
|
|
}
|
|
|
|
IIPReplyInvoke(callbackId, result)
|
|
{
|
|
var req = this.requests[callbackId];
|
|
delete this.requests[callbackId];
|
|
|
|
Codec.parse(result, 0, {}, this).then(function(rt)
|
|
{
|
|
req.trigger(rt);
|
|
});
|
|
}
|
|
|
|
IIPReportError(callbackId, errorType, errorCode, errorMessage)
|
|
{
|
|
var req = this.requests[callbackId];
|
|
delete this.requests[callbackId];
|
|
req.triggerError(errorType, errorCode, errorMessage);
|
|
}
|
|
|
|
IIPReportProgress(callbackId, type, value, max)
|
|
{
|
|
var req = this.requests[callbackId];
|
|
req.triggerProgress(type, value, max);
|
|
}
|
|
|
|
IIPReportChunk(callbackId, data)
|
|
{
|
|
if (this.requests[callbackId])
|
|
{
|
|
var req = this.requests[callbackId];
|
|
Codec.parse(data, 0, {}, this).then(function(x)
|
|
{
|
|
req.triggerChunk(x);
|
|
});
|
|
}
|
|
}
|
|
|
|
IIPEventResourceReassigned(resourceId, newResourceId) {
|
|
|
|
}
|
|
|
|
IIPEventResourceDestroyed(resourceId) {
|
|
if (this.resources[resourceId]) {
|
|
var r = this.resources[resourceId];
|
|
delete this.resources[resourceId];
|
|
r.destroy();
|
|
}
|
|
}
|
|
|
|
IIPEventPropertyUpdated(resourceId, index, content) {
|
|
|
|
var self = this;
|
|
|
|
this.fetch(resourceId).then(function(r){
|
|
// push to the queue to gaurantee serialization
|
|
var item = new AsyncReply();
|
|
self.queue.add(item);
|
|
|
|
Codec.parse(content, 0, {}, self).then(function (args) {
|
|
var pt = r.instance.template.getPropertyTemplateByIndex(index);
|
|
if (pt != null) {
|
|
item.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Propery, args, index));
|
|
}
|
|
else { // ft found, fi not found, this should never happen
|
|
self.queue.remove(item);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
IIPEventEventOccurred(resourceId, index, content) {
|
|
var self = this;
|
|
|
|
this.fetch(resourceId).then(function(r){
|
|
// push to the queue to guarantee serialization
|
|
var item = new AsyncReply();
|
|
var r = self.resources[resourceId];
|
|
|
|
self.queue.add(item);
|
|
|
|
Codec.parseVarArray(content, 0, content.length, self).then(function (args) {
|
|
var et = r.instance.template.getEventTemplateByIndex(index);
|
|
if (et != null) {
|
|
item.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Event, args, index));
|
|
}
|
|
else { // ft found, fi not found, this should never happen
|
|
self.queue.remove(item);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
IIPEventChildAdded(resourceId, childId)
|
|
{
|
|
var self = this;
|
|
|
|
this.fetch(resourceId).then(function(parent)
|
|
{
|
|
self.fetch(childId).then(function(child)
|
|
{
|
|
parent.instance.children.add(child);
|
|
});
|
|
});
|
|
}
|
|
|
|
IIPEventChildRemoved(resourceId, childId)
|
|
{
|
|
var self = this;
|
|
|
|
this.fetch(resourceId).then(function(parent)
|
|
{
|
|
self.fetch(childId).then(function(child)
|
|
{
|
|
parent.instance.children.remove(child);
|
|
});
|
|
});
|
|
}
|
|
|
|
IIPEventRenamed(resourceId, name)
|
|
{
|
|
this.fetch(resourceId).then(function(resource)
|
|
{
|
|
resource.instance.attributes.set("name", name.getString(0, name.length));
|
|
});
|
|
}
|
|
|
|
|
|
IIPEventAttributesUpdated(resourceId, attributes)
|
|
{
|
|
var self = this;
|
|
|
|
this.fetch(resourceId).then(function(resource)
|
|
{
|
|
var attrs = attributes.getStringArray(0, attributes.length);
|
|
|
|
self.getAttributes(resource, attrs).then(function(s)
|
|
{
|
|
resource.instance.setAttributes(s);
|
|
});
|
|
});
|
|
}
|
|
|
|
sendReply(action, callbackId)
|
|
{
|
|
return this.sendParams().addUint8(0x80 | action).addUint32(callbackId);
|
|
}
|
|
|
|
sendEvent(evt)
|
|
{
|
|
return this.sendParams().addUint8(evt);
|
|
}
|
|
|
|
IIPRequestAttachResource(callback, resourceId) {
|
|
|
|
//var sl = this.sendParams();
|
|
var self = this;
|
|
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (r != null) {
|
|
|
|
if (r.instance.applicable(self.session, ActionType.Attach, null) == Ruling.Denied)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AttachDenied);
|
|
return;
|
|
}
|
|
|
|
r.instance.on("ResourceEventOccurred", self.instance_eventOccurred, self);
|
|
r.instance.on("ResourceModified", self.instance_propertyModified, self);
|
|
r.instance.on("ResourceDestroyed", self.instance_resourceDestroyed, self);
|
|
// reply ok
|
|
|
|
var link = DC.stringToBytes(r.instance.link);
|
|
|
|
if (r instanceof DistributedResource)
|
|
self.sendReply(IIPPacketAction.AttachResource, callback)
|
|
.addUint8Array(r.instance.template.classId.value)
|
|
.addUint64(r.instance.age)
|
|
.addUint16(link.length)
|
|
.addUint8Array(link)
|
|
.addUint8Array(Codec.composePropertyValueArray(r._serialize(), self, true))
|
|
.done();
|
|
else
|
|
self.sendReply(IIPPacketAction.AttachResource, callback)
|
|
.addUint8Array(r.instance.template.classId.value)
|
|
.addUint64(r.instance.age)
|
|
.addUint16(link.length)
|
|
.addUint8Array(link)
|
|
.addUint8Array(Codec.composePropertyValueArray(r.instance.serialize(), self, true))
|
|
.done();
|
|
}
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestReattachResource(callback, resourceId, resourceAge) {
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (res != null) {
|
|
r.instance.on("ResourceEventOccurred", self.instance_eventOccurred, self);
|
|
r.instance.on("ResourceModified", self.instance_propertyModified, self);
|
|
r.instance.on("ResourceDestroyed", self.instance_resourceDestroyed, self);
|
|
// reply ok
|
|
self.sendReply(IIPPacketAction.ReattachResource, callback)
|
|
.addUint64(r.instance.age)
|
|
.addUint8Array(Codec.composePropertyValueArray(r.instance.serialize(), self, true))
|
|
.done();
|
|
}
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestDetachResource(callback, resourceId) {
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (r != null) {
|
|
r.instance.off("ResourceEventOccurred", self.instance_eventOccurred);
|
|
r.instance.off("ResourceModified", self.instance_propertyModified);
|
|
r.instance.off("ResourceDestroyed", self.instance_resourceDestroyed);
|
|
|
|
// reply ok
|
|
self.sendReply(IIPPacketAction.DetachResource, callback).done();
|
|
}
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestCreateResource(callback, storeId, parentId, content) {
|
|
var self = this;
|
|
Warehouse.get(storeId).then(function(store)
|
|
{
|
|
if (store == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.StoreNotFound);
|
|
return;
|
|
}
|
|
|
|
if (!(store instanceof IStore))
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceIsNotStore);
|
|
return;
|
|
}
|
|
|
|
// check security
|
|
if (store.instance.applicable(self.session, ActionType.CreateResource, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.CreateDenied);
|
|
return;
|
|
}
|
|
|
|
Warehouse.get(parentId).then(function(parent)
|
|
{
|
|
|
|
// check security
|
|
|
|
if (parent != null)
|
|
if (parent.instance.applicable(self.session, ActionType.AddChild, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied);
|
|
return;
|
|
}
|
|
|
|
var offset = 0;
|
|
|
|
var className = content.getString(offset + 1, content[0]);
|
|
offset += 1 + content[0];
|
|
|
|
var nameLength = content.getUint16(offset);
|
|
offset += 2;
|
|
var name = content.getString(offset, nameLength);
|
|
|
|
var cl = content.getUint32(offset);
|
|
offset += 4;
|
|
|
|
var type = window[className];
|
|
|
|
if (type == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ClassNotFound);
|
|
return;
|
|
}
|
|
|
|
Codec.parseVarArray(content, offset, cl, self).then(function(parameters)
|
|
{
|
|
offset += cl;
|
|
cl = content.getUint32(offset);
|
|
Codec.parseStructure(content, offset, cl, self).then(function(attributes)
|
|
{
|
|
offset += cl;
|
|
cl = content.length - offset;
|
|
|
|
Codec.parseStructure(content, offset, cl, self).then(function(values)
|
|
{
|
|
|
|
|
|
var resource = new (Function.prototype.bind.apply(type, values));
|
|
|
|
Warehouse.put(resource, name, store, parent);
|
|
|
|
|
|
self.sendReply(IIPPacketAction.CreateResource, callback)
|
|
.addUint32(resource.Instance.Id)
|
|
.done();
|
|
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
IIPRequestDeleteResource(callback, resourceId) {
|
|
var self = this;
|
|
Warehouse.get(resourceId).then(function(r)
|
|
{
|
|
if (r == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (r.instance.store.instance.applicable(session, ActionType.Delete, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.DeleteDenied);
|
|
return;
|
|
}
|
|
|
|
if (Warehouse.remove(r))
|
|
self.sendReply(IIPPacketAction.DeleteResource, callback).done();
|
|
else
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.DeleteFailed);
|
|
});
|
|
}
|
|
|
|
IIPRequestTemplateFromClassName(callback, className) {
|
|
|
|
var self = this;
|
|
|
|
Warehouse.getTemplateByClassName(className).then(function (t) {
|
|
if (t != null)
|
|
self.sendReply(IIPPacketAction.TemplateFromClassName, callback)
|
|
.addUint32(t.content.length)
|
|
.addUint8Array(t.content)
|
|
.done();
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestTemplateFromClassId(callback, classId) {
|
|
var self = this;
|
|
Warehouse.getTemplateByClassId(classId).then(function (t) {
|
|
if (t != null)
|
|
self.sendReply(IIPPacketAction.TemplateFromClassId, callback)
|
|
.addUint32(t.content.length)
|
|
.addUint8Array(t.content)
|
|
.done();
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestTemplateFromResourceId(callback, resourceId) {
|
|
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (r != null)
|
|
self.sendReply(IIPPacketAction.TemplateFromResourceId, callback)
|
|
.addUint32(r.instance.template.content.length)
|
|
.addUint8Array(r.instance.template.content)
|
|
.done();
|
|
else {
|
|
// reply failed
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound);
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestInvokeFunction(callback, resourceId, index, content) {
|
|
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (r != null) {
|
|
Codec.parseVarArray(content, 0, content.length, self).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) {
|
|
self.sendReply(IIPPacketAction.InvokeFunction, callback)
|
|
.addUint8Array(Codec.compose(res, self))
|
|
.done();
|
|
});
|
|
}
|
|
else {
|
|
// function not found on a distributed object
|
|
}
|
|
}
|
|
else {
|
|
|
|
var fi = r[ft.name];
|
|
|
|
if (r.instance.applicable(self.session, ActionType.Execute, ft) == Ruling.Denied)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.InvokeDenied);
|
|
return;
|
|
}
|
|
|
|
if (fi instanceof Function) {
|
|
args.push(self);
|
|
|
|
var rt = fi.apply(r, args);
|
|
|
|
|
|
if (rt instanceof AsyncReply) {
|
|
rt.then(function (res) {
|
|
self.sendReply(IIPPacketAction.InvokeFunction, callback)
|
|
.addUint8Array(Codec.compose(res, self))
|
|
.done();
|
|
});
|
|
}
|
|
else {
|
|
self.sendReply(IIPPacketAction.InvokeFunction, callback)
|
|
.addUint8Array(Codec.compose(rt, self))
|
|
.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 self = this;
|
|
|
|
Warehouse.get(resourceId).then(function (r) {
|
|
if (r != null) {
|
|
var pt = r.instance.template.getFunctionTemplateByIndex(index);
|
|
if (pt != null) {
|
|
if (r instanceof DistributedResource) {
|
|
self.sendReply(IIPPacketAction.GetProperty, callback)
|
|
.addUint8Array(Codec.compose(r._get(pt.index), self))
|
|
.done();
|
|
}
|
|
else {
|
|
var pv = r[pt.name];
|
|
self.sendReply(IIPPacketAction.GetProperty)
|
|
.addUint8Array(Codec.compose(pv, self))
|
|
.done();
|
|
}
|
|
}
|
|
else {
|
|
// pt not found
|
|
}
|
|
}
|
|
else {
|
|
// resource not found
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestGetPropertyIfModifiedSince(callback, resourceId, index, age) {
|
|
|
|
var self = this;
|
|
|
|
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];
|
|
self.sendReply(IIPPacketAction.GetPropertyIfModified, callback)
|
|
.addUint8Array(Codec.compose(pv, self))
|
|
.done();
|
|
}
|
|
else
|
|
{
|
|
self.sendReply(IIPPacketAction.GetPropertyIfModified, callback)
|
|
.addUint8(DataType.NotModified)
|
|
.done();
|
|
}
|
|
}
|
|
else {
|
|
// pt not found
|
|
}
|
|
}
|
|
else {
|
|
// resource not found
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestSetProperty(callback, resourceId, index, content) {
|
|
|
|
var self = this;
|
|
|
|
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) {
|
|
self.sendReply(IIPPacketAction.SetProperty, callback)
|
|
.done();
|
|
}).error(function(x){
|
|
self.sendError(x.type, callback, x.code, x.message)
|
|
.done();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
if (r.instance.applicable(self.session, ActionType.SetProperty, pt) == Ruling.Denied)
|
|
{
|
|
self.sendError(AsyncReply.ErrorType.Exception, callback, ExceptionCode.SetPropertyDenied);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (r[pt.name] instanceof DistributedPropertyContext)
|
|
value = new DistributedPropertyContext(this, value);
|
|
|
|
r[pt.name] = value;
|
|
self.sendReply(IIPPacketAction.SetProperty, callback).done();
|
|
}
|
|
catch(ex)
|
|
{
|
|
self.sendError(AsyncReply.ErrorType.Exception, callback, 0, ex.toString()).done();
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
else {
|
|
// property not found
|
|
self.sendError(AsyncReply.ErrorType.Management, callback, ExceptionCode.PropertyNotFound).done();
|
|
}
|
|
}
|
|
else {
|
|
// resource not found
|
|
self.sendError(AsyncReply.ErrorType.Management, callback, ExceptionCode.PropertyNotFound).done();
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestInquireResourceHistory(callback, resourceId, fromDate, toDate)
|
|
{
|
|
var self = this;
|
|
Warehouse.get(resourceId).then(function(r)
|
|
{
|
|
if (r != null)
|
|
{
|
|
r.instance.store.getRecord(r, fromDate, toDate).then(function(results)
|
|
{
|
|
var history = Codec.composeHistory(results, self, true);
|
|
self.sendReply(IIPPacketAction.ResourceHistory, callback)
|
|
.addUint8Array(history)
|
|
.done();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
IIPRequestQueryResources(callback, resourceLink)
|
|
{
|
|
var self = this;
|
|
|
|
Warehouse.query(resourceLink).then(function(resources)
|
|
{
|
|
|
|
var list = resources.filter(function(r){return r.instance.applicable(self.session, ActionType.Attach, null) != Ruling.Denied});
|
|
|
|
if (list.length == 0)
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
else
|
|
self.sendReply(IIPPacketAction.QueryLink, callback)
|
|
.addUint8Array(Codec.composeResourceArray(list, self, true))
|
|
.done();
|
|
});
|
|
}
|
|
|
|
create(store, parent, className, parameters, attributes, values)
|
|
{
|
|
var reply = new AsyncReply();
|
|
var sb = DC.stringToBytes(className);
|
|
|
|
var pkt = BL().addUint32(store.instance.id)
|
|
.addUint32(parent.instance.id)
|
|
.addUint32(sb.length)
|
|
.addUint8Array(sb)
|
|
.addUint8Array(Codec.composeVarArray(parameters, this, true))
|
|
.addUint8Array(Codec.composeStructure(attributes, this, true, true, true))
|
|
.addUint8Array(Codec.composeStructure(values, this));
|
|
|
|
pkt.addUint32(pkt.length, 8);
|
|
|
|
this.sendRequest(IIPPacket.IIPPacketAction.CreateResource).addUint8Array(pkt.ToArray()).done().then(function(args)
|
|
{
|
|
var rid = args[0];
|
|
|
|
self.fetch(rid).then(function(r)
|
|
{
|
|
reply.trigger(r);
|
|
});
|
|
|
|
});
|
|
|
|
return reply;
|
|
}
|
|
|
|
query(resourceLink)
|
|
{
|
|
var reply = new AsyncReply();
|
|
var self = this;
|
|
|
|
var sb = DC.stringToBytes(resourceLink);
|
|
|
|
this.sendRequest(IIPPacketAction.QueryLink)
|
|
.addUint16(sb.length)
|
|
.addUint8Array(sb)
|
|
.done()
|
|
.then(function(args)
|
|
{
|
|
Codec.parseResourceArray(args[0], 0, args[0].length, self).then(function(resources) {
|
|
reply.trigger(resources);
|
|
});
|
|
}).error(function(ex){
|
|
reply.triggerError(ex);
|
|
});
|
|
|
|
return reply;
|
|
}
|
|
|
|
getTemplate(classId) {
|
|
if (this.templates.contains(classId))
|
|
return new AsyncReply(this.templates.item(classId));
|
|
else if (this.templateRequests.contains(classId))
|
|
return this.templateRequests.item(classId);
|
|
|
|
var reply = new AsyncReply();
|
|
this.templateRequests.add(classId.valueOf(), reply);
|
|
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.TemplateFromClassId)
|
|
.addUint8Array(classId.value)
|
|
.done()
|
|
.then(function (rt) {
|
|
self.templateRequests.remove(classId);
|
|
self.templates.add(rt[0].classId.valueOf(), rt[0]);
|
|
Warehouse.putTemplate(rt[0]);
|
|
reply.trigger(rt[0]);
|
|
});
|
|
|
|
return reply;
|
|
}
|
|
|
|
// IStore interface
|
|
get(path) {
|
|
|
|
var rt = new AsyncReply();
|
|
|
|
this.query(path).then(function(ar)
|
|
{
|
|
if (ar != null && ar.length > 0)
|
|
rt.trigger(ar[0]);
|
|
else
|
|
rt.trigger(null);
|
|
}).error(function(ex) {rt.triggerError(ex);});
|
|
|
|
return rt;
|
|
|
|
/*
|
|
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 link = data.get
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.ResourceIdFromResourceLink)
|
|
.addUint16(.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
|
|
// or not
|
|
return new AsyncReply(this.resources[id]);
|
|
//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();
|
|
|
|
this.resourceRequests[id] = reply;
|
|
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.AttachResource)
|
|
.addUint32(id)
|
|
.done()
|
|
.then(function (rt) {
|
|
var dr = new DistributedResource(self, id, rt[1], rt[2]);
|
|
//var dr = new DistributedResource(self, tmp, id, rt[1], rt[2]);
|
|
|
|
self.getTemplate(rt[0]).then(function (tmp) {
|
|
|
|
// ClassId, ResourceAge, ResourceLink, Content
|
|
Warehouse.put(dr, id.toString(), self, null, tmp);
|
|
|
|
|
|
Codec.parsePropertyValueArray(rt[3], 0, rt[3].length, self).then(function (ar) {
|
|
dr._attached(ar);
|
|
delete self.resourceRequests[id];
|
|
reply.trigger(dr);
|
|
});
|
|
});
|
|
});
|
|
|
|
return reply;
|
|
}
|
|
|
|
getRecord(resource, fromDate, toDate)
|
|
{
|
|
if (resource instanceof DistributedResource)
|
|
{
|
|
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var reply = new AsyncReply();
|
|
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.ResourceHistory)
|
|
.addUint32(resource._p.instanceId)
|
|
.addDateTime(fromDate).addDateTime(toDate)
|
|
.done()
|
|
.then(function(rt)
|
|
{
|
|
Codec.parseHistory(rt[0], 0, rt[0].length, resource, self).then(function(history)
|
|
{
|
|
reply.trigger(history);
|
|
});
|
|
});
|
|
|
|
return reply;
|
|
}
|
|
else
|
|
return new AsyncReply(null);
|
|
}
|
|
|
|
instance_resourceDestroyed(resource) {
|
|
// compose the packet
|
|
this.sendEvent(IIPPacketEvent.ResourceDestroyed)
|
|
.addUint32(resource.instance.id)
|
|
.done();
|
|
}
|
|
|
|
instance_propertyModified(resource, name, newValue) {
|
|
var pt = resource.instance.template.getPropertyTemplateByName(name);
|
|
|
|
if (pt == null)
|
|
return;
|
|
|
|
this.sendEvent(IIPPacketEvent.PropertyUpdated)
|
|
.addUint32(resource.instance.id)
|
|
.addUint8(pt.index)
|
|
.addUint8Array(Codec.compose(newValue, this))
|
|
.done();
|
|
}
|
|
|
|
instance_eventOccurred(resource, issuer, receivers, name, args) {
|
|
var et = resource.instance.template.getEventTemplateByName(name);
|
|
|
|
if (et == null)
|
|
return;
|
|
|
|
if (receivers != null)
|
|
if (receivers.indexOf(this.session) < 0)
|
|
return;
|
|
|
|
if (resource.instance.applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied)
|
|
return;
|
|
|
|
// compose the packet
|
|
this.sendEvent(IIPPacketEvent.EventOccurred)
|
|
.addUint32(resource.instance.id)
|
|
.addUint8(et.index)
|
|
.addUint8Array(Codec.composeVarArray(args, this, true))
|
|
.done();
|
|
|
|
}
|
|
|
|
|
|
|
|
IIPRequestAddChild(callback, parentId, childId)
|
|
{
|
|
var self = this;
|
|
Warehouse.get(parentId).then(function(parent)
|
|
{
|
|
if (parent == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
Warehouse.get(childId).then(function(child)
|
|
{
|
|
if (child == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (parent.instance.applicable(self.session, ActionType.AddChild, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied);
|
|
return;
|
|
}
|
|
|
|
if (child.instance.applicable(self.session, ActionType.AddParent, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AddParentDenied);
|
|
return;
|
|
}
|
|
|
|
parent.instance.children.add(child);
|
|
|
|
self.sendReply(IIPPacketAction.AddChild, callback)
|
|
.done();
|
|
//child.Instance.Parents
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
IIPRequestRemoveChild(callback, parentId, childId)
|
|
{
|
|
var self = this;
|
|
|
|
Warehouse.get(parentId).then(function(parent)
|
|
{
|
|
if (parent == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
Warehouse.get(childId).then(function(child)
|
|
{
|
|
if (child == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (parent.instance.applicable(self.session, ActionType.RemoveChild, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied);
|
|
return;
|
|
}
|
|
|
|
if (child.instance.applicable(self.session, ActionType.RemoveParent, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.AddParentDenied);
|
|
return;
|
|
}
|
|
|
|
parent.instance.children.remove(child);
|
|
|
|
self.sendReply(IIPPacketAction.RemoveChild, callback)
|
|
.done();
|
|
//child.Instance.Parents
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
IIPRequestRenameResource(callback, resourceId, name)
|
|
{
|
|
var self = this;
|
|
Warehouse.get(resourceId).then(function(resource)
|
|
{
|
|
if (resource == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (resource.instance.applicable(self.session, ActionType.Rename, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.RenameDenied);
|
|
return;
|
|
}
|
|
|
|
resource.instance.name = name.getString(0, name.length);
|
|
self.sendReply(IIPPacketAction.RenameResource, callback)
|
|
.done();
|
|
});
|
|
}
|
|
|
|
IIPRequestResourceChildren(callback, resourceId)
|
|
{
|
|
var self = this;
|
|
Warehouse.get(resourceId).then(function(resource)
|
|
{
|
|
if (resource == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
self.sendReply(IIPPacketAction.ResourceChildren, callback)
|
|
.addUint8Array(Codec.composeResourceArray(resource.instance.children.toArray(), this, true))
|
|
.done();
|
|
|
|
});
|
|
}
|
|
|
|
IIPRequestResourceParents(callback, resourceId)
|
|
{
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function(resource)
|
|
{
|
|
if (resource == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
self.sendReply(IIPPacketAction.ResourceParents, callback)
|
|
.addUint8Array(Codec.composeResourceArray(resource.instance.parents.toArray(), this, true))
|
|
.done();
|
|
});
|
|
}
|
|
|
|
IIPRequestClearAttributes(callback, resourceId, attributes, all = false)
|
|
{
|
|
Warehouse.get(resourceId).then(function(r)
|
|
{
|
|
if (r == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (r.instance.store.instance.applicable(self.session, ActionType.UpdateAttributes, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeDenied);
|
|
return;
|
|
}
|
|
|
|
var attrs = [];
|
|
|
|
if (!all)
|
|
attrs = attributes.getStringArray(0, attributes.length);
|
|
|
|
if (r.instance.removeAttributes(attrs))
|
|
self.sendReply(all ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes, callback)
|
|
.done();
|
|
else
|
|
self.sendError(AsyncReply.ErrorType.Management, callback, ExceptionCode.UpdateAttributeFailed);
|
|
|
|
});
|
|
}
|
|
|
|
IIPRequestUpdateAttributes(callback, resourceId, attributes, clearAttributes = false)
|
|
{
|
|
var self = this;
|
|
|
|
Warehouse.get(resourceId).then(function(r)
|
|
{
|
|
if (r == null)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound);
|
|
return;
|
|
}
|
|
|
|
if (r.instance.store.instance.applicable(self.session, ActionType.UpdateAttributes, null) != Ruling.Allowed)
|
|
{
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeDenied);
|
|
return;
|
|
}
|
|
|
|
Codec.parseStructure(attributes, 0, attributes.Length, this).then(function(attrs) {
|
|
if (r.instance.setAttributes(attrs, clearAttributes))
|
|
self.sendReply(clearAttributes ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes,
|
|
callback)
|
|
.done();
|
|
else
|
|
self.sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeFailed);
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getChildren(resource)
|
|
{
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var rt = new AsyncReply();
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.ResourceChildren)
|
|
.addUint32(resource._p.instanceId)
|
|
.done()
|
|
.then(function(d)
|
|
{
|
|
|
|
Codec.parseResourceArray(d, 0, d.length, self).then(function(resources)
|
|
{
|
|
rt.trigger(resources);
|
|
}).error(function(ex) { rt.triggerError(ex); });
|
|
});
|
|
|
|
return rt;
|
|
}
|
|
|
|
getParents(resource)
|
|
{
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var rt = new AsyncReply();
|
|
var self = this;
|
|
|
|
this.sendRequest(IIPPacketAction.ResourceParents)
|
|
.addUint32(resource._p.instanceId)
|
|
.done()
|
|
.then(function(d)
|
|
{
|
|
Codec.parseResourceArray(d, 0, d.length, this).then(function(resources)
|
|
{
|
|
rt.trigger(resources);
|
|
}).error(function(ex) { rt.triggerError(ex);});
|
|
});
|
|
|
|
return rt;
|
|
}
|
|
|
|
removeAttributes(resource, attributes = null)
|
|
{
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var rt = new AsyncReply();
|
|
|
|
if (attributes == null)
|
|
this.sendRequest(IIPPacketAction.ClearAllAttributes)
|
|
.addUint32(resource._p.instanceId)
|
|
.done()
|
|
.then(function(ar)
|
|
{
|
|
rt.trigger(true);
|
|
}).error(function(ex) { rt.triggerError(ex); });
|
|
else
|
|
{
|
|
var attrs = DC.stringArrayToBytes(attributes);
|
|
this.sendRequest(IIPPacketAction.ClearAttributes)
|
|
.addUint32(resource.instance.id)
|
|
.addUint32(attrs.length)
|
|
.addUint8Array(attrs)
|
|
.done()
|
|
.then(function(ar)
|
|
{
|
|
rt.trigger(true);
|
|
}).error(function(ex) { rt.triggerChunk(ex); });
|
|
}
|
|
|
|
return rt;
|
|
}
|
|
|
|
setAttributes(resource, attributes, clearAttributes = false)
|
|
{
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var rt = new AsyncReply();
|
|
|
|
this.sendRequest(clearAttributes ? IIPPacketAction.UpdateAllAttributes : IIPPacketAction.UpdateAttributes)
|
|
.addUint32(resource._p.instanceId)
|
|
.addUint8Array(Codec.composeStructure(attributes, this, true, true, true))
|
|
.done()
|
|
.then(function(ar)
|
|
{
|
|
rt.trigger(true);
|
|
}).error(function(ex) {rt.triggerError(ex);});
|
|
|
|
return rt;
|
|
}
|
|
|
|
getAttributes(resource, attributes = null)
|
|
{
|
|
if (resource._p.connection != this)
|
|
return new AsyncReply(null);
|
|
|
|
var rt = new AsyncReply();
|
|
var self = this;
|
|
|
|
if (attributes == null)
|
|
{
|
|
this.sendRequest(IIPPacketAction.GetAllAttributes)
|
|
.addUint32(resource._p.instanceId)
|
|
.done()
|
|
.then(function(ar)
|
|
{
|
|
Codec.parseStructure(ar[0], 0, ar[0].length, this).then(function(st)
|
|
{
|
|
for (var a in st)
|
|
resource.instance.attributes.set(a, st[a]);
|
|
rt.trigger(st);
|
|
}).error(function(ex) { rt.triggerError(ex); });
|
|
});
|
|
}
|
|
else
|
|
{
|
|
var attrs = DC.stringArrayToBytes(attributes);
|
|
this.sendRequest(IIPPacketAction.GetAttributes)
|
|
.addUint32(resource._p.instanceId)
|
|
.addUint32(attrs.length)
|
|
.addUint8Array(attrs)
|
|
.done()
|
|
.then(function(ar)
|
|
{
|
|
Codec.parseStructure(ar[0], 0, ar[0].length, self).then(function(st)
|
|
{
|
|
for (var a in st)
|
|
resource.instance.attributes.set(a, st[a]);
|
|
rt.trigger(st);
|
|
}).error(function(ex) { rt.triggerError(ex); });
|
|
});
|
|
}
|
|
|
|
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 25/07/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class DistributedResource extends IResource
|
|
{
|
|
destroy()
|
|
{
|
|
this.destroyed = true;
|
|
this._emit("destroy", this);
|
|
}
|
|
|
|
constructor(connection, instanceId, age, link)
|
|
{
|
|
super();
|
|
|
|
this._p = {
|
|
isAttached: false,
|
|
connection: connection,
|
|
instanceId: instanceId,
|
|
age: age,
|
|
link: link,
|
|
properties: []
|
|
};
|
|
}
|
|
|
|
_serialize()
|
|
{
|
|
var props = [];
|
|
|
|
for (var i = 0; i < this._p.properties.length; i++)
|
|
props.push(new PropertyValue(this._p.properties[i],
|
|
this.instance.getAge(i),
|
|
this.instance.getModificationDate(i)));
|
|
|
|
return props;
|
|
}
|
|
|
|
_attached(properties)
|
|
{
|
|
|
|
if (this._isAttached)
|
|
return false;
|
|
else
|
|
{
|
|
for(var i = 0; i < properties.length; i++)
|
|
{
|
|
this.instance.setAge(i, properties[i].age);
|
|
this.instance.setModificationDate(i, properties[i].date);
|
|
this._p.properties.push(properties[i].value);
|
|
}
|
|
|
|
|
|
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.instance.template.functions.length; i++)
|
|
{
|
|
var ft = this.instance.template.functions[i];
|
|
this[ft.name] = makeFunc(ft.index);
|
|
}
|
|
|
|
for(var i = 0; i < this.instance.template.properties.length; i++)
|
|
{
|
|
var pt = this.instance.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.instance.template.getEventTemplateByIndex(index);
|
|
this._emitArgs(et.name, args);
|
|
this.instance._emitResourceEvent(null, null, et.name, args);
|
|
}
|
|
|
|
_invoke(index, args) {
|
|
if (this.destroyed)
|
|
throw new Exception("Trying to access destroyed object");
|
|
|
|
if (index >= this.instance.template.functions.length)
|
|
throw new Exception("Function index is incorrect");
|
|
|
|
return this._p.connection.sendInvoke(this._p.instanceId, index, args);
|
|
|
|
/*
|
|
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.instance.template.getPropertyTemplateByIndex(index);
|
|
this._p.properties[index] = value;
|
|
this.instance.emitModification(pt, 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)
|
|
.addUint32(self._p.instanceId).addUint8(index).addUint8Array(parameters)
|
|
.done()
|
|
.then(function(res)
|
|
{
|
|
// not really needed, server will always send property modified, this only happens if the programmer forgot to emit in property setter
|
|
self._p.properties[index] = value;
|
|
reply.trigger(null);
|
|
});
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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 | (this.isVoid ? 0x8 : 0x0))
|
|
.addUint32(exp.length).addUint8Array(exp)
|
|
.addUint8(name.length).addUint8Array(name).toArray();
|
|
}
|
|
else
|
|
return rt.addUint8(this.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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const IIPAuthPacketCommand =
|
|
{
|
|
Action: 0,
|
|
Declare: 1,
|
|
Acknowledge: 2,
|
|
Error: 3
|
|
};
|
|
|
|
const IIPAuthPacketAction =
|
|
{
|
|
// Authenticate
|
|
AuthenticateHash: 0,
|
|
NewConnection: 0x20,
|
|
ResumeConnection: 0x21,
|
|
ConnectionEstablished: 0x28
|
|
};
|
|
|
|
|
|
const 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const IIPPacketCommand =
|
|
{
|
|
Event: 0,
|
|
Request: 1,
|
|
Reply: 2,
|
|
Report: 3
|
|
};
|
|
|
|
const IIPPacketReport =
|
|
{
|
|
ManagementError: 0,
|
|
ExecutionError: 1,
|
|
ProgressReport: 0x8,
|
|
ChunkStream: 0x9
|
|
};
|
|
|
|
const IIPPacketEvent =
|
|
{
|
|
// Event Manage
|
|
ResourceReassigned : 0,
|
|
ResourceDestroyed: 1,
|
|
ChildAdded: 2,
|
|
ChildRemoved: 3,
|
|
Renamed: 4,
|
|
|
|
// Event Invoke
|
|
PropertyUpdated : 0x10,
|
|
EventOccurred: 0x11,
|
|
|
|
// Attribute
|
|
AttributesUpdated: 0x18
|
|
|
|
};
|
|
|
|
const IIPPacketAction =
|
|
{
|
|
// Request Manage
|
|
AttachResource: 0,
|
|
ReattachResource: 1,
|
|
DetachResource: 2,
|
|
CreateResource: 3,
|
|
DeleteResource: 4,
|
|
AddChild: 5,
|
|
RemoveChild: 6,
|
|
RenameResource: 7,
|
|
|
|
// Request Inquire
|
|
TemplateFromClassName: 8,
|
|
TemplateFromClassId: 9,
|
|
TemplateFromResourceId: 10,
|
|
QueryLink: 11,
|
|
ResourceHistory: 12,
|
|
ResourceChildren: 13,
|
|
ResourceParents: 14,
|
|
|
|
// Request Invoke
|
|
InvokeFunction: 16,
|
|
GetProperty: 17,
|
|
GetPropertyIfModified: 18,
|
|
SetProperty: 19,
|
|
|
|
// Request Attribute
|
|
GetAllAttributes: 24,
|
|
UpdateAllAttributes: 25,
|
|
ClearAllAttributes: 26,
|
|
GetAttributes: 27,
|
|
UpdateAttributes: 28,
|
|
ClearAttributes: 29
|
|
};
|
|
|
|
|
|
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;
|
|
this.originalOffset = 0;
|
|
}
|
|
|
|
notEnough(offset, ends, needed)
|
|
{
|
|
if (offset + needed > ends)
|
|
{
|
|
this.dataLengthNeeded = needed - (ends - this.originalOffset);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
parse(data, offset, ends)
|
|
{
|
|
this.originalOffset = 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 if (this.command == IIPPacketCommand.Report)
|
|
{
|
|
this.report = (data.getUint8(offset++) & 0x3f);
|
|
|
|
if (this.notEnough(offset, ends, 4))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.callbackId = 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.ChildAdded
|
|
|| this.event == IIPPacketEvent.ChildRemoved)
|
|
{
|
|
if (this.notEnough(offset, ends, 4))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.childId = data.getUint32(offset);
|
|
offset += 4;
|
|
}
|
|
else if(this.event == IIPPacketEvent.Renamed)
|
|
{
|
|
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.content = data.clip(offset, cl);
|
|
|
|
offset += cl;
|
|
}
|
|
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.EventOccurred)
|
|
{
|
|
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;
|
|
}
|
|
// Attribute
|
|
else if (this.event == IIPPacketEvent.AttributesUpdated)
|
|
{
|
|
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.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, 12))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
this.resourceAge = data.getUint64(offset);
|
|
offset += 8;
|
|
}
|
|
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, 12))
|
|
return -dataLengthNeeded;
|
|
|
|
this.storeId = data.getUint32(offset);
|
|
offset += 4;
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
var cl = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
if (this.notEnough(offset, ends, cl))
|
|
return -dataLengthNeeded;
|
|
|
|
this.content = data.clip(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.AddChild
|
|
|| this.action == IIPPacketAction.RemoveChild)
|
|
{
|
|
if (this.notEnough(offset, ends, 8))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
this.childId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
}
|
|
else if (this.action == IIPPacketAction.RenameResource)
|
|
{
|
|
if (this.notEnough(offset, ends, 6))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
var cl = data.getUint16(offset);
|
|
offset += 2;
|
|
|
|
if (this.notEnough(offset, ends, cl))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.content = data.clip(offset, cl);
|
|
offset += cl;
|
|
|
|
}
|
|
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.TemplateFromResourceId)
|
|
{
|
|
if (this.notEnough(offset, ends, 4))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
}
|
|
else if (this.action == IIPPacketAction.QueryLink)
|
|
{
|
|
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.ResourceChildren
|
|
|| this.action == IIPPacketAction.ResourceParents)
|
|
{
|
|
if (this.notEnough(offset, ends, 4))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
}
|
|
else if (this.action == IIPPacketAction.ResourceHistory)
|
|
{
|
|
if (this.notEnough(offset, ends, 20))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
|
|
this.fromDate = data.getDateTime(offset);
|
|
offset += 8;
|
|
|
|
this.toDate = data.getDateTime(offset);
|
|
offset += 8;
|
|
|
|
}
|
|
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.getUint64(offset);
|
|
offset += 8;
|
|
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Attribute
|
|
else if (this.action == IIPPacketAction.UpdateAllAttributes
|
|
|| this.action == IIPPacketAction.GetAttributes
|
|
|| this.action == IIPPacketAction.UpdateAttributes
|
|
|| this.action == IIPPacketAction.ClearAttributes)
|
|
{
|
|
if (this.notEnough(offset, ends, 8))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.resourceId = data.getUint32(offset);
|
|
offset += 4;
|
|
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.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.getUint64(offset);
|
|
offset += 8;
|
|
|
|
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.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.TemplateFromResourceId
|
|
|| this.action == IIPPacketAction.QueryLink
|
|
|| this.action == IIPPacketAction.ResourceChildren
|
|
|| this.action == IIPPacketAction.ResourceParents
|
|
|| this.action == IIPPacketAction.ResourceHistory
|
|
// Attribute
|
|
|| this.action == IIPPacketAction.GetAllAttributes
|
|
|| this.action == IIPPacketAction.GetAttributes)
|
|
{
|
|
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.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.Report)
|
|
{
|
|
if (this.report == IIPPacketReport.ManagementError)
|
|
{
|
|
if (this.notEnough(offset, ends, 2))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.errorCode = data.getUint16(offset);
|
|
offset += 2;
|
|
}
|
|
else if (this.report == IIPPacketReport.ExecutionError)
|
|
{
|
|
if (this.notEnough(offset, ends, 2))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.errorCode = data.getUint16(offset);
|
|
offset += 2;
|
|
|
|
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.errorMessage = data.getString(offset, cl);
|
|
offset += cl;
|
|
}
|
|
else if (this.report == IIPPacketReport.ProgressReport)
|
|
{
|
|
if (this.notEnough(offset, ends, 8))
|
|
return -this.dataLengthNeeded;
|
|
|
|
this.progressValue = data.getInt32(offset);
|
|
offset += 4;
|
|
this.progressMax = data.getInt32(offset);
|
|
offset += 4;
|
|
}
|
|
else if (this.report == IIPPacketReport.ChunkStream)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return offset - this.originalOffset;
|
|
}
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class Instance extends IEventHandler
|
|
{
|
|
|
|
getAge(index)
|
|
{
|
|
if (index < this.ages.length)
|
|
return this.ages[index];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
setAge(index, value)
|
|
{
|
|
if (index < this.ages.length)
|
|
{
|
|
this.ages[index] = value;
|
|
if (value > this.instanceAge)
|
|
this.instanceAge = value;
|
|
}
|
|
}
|
|
|
|
getModificationDate(index)
|
|
{
|
|
if (index < this.modificationDates.length)
|
|
return this.modificationDates[index];
|
|
else
|
|
return new Date(0);
|
|
}
|
|
|
|
setModificationDate(index, value)
|
|
{
|
|
if (index < this.modificationDates.length)
|
|
{
|
|
this.modificationDates[index] = value;
|
|
|
|
if (value > this.instanceModificationDate)
|
|
this.instanceModificationDate = value;
|
|
}
|
|
}
|
|
|
|
loadProperty(name, age, modificationDate, value)
|
|
{
|
|
var pt = this.template.getPropertyTemplateByName(name);
|
|
|
|
if (pt == null)
|
|
return false;
|
|
|
|
this.resource[name] = value;
|
|
|
|
this.setAge(pt.index, age);
|
|
this.setModificationDate(pt.index, modificationDate);
|
|
|
|
return true;
|
|
}
|
|
|
|
deserialize(properties)
|
|
{
|
|
|
|
for (var i = 0; i < properties.length; i++)
|
|
{
|
|
var pt = this.template.GetPropertyTemplateByIndex(i);
|
|
if (pt != null)
|
|
{
|
|
var pv = properties[i];
|
|
this.loadProperty(pt.name, pv.age, pv.date, pv.value);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
serialize()
|
|
{
|
|
var props = [];
|
|
|
|
for (var i = 0; i < this.template.properties.length; i++)
|
|
props.push(new PropertyValue(this.resource[this.template.properties[i].name],
|
|
this.ages[this.template.properties[i].index],
|
|
this.modificationDates[this.template.properties[i].index]));
|
|
|
|
return props;
|
|
}
|
|
|
|
isStorable()
|
|
{
|
|
return resource instanceof Storable;
|
|
}
|
|
|
|
emitModification(pt, value)
|
|
{
|
|
this.instanceAge++;
|
|
|
|
var now = new Date();
|
|
|
|
this.ages[pt.index] = this.instanceAge;
|
|
this.modificationDates[pt.index] = now;
|
|
|
|
if (pt.recordable)
|
|
this.store.record(this.resource, pt.name, value, this.ages[pt.index], now);
|
|
|
|
super._emit("ResourceModified", this.resource, pt.name, value);
|
|
this.resource._emit("modified", pt.name, value);
|
|
}
|
|
|
|
modified(propertyName = null)
|
|
{
|
|
if (propertyName == null)
|
|
propertyName = modified.caller.name;
|
|
|
|
var val = {};
|
|
if (this.getPropertyValue(propertyName, val))
|
|
{
|
|
var pt = this.template.getPropertyTemplateByName(propertyName);
|
|
this.emitModification(pt, val.value)
|
|
}
|
|
}
|
|
|
|
_emitResourceEvent(issuer, receivers, name, args)
|
|
{
|
|
super._emit("ResourceEventOccurred", this.resource, issuer, receivers, name, 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, customTemplate = null, age = 0)
|
|
{
|
|
super();
|
|
|
|
this.store = store;
|
|
this.resource = resource;
|
|
this.id = id;
|
|
this.name = name;
|
|
|
|
this.instanceAge = age;
|
|
this.instanceModificationDate = new Date(0);
|
|
|
|
this.children = new AutoList();
|
|
this.parents = new AutoList();
|
|
this.managers = new AutoList();
|
|
|
|
this.attributes = new KeyList();
|
|
|
|
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);
|
|
});
|
|
|
|
if (customTemplate != null)
|
|
this.template = customTemplate;
|
|
else
|
|
this.template = Warehouse.getTemplateByType(this.resource.constructor);
|
|
|
|
// set ages
|
|
this.ages = [];
|
|
this.modificationDates = [];
|
|
|
|
for(var i = 0; i < this.template.properties.length; i++)
|
|
{
|
|
this.ages.push(0);
|
|
this.modificationDates.push(new Date(0));
|
|
}
|
|
|
|
// connect events
|
|
for (var i = 0; i < this.template.events.length; i++)
|
|
this.resource.on(this.template.events[i].name, this._makeHandler(this.template.events[i].name));
|
|
|
|
}
|
|
|
|
_makeHandler(name)
|
|
{
|
|
var self = this;
|
|
return function(args)
|
|
{
|
|
if (args instanceof CustomResourceEvent)
|
|
self._emitResourceEvent(args.issuer, args.receivers, name, args.params);
|
|
else
|
|
self._emitResourceEvent(null, null, name, args);
|
|
};
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Check for permission.
|
|
/// </summary>
|
|
/// <param name="session">Caller sessions.</param>
|
|
/// <param name="action">Action type</param>
|
|
/// <param name="member">Function or property to check for permission.</param>
|
|
/// <returns>Ruling.</returns>
|
|
applicable(session, action, member, inquirer)
|
|
{
|
|
for (var i = 0; i < this.managers.length; i++)
|
|
{
|
|
var r = this.managers.item(i).applicable(this.resource, session, action, member, inquirer);
|
|
if (r != Ruling.DontCare)
|
|
return r;
|
|
}
|
|
|
|
return Ruling.DontCare;
|
|
}
|
|
|
|
|
|
|
|
removeAttributes(attributes = null)
|
|
{
|
|
if (attributes == null)
|
|
this.attributes.clear();
|
|
else
|
|
{
|
|
for(var i = 0; i < attributes.length; i++)
|
|
this.attributes.remove(attributes[i]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
getAttributes(attributes = null)
|
|
{
|
|
var st = new Structure();
|
|
|
|
if (attributes == null)
|
|
{
|
|
attributes = this.attributes.keys.slice(0);
|
|
attributes.push("managers");
|
|
}
|
|
|
|
for(var i = 0; i < attributes.length; i++)
|
|
{
|
|
var attr = attributes[i];
|
|
|
|
if (attr == "name")
|
|
st["name"] = this.name;
|
|
|
|
else if (attr == "managers")
|
|
{
|
|
var mngrs = new StructureArray();
|
|
|
|
for(var j = 0; j < this.managers.length; j++)
|
|
{
|
|
var manager = this.managers.item(j);
|
|
var sm = new Structure();
|
|
sm["type"] = manager.constructor.name;
|
|
sm["settings"] = manager.settings;
|
|
|
|
mngrs.push(sm);
|
|
}
|
|
|
|
st["managers"] = mngrs;
|
|
|
|
}
|
|
else
|
|
st[attr] = this.attributes.item(attr);
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
setAttributes(attributes, clearAttributes = false)
|
|
{
|
|
|
|
if (clearAttributes)
|
|
this.attributes.clear();
|
|
|
|
|
|
for (var attr in attributes)
|
|
if (attr == "name")
|
|
this.name = attributes[attr];
|
|
else if (attr == "managers")
|
|
{
|
|
this.managers.clear();
|
|
|
|
var mngrs = attributes[attr];
|
|
|
|
for (var i = 0; i < mngrs.length; i++)
|
|
{
|
|
var mngr = mngrs[i];
|
|
|
|
var type = window[mngr];
|
|
|
|
var settings = mngr["settings"];
|
|
|
|
var manager = new (Function.prototype.bind.apply(type));
|
|
|
|
if (manager instanceof IPermissionsManager)
|
|
{
|
|
manager.initialize(settings, this.resource);
|
|
this.managers.add(manager);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.attributes.set(attr, attributes[attr]);
|
|
}
|
|
|
|
|
|
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 26/08/2017.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const 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();
|
|
var pv = (this.permission >> 1) | (this.recordable ? 1 : 0);
|
|
|
|
if (this.writeExpansion != null && this.readExpansion != null)
|
|
{
|
|
var rexp = DC.stringToBytes(this.readExpansion);
|
|
var wexp = DC.stringToBytes(this.writeExpansion);
|
|
return rt.addUint8(0x38 | pv)
|
|
.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 | pv)
|
|
.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 | pv)
|
|
.addUint32(rexp.length)
|
|
.addUint8Array(rexp)
|
|
.addUint8(name.length)
|
|
.addUint8Array(name).toArray();
|
|
}
|
|
else
|
|
return rt.addUint8(0x20 | pv)
|
|
.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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class ResourceTemplate {
|
|
|
|
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 = SHA256.compute(DC.stringToBytes(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;
|
|
pt.recordable = template.properties[i].recordable;
|
|
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.recordable = ((data.getUint8(offset) & 1) == 1);
|
|
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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
class SendList extends BinaryList
|
|
{
|
|
constructor(connection, doneReply)
|
|
{
|
|
super();
|
|
this.connection = connection;
|
|
this.reply = doneReply;
|
|
}
|
|
|
|
done()
|
|
{
|
|
this.connection.send(this.toArray());
|
|
return this.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.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
|
|
class Warehouse
|
|
{
|
|
static new(type, name, store = null, parent = null, manager = null)
|
|
{
|
|
var res = type();
|
|
Warehouse.put(res, name, store, parent, null, 0, manager);
|
|
return res;
|
|
}
|
|
|
|
static get(id)
|
|
{
|
|
if (Number.isInteger(id))
|
|
{
|
|
//if (Warehouse.resources.contains(id))
|
|
return new AsyncReply(Warehouse.resources.item(id));
|
|
//else
|
|
// return null;
|
|
}
|
|
else
|
|
{
|
|
var p = id.split('/');
|
|
var res = null;
|
|
|
|
for(var s = 0; s < this.stores.length; s++)
|
|
{
|
|
var d = this.stores.at(s);
|
|
if (p[0] == d.instance.name)
|
|
{
|
|
var i = 1;
|
|
res = d;
|
|
while(p.length > i)
|
|
{
|
|
var si = i;
|
|
|
|
for (var r = 0; r < res.instance.children.length; r++)
|
|
if (res.instance.children.item(r).instance.name == p[i])
|
|
{
|
|
i++;
|
|
res = res.instance.children.item(r);
|
|
break;
|
|
}
|
|
|
|
if (si == i)
|
|
// not found, ask the store
|
|
return d.get(id.substring(p[0].length + 1));
|
|
}
|
|
|
|
return new AsyncReply(res);
|
|
}
|
|
}
|
|
|
|
return new AsyncReply(null);
|
|
}
|
|
}
|
|
|
|
|
|
static remove(resource)
|
|
{
|
|
|
|
if (Warehouse.resources.contains(resource.instance.id))
|
|
Warehouse.resources.remove(resource.instance.id);
|
|
else
|
|
return false;
|
|
|
|
if (resource instanceof IStore)
|
|
{
|
|
Warehouse.stores.remove(resource);
|
|
|
|
// remove all objects associated with the store
|
|
var toBeRemoved = null;
|
|
|
|
for (var i = 0; i < Warehouse.resources.length; i++)
|
|
{
|
|
var o = Warehouse.resources.at(i);
|
|
if (o.instance.store == resource)
|
|
{
|
|
if (toBeRemoved == null)
|
|
toBeRemoved = [];
|
|
toBeRemoved.push(o);
|
|
}
|
|
}
|
|
|
|
if (toBeRemoved != null)
|
|
for(var i = 0; i < toBeRemoved.length; i++)
|
|
Warehouse.remove(toBeRemoved[i]);
|
|
}
|
|
|
|
if (resource.instance.store != null)
|
|
resource.instance.store.remove(resource);
|
|
resource.destroy();
|
|
|
|
return true;
|
|
}
|
|
|
|
static put(resource, name, store, parent, customTemplate = null, age = 0, manager = null){
|
|
resource.instance = new Instance(Warehouse.resourceCounter++, name, resource, store, customTemplate, age);
|
|
//resource.instance.children.on("add", Warehouse._onChildrenAdd).on("remove", Warehouse._onChildrenRemove);
|
|
//resource.instance.parents.on("add", Warehouse._onParentsAdd).on("remove", Warehouse._onParentsRemove);
|
|
|
|
if (manager != null)
|
|
resource.instance.managers.add(manager);
|
|
|
|
if (parent)
|
|
{
|
|
parent.instance.children.add(resource);
|
|
}
|
|
else
|
|
{
|
|
if (!(resource instanceof IStore))
|
|
store.instance.children.add(resource);
|
|
}
|
|
|
|
if (resource instanceof IStore)
|
|
Warehouse.stores.add(resource);
|
|
else
|
|
store.put(resource);
|
|
|
|
Warehouse.resources.add(resource.instance.id, resource);
|
|
}
|
|
|
|
static _onParentsRemove(value)
|
|
{
|
|
if (value.instance.children.contains(value))
|
|
value.instance.children.remove(value);
|
|
}
|
|
|
|
static _onParentsAdd(value)
|
|
{
|
|
if (!value.instance.children.contains(value))
|
|
value.instance.children.add(value);
|
|
}
|
|
|
|
static _onChildrenRemove(value)
|
|
{
|
|
if (value.instance.parents.contains(value))
|
|
value.instance.parents.remove(value);
|
|
}
|
|
|
|
static _onChildrenAdd(value)
|
|
{
|
|
if (!value.instance.parents.contains(value))
|
|
value.instance.parents.add(value);
|
|
}
|
|
|
|
static putTemplate(template)
|
|
{
|
|
Warehouse.templates.add(template.classId.valueOf(), template);
|
|
}
|
|
|
|
static getTemplateByType(type)
|
|
{
|
|
// loaded ?
|
|
for (var i = 0; i < Warehouse.templates.length; i++)
|
|
if (Warehouse.templates.at(i).className == typeof(type))
|
|
return Warehouse.templates.at(i);
|
|
|
|
var template = new ResourceTemplate(type);
|
|
Warehouse.templates.add(template.classId.valueOf(), template);
|
|
|
|
return template;
|
|
}
|
|
|
|
static getTemplateByClassId(classId)
|
|
{
|
|
var template = Warehouse.templates.item(classId);
|
|
return new AsyncReply(template);
|
|
}
|
|
|
|
static getTemplateByClassName(className)
|
|
{
|
|
for(var i = 0; i < Warehouse.templates.length; i++)
|
|
if (Warehouse.templates.at(i).className == className)
|
|
return new AsyncReply(Warehouse.templates.at(i));
|
|
|
|
return new AsyncReply(null);
|
|
}
|
|
|
|
static _qureyIn(path, index, resources)
|
|
{
|
|
var rt = [];
|
|
|
|
if (index == path.length - 1)
|
|
{
|
|
if (path[index] == "")
|
|
for(var i = 0; i < resources.length; i++)
|
|
rt.push(resources.at(i));
|
|
else
|
|
for(var i = 0; i < resources.length; i++)
|
|
if (resources.at(i).instance.name == path[index])
|
|
rt.push(resources.at(i));
|
|
}
|
|
else
|
|
for(var i = 0; i < resources.length; i++)
|
|
if (resources.at(i).instance.name == path[index])
|
|
rt = rt.concat(Warehouse._qureyIn(path, index+1, resources.at(i).instance.children));
|
|
|
|
return rt;
|
|
}
|
|
|
|
static query(path)
|
|
{
|
|
var p = path.split('/');
|
|
return new AsyncReply(Warehouse._qureyIn(p, 0, Warehouse.stores));
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
Warehouse.stores = new AutoList();
|
|
Warehouse.resources = new KeyList();
|
|
Warehouse.resourceCounter = 0;
|
|
Warehouse.templates = new KeyList();
|
|
|
|
exports.printMsg = function() {
|
|
console.log("Esiur 1.1");
|
|
}
|
|
|
|
module.exports = { Warehouse, DistributedConnection};
|
|
|
|
|
|
var WebSocket = require('ws')
|
|
|