/* * 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"; import IStore from '../../Resource/IStore.js'; import Session from '../../Security/Authority/Session.js'; import Authentication from '../../Security/Authority/Authentication.js'; import AuthenticationType from "../../Security/Authority/AuthenticationType.js"; import SHA256 from '../../Security/Integrity/SHA256.js'; import { BL, DC } from '../../Data/DataConverter.js'; import SendList from '../SendList.js'; import AsyncReply from '../../Core/AsyncReply.js'; import Codec from '../../Data/Codec.js'; import NetworkBuffer from '../Sockets/NetworkBuffer.js'; import KeyList from '../../Data/KeyList.js'; import AsyncQueue from '../../Core/AsyncQueue.js'; import Warehouse from '../../Resource/Warehouse.js'; import IIPAuthPacket from "../Packets/IIPAuthPacket.js"; import IIPPacket from "../Packets/IIPPacket.js"; import IIPAuthPacketAction from "../Packets/IIPAuthPacketAction.js"; import IIPAuthPacketCommand from "../Packets/IIPAuthPacketCommand.js"; import AuthenticationMethod from "../../Security/Authority/AuthenticationMethod.js"; import IIPPacketAction from "../Packets/IIPPacketAction.js"; import IIPPacketCommand from "../Packets/IIPPacketCommand.js"; import IIPPacketEvent from "../Packets/IIPPacketEvent.js"; import IIPPacketReport from "../Packets//IIPPacketReport.js"; import ErrorType from "../../Core/ErrorType.js"; import ProgressType from "../../Core/ProgressType.js"; import ExceptionCode from "../../Core/ExceptionCode.js"; import DistributedResource from './DistributedResource.js'; import ResourceTemplate from '../../Resource/Template/ResourceTemplate.js'; import DistributedResourceQueueItem from './DistributedResourceQueueItem.js'; import DistributedResourceQueueItemType from './DistributedResourceQueueItemType.js'; import DistributedPropertyContext from './DistributedPropertyContext.js'; import { ResourceTrigger } from '../../Resource/IResource.js'; import Ruling from '../../Security/Permissions/Ruling.js'; import ActionType from '../../Security/Permissions/ActionType.js'; import AsyncException from '../../Core/AsyncException.js'; export default class DistributedConnection extends IStore { send(data) { if (this.holdSending) { //console.log("hold ", data.length); this.sendBuffer.writeAll(data); } else //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() { 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.packet = new IIPPacket(); this.authPacket = new IIPAuthPacket(); this.resources = new KeyList();//{}; this.templates = new KeyList(); this.requests = new KeyList();// {}; //this.pathRequests = new KeyList();// {}; this.templateRequests = new KeyList(); this.resourceRequests = new KeyList();// {}; 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) //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; try { 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.InvokeFunctionArrayArguments: this.IIPRequestInvokeFunctionArrayArguments(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); break; case IIPPacketAction.InvokeFunctionNamedArguments: this.IIPRequestInvokeFunctionNamedArguments(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.InvokeFunctionArrayArguments: case IIPPacketAction.InvokeFunctionNamedArguments: 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; } } } catch (ex) { console.log("Esiur Error ", ex); } } } 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 == AuthenticationMethod.credentials && authPacket.localMethod == AuthenticationMethod.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(ExceptionCode.AccessDenied) .addUint16(13) .addString("Access Denied") .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.openReply.trigger(this); this.openReply = null; //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 = SHA256.compute(BL().addUint8Array(this.localPasswordOrToken) .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) { var remoteHash = SHA256.compute(BL().addUint8Array(this.remoteNonce) .addUint8Array(this.localNonce) .addUint8Array(this.localPasswordOrToken).toDC()); if (remoteHash.sequenceEqual(authPacket.hash)) { // send establish request this.sendParams().addUint8(0x20).addUint16(0).done(); } else { this.sendParams().addUint8(0xc0) .addUint32(ExceptionCode.ChallengeFailed) .addUint16(16) .addString("Challenge Failed") .done(); } } else if (authPacket.action == IIPAuthPacketAction.ConnectionEstablished) { this.session.id = authPacket.sessionId; this.ready = true; this.openReply.trigger(this); this.openReply = null; //this._emit("ready", this); } } else if (authPacket.command == IIPAuthPacketCommand.Error) { this.openReply.triggerError(1, authPacket.errorCode, authPacket.errorMessage); this.openReply = null; //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.ready = false; this.readyToEstablish = false; try { this.requests.values.forEach((x) => x.triggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"))); this.resourceRequests.values.forEach((x) => x.triggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"))); this.templateRequests.values.forEach((x) => x.triggerError(new AsyncException(ErrorType.Management, 0, "Connection closed"))); } catch(ex) { // unhandled error } this.resources.values.forEach((x) => x._suspend()); this.requests.clear(); this.resourceRequests.clear(); this.templateRequests.clear(); // Warehouse.remove(this); if (this.socket.readyState != this.socket.CLOSED) { this.socket.close(); } this._emit("close", event); } async reconnect() { try { if (await this.connect()) { try { var bag = new AsyncBag(); for (var i = 0; i < this.resources.keys.length; i++) { var index = this.resources.keys[i]; bag.add(this.fetch(index)); } bag.seal(); await bag; } catch (ex) { console.log(ex); } } } catch (ex) { return false; } return true; } hold() { this.holdSending = true; } unhold() { if (this.holdSending) { this.holdSending = false; var msg = this.sendBuffer.read(); if (msg == null || msg.length == 0) return; this.socket.send(msg); } } trigger(trigger) { if (trigger == ResourceTrigger.Open) { var { domain = null, secure = false, username = "guest", password = "", checkInterval = 30, connectionTimeout = 600, revivingTime = 120, tokenIndex = 0, token = null, debug = false } = this.instance.attributes.toObject(); this.debug = debug; this.checkInterval = checkInterval * 1000; // check every 30 seconds this.connectionTimeout = connectionTimeout * 1000; // 10 minutes (4 pings failed) this.revivingTime = revivingTime * 1000; // 2 minutes var host = this.instance.name.split(':'); var address = host[0]; var port = parseInt(host[1]); if (token != null) { var tk = DC.stringToBytes(token); return this.connect(secure, AuthenticationMethod.token, address, port, null, tokenIndex, tk, domain); } else { var pw = DC.stringToBytes(password); return this.connect(secure, AuthenticationMethod.credentials, address, port, username, null, pw, domain); } } return new AsyncReply(true); } connect(secure, method, hostname, port, username, tokenIndex, passwordOrToken, domain) { this.openReply = new AsyncReply(); if (secure !== undefined) { this.session.localAuthentication.method = method; this.session.localAuthentication.tokenIndex = tokenIndex; this.session.localAuthentication.domain = domain; this.session.localAuthentication.username = username; this.localPasswordOrToken = passwordOrToken; //this.url = `ws${secure ? 's' : ''}://${this.instance.name}`; this.url = `ws${secure ? 's' : ''}://${hostname}:${port}`; } //this.debug = debug; this.totalReceived = 0; this.totalSent = 0; this.lastAction = Date.now(); this.socket = new WebSocket(this.url, "iip"); this.socket.binaryType = "arraybuffer"; this.socket.connection = this; this.socket.networkBuffer = new NetworkBuffer(); this.sendBuffer = new NetworkBuffer(); var un = DC.stringToBytes(this.session.localAuthentication.username); var dmn = DC.stringToBytes(this.session.localAuthentication.domain); var self = this; this.socket.onopen = function () { var bl = BL(); 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(); self.hold(); while (this.networkBuffer.available > 0 && !this.networkBuffer.protected) { // try // { self.receive(this.networkBuffer); // } // catch(e) //{ // console.log(e); //} } self.unhold(); }; this.socket.onclose = function (event) { if (this.connection.openReply) { this.connection.openReply.triggerError(0, 0, "Host not reachable"); this.connection.openReply = null; } self.close(event); }; return this.openReply; } reconnect() { } put(resource) { this.resources.add(parseInt(resource.instance.name), resource); return true; } remove(resource) { // nothing to do (IStore interface) } // Protocol Implementation sendRequest(action) { var reply = new AsyncReply(); this.callbackCounter++; this.requests.set(this.callbackCounter, reply); return this.sendParams(reply).addUint8(0x40 | action).addUint32(this.callbackCounter); } sendDetachRequest(instanceId) { try { return this.sendRequest(IIPPacketAction.DetachResource).addUint32(instanceId).done(); } catch(ex) { return null; } } sendInvokeByArrayArguments(instanceId, index, parameters) { var reply = new AsyncReply(); var pb = Codec.composeVarArray(parameters, this, true); this.callbackCounter++; this.sendParams() .addUint8(0x40 | IIPPacketAction.InvokeFunctionArrayArguments) .addUint32(this.callbackCounter) .addUint32(instanceId) .addUint8(index) .addUint8Array(pb) .done(); this.requests.set(this.callbackCounter, reply); return reply; } sendInvokeByNamedArguments(instanceId, index, parameters) { var reply = new AsyncReply(); var pb = Codec.composeStructure(parameters, this, true, true, true); this.callbackCounter++; this.sendParams() .addUint8(0x40 | IIPPacketAction.InvokeFunctionNamedArguments) .addUint32(this.callbackCounter) .addUint32(instanceId) .addUint8(index) .addUint8Array(pb) .done(); this.requests.set(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.item(callbackId); this.requests.remove(callbackId); req.trigger(results); } IIPReplyInvoke(callbackId, result) { var req = this.requests.item(callbackId); if (req != null) { this.requests.remove(callbackId); Codec.parse(result, 0, {}, this).then(function (rt) { req.trigger(rt); }); } } IIPReportError(callbackId, errorType, errorCode, errorMessage) { var req = this.requests.item(callbackId); if (req != null) { this.requests.remove(callbackId); req.triggerError(errorType, errorCode, errorMessage); } } IIPReportProgress(callbackId, type, value, max) { var req = this.requests.item(callbackId); if (req != null) req.triggerProgress(type, value, max); } IIPReportChunk(callbackId, data) { var req = this.requests.item(callbackId); if (req != null) { Codec.parse(data, 0, {}, this).then(function (x) { req.triggerChunk(x); }); } } IIPEventResourceReassigned(resourceId, newResourceId) { } IIPEventResourceDestroyed(resourceId) { if (this.resources.item(resourceId)) { var r = this.resources.item(resourceId); this.resources.remove(resourceId); r.destroy(); } } IIPEventPropertyUpdated(resourceId, index, content) { let self = this; this.fetch(resourceId).then(function (r) { let pt = r.instance.template.getPropertyTemplateByIndex(index); if (pt == null) return; // ft found, fi not found, this should never happen // push to the queue to gaurantee serialization let item = new AsyncReply(); self.queue.add(item); Codec.parse(content, 0, {}, self).then(function (args) { item.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Propery, args, index)); }).error(function (ex) { self.queue.remove(item); console.log("Esiur Property Error", ex); }); }); } IIPEventEventOccurred(resourceId, index, content) { var self = this; this.fetch(resourceId).then(function (r) { let et = r.instance.template.getEventTemplateByIndex(index); if (et == null) return; // ft found, fi not found, this should never happen // push to the queue to guarantee serialization var item = new AsyncReply(); self.queue.add(item); Codec.parseVarArray(content, 0, content.length, self).then(function (args) { item.trigger(new DistributedResourceQueueItem(r, DistributedResourceQueueItemType.Event, args, index)); }).error(function (ex) { self.queue.remove(item); console.log("Esiur Event Error", ex); }); }); } 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.getById(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; } // 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(); r.instance.on("ResourceEventOccurred", self.instance_eventOccurred, self); r.instance.on("ResourceModified", self.instance_propertyModified, self); r.instance.on("ResourceDestroyed", self.instance_resourceDestroyed, self); } else { // reply failed self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound); } }); } IIPRequestReattachResource(callback, resourceId, resourceAge) { var self = this; Warehouse.getById(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.getById(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.getById(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.getById(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).then(function(ok){ self.sendReply(IIPPacketAction.CreateResource, callback) .addUint32(resource.Instance.Id) .done(); }).error(function(ex){ // send some error self.sendError(ErrorType.Management, callback, ExceptionCode.AddToStoreFailed); }); }); }); }); }); }); } IIPRequestDeleteResource(callback, resourceId) { var self = this; Warehouse.getById(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.getById(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); } }); } IIPRequestInvokeFunctionArrayArguments(callback, resourceId, index, content) { var self = this; Warehouse.getById(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._invokeByArrayArguments(index, args); if (rt != null) { rt.then(function (res) { self.sendReply(IIPPacketAction.InvokeFunctionArrayArguments, 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); function* itt() { }; // Is iterator ? if (rt[Symbol.iterator] instanceof Function) { for (let v of rt) self.sendChunk(callback, v); self.sendReply(IIPPacket.IIPPacketAction.InvokeFunctionArrayArguments, callback) .addUint8(DataType.Void) .done(); } else if (rt instanceof AsyncReply) { rt.then(function (res) { self.sendReply(IIPPacketAction.InvokeFunctionArrayArguments, callback) .addUint8Array(Codec.compose(res, self)) .done(); }); } else { self.sendReply(IIPPacketAction.InvokeFunctionArrayArguments, 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 } }); } IIPRequestInvokeFunctionNamedArguments(callback, resourceId, index, content) { var self = this; Warehouse.getById(resourceId).then(function (r) { if (r != null) { Codec.parseStructure(content, 0, content.length, self).then(function (namedArgs) { var ft = r.instance.template.getFunctionTemplateByIndex(index); if (ft != null) { if (r instanceof DistributedResource) { var rt = r._invokeByNamedArguments(index, namedArgs); if (rt != null) { rt.then(function (res) { self.sendReply(IIPPacketAction.InvokeFunctionNamedArguments, 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) { var pi = ResourceTemplate.getFunctionParameters(fi); var args = new Array(pi.length); for (var i = 0; i < pi.length; i++) { if (namedArgs[pi[i]] !== undefined) args[i] = namedArgs[pi[i]]; } // pass this to the last argument if it is undefined if (args[args.length - 1] === undefined) args[args.length - 1] = self; var rt = fi.apply(r, args); // Is iterator ? if (rt[Symbol.iterator] instanceof Function) { for (let v of rt) self.sendChunk(callback, v); self.sendReply(IIPPacket.IIPPacketAction.InvokeFunctionNamedArguments, callback) .addUint8(DataType.Void) .done(); } else if (rt instanceof AsyncReply) { rt.then(function (res) { self.sendReply(IIPPacketAction.InvokeFunctionNamedArguments, callback) .addUint8Array(Codec.compose(res, self)) .done(); }); } else { self.sendReply(IIPPacketAction.InvokeFunctionNamedArguments, 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.getById(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.getById(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.getById(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.getById(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) { let r = this.resources.item(iid); return new AsyncReply(r); //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) { let resource = this.resources.item(id); let request = this.resourceRequests.item(id); if (request != null) { if (resource != null) // dig for dead locks // or not return new AsyncReply(resource); else return request; } else if (resource != null && !resource._p.suspended) { return new AsyncReply(resource); } var reply = new AsyncReply(); this.resourceRequests.set(id, reply); var self = this; this.sendRequest(IIPPacketAction.AttachResource) .addUint32(id) .done() .then(function (rt) { let dr = resource || new DistributedResource(self, id, rt[1], rt[2]); self.getTemplate(rt[0]).then(function (tmp) { // ClassId, ResourceAge, ResourceLink, Content if (resource == null) { Warehouse.put(dr, id.toString(), self, null, tmp).then(function(ok){ Codec.parsePropertyValueArray(rt[3], 0, rt[3].length, self).then(function (ar) { dr._attach(ar); self.resourceRequests.remove(id); reply.trigger(dr); }); }).error(function(ex){ reply.triggerError(ex); }); } else { Codec.parsePropertyValueArray(rt[3], 0, rt[3].length, self).then(function (ar) { dr._attach(ar); self.resourceRequests.remove(id); reply.trigger(dr); }).error(function(ex){ reply.triggerError(ex); }); } }).error(function(ex){ reply.triggerError(ex); }); }).error(function(ex){ reply.triggerError(ex); }); 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.getById(parentId).then(function (parent) { if (parent == null) { self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound); return; } Warehouse.getById(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.getById(parentId).then(function (parent) { if (parent == null) { self.sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound); return; } Warehouse.getById(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.getById(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.getById(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.getById(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.getById(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.getById(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.triggerError(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; } }