From 737397da1181da3281de0f9e9eacc7e00b6b1116 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Wed, 14 Jul 2021 05:16:40 +0300 Subject: [PATCH] 1.3 --- .vscode/launch.json | 8 + LICENSE | 2 +- bin/esiur.dart | 41 + build.yaml | 7 + lib/builder.dart | 47 + lib/esiur.dart | 7 +- lib/src/Core/AsyncBag.dart | 83 +- lib/src/Core/AsyncReply.dart | 245 +- lib/src/Core/ExceptionCode.dart | 6 +- lib/src/Core/IEventHandler.dart | 2 +- lib/src/Data/BinaryList.dart | 2 +- lib/src/Data/Codec.dart | 2136 ++++---- lib/src/Data/DC.dart | 1019 ++-- lib/src/Data/DataType.dart | 2 + lib/src/Data/Guid.dart | 17 +- lib/src/Data/IRecord.dart | 32 + lib/src/Data/ParseResult.dart | 6 + lib/src/Data/Record.dart | 25 + lib/src/Data/RecordComparisonResult.dart | 6 + lib/src/Data/ResourceArrayType.dart | 5 + lib/src/Misc/Global.dart | 13 + lib/src/Net/IIP/DistributedConnection.dart | 4530 +++++++++-------- lib/src/Net/IIP/DistributedResource.dart | 46 +- lib/src/Net/IIP/DistributedServer.dart | 35 + lib/src/Net/IIP/EntryPoint.dart | 12 + lib/src/Net/INetworkReceiver.dart | 9 + lib/src/Net/NetworkConnection.dart | 293 +- lib/src/Net/Packets/IIPAuthPacket.dart | 13 +- lib/src/Net/Packets/IIPPacket.dart | 49 +- lib/src/Net/Packets/IIPPacketAction.dart | 66 +- lib/src/Net/Sockets/ISocket.dart | 31 +- lib/src/Net/Sockets/TCPSocket.dart | 251 +- lib/src/Proxy/TemplateGenerator.dart | 306 ++ lib/src/Resource/IResource.dart | 29 +- lib/src/Resource/Instance.dart | 8 +- .../Resource/Template/ArgumentTemplate.dart | 34 + lib/src/Resource/Template/EventTemplate.dart | 62 +- .../Resource/Template/FunctionTemplate.dart | 69 +- lib/src/Resource/Template/MemberTemplate.dart | 8 +- .../Resource/Template/PropertyTemplate.dart | 128 +- .../Resource/Template/ResourceTemplate.dart | 330 -- .../Resource/Template/TemplateDataType.dart | 120 + .../Resource/Template/TemplateDescriber.dart | 81 + lib/src/Resource/Template/TemplateType.dart | 6 + lib/src/Resource/Template/TypeTemplate.dart | 550 ++ lib/src/Resource/Warehouse.dart | 215 +- lib/src/Security/Permissions/ActionType.dart | 3 +- pubspec.lock | 143 +- pubspec.yaml | 10 +- test/main.dart | 16 +- 50 files changed, 6238 insertions(+), 4926 deletions(-) create mode 100644 bin/esiur.dart create mode 100644 build.yaml create mode 100644 lib/builder.dart create mode 100644 lib/src/Data/IRecord.dart create mode 100644 lib/src/Data/ParseResult.dart create mode 100644 lib/src/Data/Record.dart create mode 100644 lib/src/Data/RecordComparisonResult.dart create mode 100644 lib/src/Data/ResourceArrayType.dart create mode 100644 lib/src/Misc/Global.dart create mode 100644 lib/src/Net/IIP/DistributedServer.dart create mode 100644 lib/src/Net/IIP/EntryPoint.dart create mode 100644 lib/src/Net/INetworkReceiver.dart create mode 100644 lib/src/Proxy/TemplateGenerator.dart create mode 100644 lib/src/Resource/Template/ArgumentTemplate.dart delete mode 100644 lib/src/Resource/Template/ResourceTemplate.dart create mode 100644 lib/src/Resource/Template/TemplateDataType.dart create mode 100644 lib/src/Resource/Template/TemplateDescriber.dart create mode 100644 lib/src/Resource/Template/TemplateType.dart create mode 100644 lib/src/Resource/Template/TypeTemplate.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index 02310b8..0480a62 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,6 +9,14 @@ "program": "test/main.dart", "request": "launch", "type": "dart" + }, + { + "program": "test/template_test/.dart_tool/build/entrypoint/build.dart", + "name": "template_test", + "cwd": "template_test", + "request": "launch", + "type": "dart", + "args": ["serve"], } ] } \ No newline at end of file diff --git a/LICENSE b/LICENSE index 8507251..e69e7c9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Esi Ur +Copyright (c) 2019-2021 Esiur Foundation, 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 diff --git a/bin/esiur.dart b/bin/esiur.dart new file mode 100644 index 0000000..9d52f2a --- /dev/null +++ b/bin/esiur.dart @@ -0,0 +1,41 @@ +import 'package:args/args.dart'; + +void main(List arguments) { + if (arguments.length == 0) { + // print help + print("Esiur package command line"); + print(""); + print("Usage: [arguments]"); + print(""); + print("Available commands:"); + print("\tget-template\tGet a template from an IIP link."); + print("\tversion: print esiur version."); + print(""); + print("Global options:"); + print("\t-u, --username\tAuthentication username"); + print("\t-p, --password\tAuthentication password"); + } + + var cmd = arguments[0]; + + if (cmd == "get-template") { + if (arguments.length < 2) { + print("Please provide an IIP link"); + return; + } + + var link = arguments[1]; + + final parser = ArgParser() + ..addFlag('username', abbr: 'u') + ..addFlag('password', abbr: 'p'); + + var results = parser.parse(arguments.skip(2)); + + var username = results['username']; + var password = results['password']; + + // make template + + } +} diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..67cd8a2 --- /dev/null +++ b/build.yaml @@ -0,0 +1,7 @@ +builders: + services: + import: "package:esiur/builder.dart" + builder_factories: ["iipService"] + build_extensions: {".iip.yaml": [".iip.dart"]} + auto_apply: dependents + build_to: source \ No newline at end of file diff --git a/lib/builder.dart b/lib/builder.dart new file mode 100644 index 0000000..a88476e --- /dev/null +++ b/lib/builder.dart @@ -0,0 +1,47 @@ +import 'package:source_gen/source_gen.dart'; +import 'package:build/build.dart'; +import 'package:yaml/yaml.dart'; + +Builder iipService(BuilderOptions options) { + return LibraryBuilder(TemplateGenerator(), generatedExtension: '.info.dart'); +} + +class TemplateBuilder implements Builder { + //BuilderOptions options; + String _fileName; + TemplateBuilder([BuilderOptions options]) : _fileName = _get_dest(options); + + @override + Future build(BuildStep buildStep) async { + final id = AssetId(buildStep.inputId.package, _fileName); + + // generate + var content = "Testing"; + + await buildStep.writeAsString(id, content); + } + + static String _get_dest(BuilderOptions options) { + const defaultDestination = 'lib/src/iip_template.dart'; + if (options == null) return defaultDestination; + if (options.config == null) return defaultDestination; + return options.config['destination_file'] as String ?? defaultDestination; + } + + @override + Map> get buildExtensions { + return { + '.iip.yaml': [".iip.dart"] + }; + } +} + +class TemplateGenerator extends Generator { + @override + String generate(LibraryReader library, BuildStep buildStep) { + return ''' +// Source library: ${library.element.source.uri} +const Testinggggg = 3; +'''; + } +} diff --git a/lib/esiur.dart b/lib/esiur.dart index 5b8819f..baf5845 100644 --- a/lib/esiur.dart +++ b/lib/esiur.dart @@ -13,7 +13,7 @@ export 'src/Resource/Template/MemberTemplate.dart'; export 'src/Resource/Template/MemberType.dart'; export 'src/Resource/Template/PropertyPermission.dart'; export 'src/Resource/Template/PropertyTemplate.dart'; -export 'src/Resource/Template/ResourceTemplate.dart'; +export 'src/Resource/Template/TypeTemplate.dart'; // ----------------------------------------------------------------- // Core @@ -44,7 +44,8 @@ export 'src/Data/Structure.dart'; export 'src/Data/StructureComparisonResult.dart'; export 'src/Data/StructureMetadata.dart'; export 'src/Data/ValueObject.dart'; - +export 'src/Data/IRecord.dart'; +export 'src/Data/Record.dart'; // ----------------------------------------------------------------- // Net export 'src/Net/NetworkBuffer.dart'; @@ -93,4 +94,4 @@ export 'src/Security/Integrity/SHA256.dart'; // Security-Permissions export 'src/Security/Permissions/ActionType.dart'; export 'src/Security/Permissions/IPermissionsManager.dart'; -export 'src/Security/Permissions/Ruling.dart'; \ No newline at end of file +export 'src/Security/Permissions/Ruling.dart'; diff --git a/lib/src/Core/AsyncBag.dart b/lib/src/Core/AsyncBag.dart index fe76dab..a895129 100644 --- a/lib/src/Core/AsyncBag.dart +++ b/lib/src/Core/AsyncBag.dart @@ -1,63 +1,50 @@ import 'AsyncReply.dart'; -class AsyncBag extends AsyncReply> -{ +class AsyncBag extends AsyncReply> { + List> _replies = new List>(); + List _results = []; - List> _replies = new List>(); - List _results = new List(); + int _count = 0; + bool _sealedBag = false; - int _count = 0; - bool _sealedBag = false; + Type arrayType; + + seal() { + //print("SEALED"); - seal() - { - //print("SEALED"); - - if (_sealedBag) - return; + if (_sealedBag) return; - _sealedBag = true; + _sealedBag = true; - if (_results.length == 0) - trigger(new List()); + if (_results.length == 0) trigger(new List()); - for (var i = 0; i < _results.length; i++) - { - var k = _replies[i]; - var index = i; + for (var i = 0; i < _results.length; i++) { + var k = _replies[i]; + var index = i; - k.then((r) - { - _results[index] = r; - _count++; - //print("Seal ${_count}/${_results.length}"); - if (_count == _results.length) - trigger(_results); - }).error((ex){ - triggerError(ex); - }); - } + k.then((r) { + _results[index] = r; + _count++; + //print("Seal ${_count}/${_results.length}"); + if (_count == _results.length) trigger(_results); + }).error((ex) { + triggerError(ex); + }); } + } - add(AsyncReply reply) - { - if (!_sealedBag) - { - _results.add(null); - _replies.add(reply); - } + add(AsyncReply reply) { + if (!_sealedBag) { + _results.add(null); + _replies.add(reply); } + } - addBag(AsyncBag bag) - { - bag._replies.forEach((r) { - add(r); - }); - } - - AsyncBag() - { - - } + addBag(AsyncBag bag) { + bag._replies.forEach((r) { + add(r); + }); + } + AsyncBag() {} } diff --git a/lib/src/Core/AsyncReply.dart b/lib/src/Core/AsyncReply.dart index 30e45c8..ba4e80d 100644 --- a/lib/src/Core/AsyncReply.dart +++ b/lib/src/Core/AsyncReply.dart @@ -26,196 +26,155 @@ import 'dart:core'; import 'AsyncException.dart'; import 'ProgressType.dart'; -class AsyncReply implements Future -{ +class AsyncReply implements Future { + List _callbacks = new List(); - List _callbacks = new List(); + T _result; - T _result; + List _errorCallbacks = + new List(); - List _errorCallbacks = new List(); - - List _progressCallbacks = new List(); + List _progressCallbacks = + new List(); - List _chunkCallbacks = new List(); + List _chunkCallbacks = new List(); + bool _resultReady = false; + AsyncException _exception; + bool get ready { + return _resultReady; + } - bool _resultReady = false; - AsyncException _exception; + set ready(value) { + _resultReady = value; + } + T get result { + return _result; + } - bool get ready - { - return _resultReady; - } + setResultReady(bool val) { + _resultReady = val; + } - set ready(value) - { - _resultReady = value; - } - - T get result - { - return _result; - } - - setResultReady(bool val) - { - _resultReady = val; - } - - - AsyncReply next(Function(T) callback) - { + AsyncReply next(Function(T) callback) { then(callback); return this; } - AsyncReply then(FutureOr onValue(T value), {Function onError}) - { - _callbacks.add(onValue); - if (onError != null) - { - if (onError is Function(dynamic, dynamic)) - { - _errorCallbacks.add((ex)=>onError(ex, null)); - } - else if (onError is Function(dynamic)) - { - _errorCallbacks.add(onError); - } - else if (onError is Function()) - { - _errorCallbacks.add((ex)=>onError()); - } - else if (onError is Function(Object, StackTrace)) - { - _errorCallbacks.add((ex)=>onError(ex, null)); - } + AsyncReply then(FutureOr onValue(T value), {Function onError}) { + _callbacks.add(onValue); + if (onError != null) { + if (onError is Function(dynamic, dynamic)) { + _errorCallbacks.add((ex) => onError(ex, null)); + } else if (onError is Function(dynamic)) { + _errorCallbacks.add(onError); + } else if (onError is Function()) { + _errorCallbacks.add((ex) => onError()); + } else if (onError is Function(Object, StackTrace)) { + _errorCallbacks.add((ex) => onError(ex, null)); } + } + if (_resultReady) onValue(result); - if (_resultReady) - onValue(result); - - if (R == Null) - return null; - else - return this as AsyncReply; + if (R == Null) + return null; + else + return this as AsyncReply; } - AsyncReply whenComplete(FutureOr action()) - { + AsyncReply whenComplete(FutureOr action()) { return this; //_callbacks.add(action); } - Stream asStream() - { + Stream asStream() { return null; } - AsyncReply catchError(Function onError, {bool test(Object error)}) - { - return this.error(onError); + AsyncReply catchError(Function onError, {bool test(Object error)}) { + return this.error(onError); } - AsyncReply timeout(Duration timeLimit, {FutureOr onTimeout()}) - { + AsyncReply timeout(Duration timeLimit, {FutureOr onTimeout()}) { return this; } - - AsyncReply error(Function(dynamic) callback) - { - _errorCallbacks.add(callback); - if (_exception != null) - callback(_exception); - - return this; - } + AsyncReply error(Function(dynamic) callback) { + _errorCallbacks.add(callback); - AsyncReply progress(Function(ProgressType, int, int) callback) - { - _progressCallbacks.add(callback); - return this; - } + if (_exception != null) callback(_exception); - - AsyncReply chunk(Function(T) callback) - { - _chunkCallbacks.add(callback); - return this; - } + return this; + } - void trigger(T result) - { + AsyncReply progress(Function(ProgressType, int, int) callback) { + _progressCallbacks.add(callback); + return this; + } -// lock (callbacksLock) -// { - if (_resultReady) - return; + AsyncReply chunk(Function(T) callback) { + _chunkCallbacks.add(callback); + return this; + } - _result = result; - _resultReady = true; + AsyncReply trigger(T result) { + if (_resultReady) return this; - _callbacks.forEach((x) { - x(result); - }); + _result = result; + _resultReady = true; -// } + _callbacks.forEach((x) { + x(result); + }); - } + return this; + } - triggerError(Exception exception) - { - if (_resultReady) - return; + AsyncReply triggerError(Exception exception) { + if (_resultReady) return this; - if (exception is AsyncException) - _exception = exception; - else - _exception = AsyncException.toAsyncException(exception); + if (exception is AsyncException) + _exception = exception; + else + _exception = AsyncException.toAsyncException(exception); - ///lock (callbacksLock) - //{ + ///lock (callbacksLock) + //{ - if (this._errorCallbacks.length == 0) - throw _exception; - else - _errorCallbacks.forEach((x) { - x(_exception); - }); - //} + if (this._errorCallbacks.length == 0) + throw _exception; + else + _errorCallbacks.forEach((x) { + x(_exception); + }); + //} - } + return this; + } - triggerProgress(ProgressType type, int value, int max) - { - _progressCallbacks.forEach((x) { - x(type, value, max); - }); - } + AsyncReply triggerProgress(ProgressType type, int value, int max) { + _progressCallbacks.forEach((x) { + x(type, value, max); + }); - - triggerChunk(T value) - { - _chunkCallbacks.forEach((x) { - x(value); - }); - } + return this; + } + AsyncReply triggerChunk(T value) { + _chunkCallbacks.forEach((x) { + x(value); + }); - AsyncReply.ready(T result) - { - _resultReady = true; - _result = result; - } + return this; + } - AsyncReply() - { + AsyncReply.ready(T result) { + _resultReady = true; + _result = result; + } - } - -} \ No newline at end of file + AsyncReply() {} +} diff --git a/lib/src/Core/ExceptionCode.dart b/lib/src/Core/ExceptionCode.dart index 5a9d2dd..53e2da1 100644 --- a/lib/src/Core/ExceptionCode.dart +++ b/lib/src/Core/ExceptionCode.dart @@ -31,5 +31,9 @@ enum ExceptionCode SetPropertyDenied, ReadOnlyProperty, GeneralFailure, - AddToStoreFailed + AddToStoreFailed, + NotAttached, + AlreadyListened, + AlreadyUnlistened, + NotListenable } \ No newline at end of file diff --git a/lib/src/Core/IEventHandler.dart b/lib/src/Core/IEventHandler.dart index 1d81101..5ce71eb 100644 --- a/lib/src/Core/IEventHandler.dart +++ b/lib/src/Core/IEventHandler.dart @@ -22,7 +22,7 @@ class IEventHandler return false; } - + on(String event, Function callback) { event = event.toLowerCase(); diff --git a/lib/src/Data/BinaryList.dart b/lib/src/Data/BinaryList.dart index 5cf7f3d..21c520c 100644 --- a/lib/src/Data/BinaryList.dart +++ b/lib/src/Data/BinaryList.dart @@ -32,7 +32,7 @@ import 'Guid.dart'; class BinaryList { - var _list = new List(); + var _list = []; int get length => _list.length; diff --git a/lib/src/Data/Codec.dart b/lib/src/Data/Codec.dart index 271bc3c..98b9a19 100644 --- a/lib/src/Data/Codec.dart +++ b/lib/src/Data/Codec.dart @@ -21,7 +21,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import 'package:esiur/src/Resource/Template/TemplateType.dart'; + import 'DataType.dart'; +import 'Guid.dart'; +import 'IRecord.dart'; +import 'Record.dart'; +import 'ResourceArrayType.dart'; import 'StructureComparisonResult.dart'; import 'dart:typed_data'; import 'Structure.dart'; @@ -41,1039 +47,1363 @@ import '../Resource/Warehouse.dart'; import '../Resource/IResource.dart'; import '../Resource/Template/PropertyTemplate.dart'; import '../Net/IIP/DistributedPropertyContext.dart'; +import './RecordComparisonResult.dart'; -class Codec -{ - /// - /// Check if a DataType is an array - /// - /// DataType to check - /// True if DataType is an array, otherwise false - static bool isArray(int type) - { - return ((type & 0x80) == 0x80) && (type != DataType.NotModified); +class Codec { + /// + /// Check if a DataType is an array + /// + /// DataType to check + /// True if DataType is an array, otherwise false + static bool isArray(int type) { + return ((type & 0x80) == 0x80) && (type != DataType.NotModified); + } + + /// + /// Get the element DataType + /// + /// + /// Passing UInt8Array will return UInt8 + /// + /// DataType to get its element DataType + static int getElementType(int type) { + return type & 0x7F; + } + + /// + /// Get DataType array of a given Structure + /// + /// Structure to get its DataTypes + /// Distributed connection is required in case a type is at the other end + static List getStructureDateTypes( + Structure structure, DistributedConnection connection) { + var keys = structure.getKeys(); + var types = new List(keys.length); + + for (var i = 0; i < keys.length; i++) + types[i] = Codec.getDataType(structure[keys[i]], connection); + return types; + } + + /// + /// Compare two structures + /// + /// Initial structure to compare with + /// Next structure to compare with the initial + /// DistributedConnection is required in case a structure holds items at the other end + static int compareStructures( + Structure initial, Structure next, DistributedConnection connection) { + if (next == null) return StructureComparisonResult.Null; + + if (initial == null) return StructureComparisonResult.Structure; + + if (next == initial) return StructureComparisonResult.Same; + + if (initial.length != next.length) + return StructureComparisonResult.Structure; + + var previousKeys = initial.getKeys(); + var nextKeys = next.getKeys(); + + for (var i = 0; i < previousKeys.length; i++) + if (previousKeys[i] != nextKeys[i]) + return StructureComparisonResult.Structure; + + var previousTypes = getStructureDateTypes(initial, connection); + var nextTypes = getStructureDateTypes(next, connection); + + for (var i = 0; i < previousTypes.length; i++) + if (previousTypes[i] != nextTypes[i]) + return StructureComparisonResult.StructureSameKeys; + + return StructureComparisonResult.StructureSameTypes; + } + + /// + /// Compare two records + /// + /// Initial record to compare with + /// Next record to compare with the initial + /// DistributedConnection is required in case a structure holds items at the other end + static int compareRecords(IRecord initial, IRecord next) { + if (next == null) return RecordComparisonResult.Null; + + if (initial == null) return RecordComparisonResult.Record; + + if (next == initial) return RecordComparisonResult.Same; + + if (next.runtimeType == initial.runtimeType) + return RecordComparisonResult.RecordSameType; + + return RecordComparisonResult.Record; + } + + static AsyncBag parseRecordArray( + DC data, int offset, int length, DistributedConnection connection) { + var reply = new AsyncBag(); + + if (length == 0) { + reply.seal(); + return reply; } - /// - /// Get the element DataType - /// - /// - /// Passing UInt8Array will return UInt8 - /// - /// DataType to get its element DataType - static int getElementType(int type) - { - return type & 0x7F; - } + var end = offset + length; - /// - /// Get DataType array of a given Structure - /// - /// Structure to get its DataTypes - /// Distributed connection is required in case a type is at the other end - static List getStructureDateTypes(Structure structure, DistributedConnection connection) - { - var keys = structure.getKeys(); - var types = new List(keys.length); + var isTyped = (data[offset] & 0x10) == 0x10; - for (var i = 0; i < keys.length; i++) - types[i] = Codec.getDataType(structure[keys[i]], connection); - return types; - } + var result = (data[offset++] & 0xF); - /// - /// Compare two structures - /// - /// Initial structure to compare with - /// Next structure to compare with the initial - /// DistributedConnection is required in case a structure holds items at the other end - static int compareStructures(Structure initial, Structure next, DistributedConnection connection) - { - if (next == null) - return StructureComparisonResult.Null; + if (isTyped) { + var classId = data.getGuid(offset); + offset += 16; - if (initial == null) - return StructureComparisonResult.Structure; + var template = + Warehouse.getTemplateByClassId(classId, TemplateType.Record); - if (next == initial) - return StructureComparisonResult.Same; + reply.arrayType = template.definedType; - if (initial.length != next.length) - return StructureComparisonResult.Structure; + AsyncReply previous = null; - var previousKeys = initial.getKeys(); - var nextKeys = next.getKeys(); + if (result == RecordComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == RecordComparisonResult.Record || + result == RecordComparisonResult.RecordSameType) { + var cs = data.getUint32(offset); + var recordLength = cs; + offset += 4; + previous = parseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } - for (var i = 0; i < previousKeys.length; i++) - if (previousKeys[i] != nextKeys[i]) - return StructureComparisonResult.Structure; + reply.add(previous); - var previousTypes = getStructureDateTypes(initial, connection); - var nextTypes = getStructureDateTypes(next, connection); + while (offset < end) { + result = data[offset++]; - for (var i = 0; i < previousTypes.length; i++) - if (previousTypes[i] != nextTypes[i]) - return StructureComparisonResult.StructureSameKeys; - - return StructureComparisonResult.StructureSameTypes; - } - - /// - /// Compose an array of structures into an array of bytes - /// - /// Array of Structure to compose - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - static DC composeStructureArray(List structures, DistributedConnection connection, [bool prependLength = false]) - { - if (structures == null || structures?.length == 0) - return prependLength ? new DC(4): new DC(0); - - var rt = new BinaryList(); - var comparsion = StructureComparisonResult.Structure; - - rt.addUint8(comparsion) - .addDC(composeStructure(structures[0], connection, true, true, true)); - - for (var i = 1; i < structures.length; i++) - { - comparsion = compareStructures(structures[i - 1], structures[i], connection); - rt.addUint8(comparsion); - - if (comparsion == StructureComparisonResult.Structure) - rt.addDC(composeStructure(structures[i], connection, true, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameKeys) - rt.addDC(composeStructure(structures[i], connection, false, true, true)); - else if (comparsion == StructureComparisonResult.StructureSameTypes) - rt.addDC(composeStructure(structures[i], connection, false, false, true)); - } - - if (prependLength) - rt.insertInt32(0, rt.length); - - return rt.toDC(); - } - - /// - /// Parse an array of structures - /// - /// Bytes array - /// Zero-indexed offset - /// Number of bytes to parse - /// DistributedConnection is required in case a structure in the array holds items at the other end - /// Array of structures - static AsyncBag parseStructureArray(DC data, int offset, int length, DistributedConnection connection) - { - var reply = new AsyncBag(); - if (length == 0) - { - reply.seal(); - return reply; - } - - var end = offset + length; - - var result = data[offset++]; - - AsyncReply previous = null; - // string[] previousKeys = null; - // DataType[] previousTypes = null; - - StructureMetadata metadata = new StructureMetadata(); - - - if (result == StructureComparisonResult.Null) - previous = new AsyncReply.ready(null); - else if (result == StructureComparisonResult.Structure) - { - int cs = data.getUint32(offset); - offset += 4; - previous = parseStructure(data, offset, cs, connection, metadata); - offset += cs; + if (result == RecordComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == RecordComparisonResult.Record || + result == RecordComparisonResult.RecordSameType) { + var cs = data.getUint32(offset); + offset += 4; + previous = parseRecord(data, offset, cs, connection, classId); + offset += cs; + } else if (result == RecordComparisonResult.Same) { + // do nothing } reply.add(previous); + } + } else { + AsyncReply previous = null; + Guid classId = null; + if (result == RecordComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == RecordComparisonResult.Record) { + var cs = data.getUint32(offset); + var recordLength = cs - 16; + offset += 4; + classId = data.getGuid(offset); + offset += 16; + previous = parseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } - while (offset < end) - { - result = data[offset++]; + reply.add(previous); - if (result == StructureComparisonResult.Null) - previous = new AsyncReply.ready(null); - else if (result == StructureComparisonResult.Structure) - { - int cs = data.getUint32(offset); - offset += 4; - previous = parseStructure(data, offset, cs, connection, metadata);// out previousKeys, out previousTypes); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameKeys) - { - int cs = data.getUint32(offset); - offset += 4; - previous = parseStructure(data, offset, cs, connection, metadata, metadata.keys); - offset += cs; - } - else if (result == StructureComparisonResult.StructureSameTypes) - { - int cs = data.getUint32(offset); - offset += 4; - previous = parseStructure(data, offset, cs, connection, metadata, metadata.keys, metadata.types); - offset += cs; - } + while (offset < end) { + result = data[offset++]; - reply.add(previous); + if (result == RecordComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == RecordComparisonResult.Record) { + var cs = data.getUint32(offset); + var recordLength = cs - 16; + offset += 4; + classId = data.getGuid(offset); + offset += 16; + previous = + parseRecord(data, offset, recordLength, connection, classId); + offset += recordLength; + } else if (result == RecordComparisonResult.RecordSameType) { + var cs = data.getUint32(offset); + offset += 4; + previous = parseRecord(data, offset, cs, connection, classId); + offset += cs; + } else if (result == RecordComparisonResult.Same) { + // do nothing } - reply.seal(); - return reply; + reply.add(previous); + } } - /// - /// Compose a structure into an array of bytes - /// - /// Structure to compose - /// DistributedConnection is required in case an item in the structure is at the other end - /// Whether to include the structure keys - /// Whether to include each item DataType - /// If true, prepend the length as UInt32 at the beginning of the returned bytes array - /// Array of bytes in the network byte order - static DC composeStructure(Structure value, DistributedConnection connection, [bool includeKeys = true, bool includeTypes = true, bool prependLength = false]) - { - var rt = new BinaryList(); + reply.seal(); + return reply; - if (includeKeys) - { - for (var k in value.keys) - { - var key = DC.stringToBytes(k); - rt.addUint8(key.length) - .addDC(key) - .addDC(compose(value[k], connection)); - } - } - else - { - for (var k in value.keys) - rt.addDC(compose(value[k], connection, includeTypes)); - } + // var reply = new AsyncBag(); + // if (length == 0) { + // reply.seal(); + // return reply; + // } - if (prependLength) - rt.insertInt32(0, rt.length); + // var end = offset + length; - return rt.toDC(); //.toArray(); + // var result = data[offset++]; + + // AsyncReply previous = null; + // Guid classId = null; + + // if (result == RecordComparisonResult.Null) + // previous = new AsyncReply.ready(null); + // else if (result == RecordComparisonResult.Record) { + // int cs = data.getUint32(offset); + // int recordLength = cs - 16; + // offset += 4; + // classId = data.getGuid(offset); + // offset += 16; + // previous = parseRecord(data, offset, recordLength, connection, classId); + // offset += recordLength; + // } + + // reply.add(previous); + + // while (offset < end) { + // result = data[offset++]; + + // if (result == RecordComparisonResult.Null) + // previous = new AsyncReply.ready(null); + // else if (result == RecordComparisonResult.Record) { + // int cs = data.getUint32(offset); + // int recordLength = cs - 16; + // offset += 4; + // classId = data.getGuid(offset); + // offset += 16; + // previous = parseRecord(data, offset, recordLength, connection, classId); + // offset += recordLength; + // } else if (result == RecordComparisonResult.RecordSameType) { + // int cs = data.getUint32(offset); + // offset += 4; + // previous = parseRecord(data, offset, cs, connection, classId); + // offset += cs; + // } else if (result == RecordComparisonResult.Same) { + // // do nothing + // } + + // reply.add(previous); + // } + + // reply.seal(); + // return reply; + } + + static AsyncReply parseRecord( + DC data, int offset, int length, DistributedConnection connection, + [Guid classId = null]) { + var reply = new AsyncReply(); + + if (classId == null) { + classId = data.getGuid(offset); + + offset += 16; + length -= 16; } - /// - /// Parse a structure - /// - /// Bytes array - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// Array to store keys in. - /// Array to store DataTypes in. - /// Array of keys, in case the data doesn't include keys - /// Array of DataTypes, in case the data doesn't include DataTypes - /// Structure - static AsyncReply parseStructure(DC data, int offset, int length, DistributedConnection connection, [StructureMetadata metadata = null, List keys = null, List types = null])// out string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) - { - var reply = new AsyncReply(); - var bag = new AsyncBag(); - var keylist = new List(); - var typelist = new List(); - var sizeObject = new SizeObject(); + var template = Warehouse.getTemplateByClassId(classId, TemplateType.Record); - if (keys == null) - { - while (length > 0) - { - var len = data[offset++]; - keylist.add(data.getString(offset, len)); - offset += len; + if (template != null) { + parseVarArray(data, offset, length, connection).then((ar) { + if (template.definedType != null) { + var record = + Warehouse.createInstance(template.definedType) as IRecord; - typelist.add(data[offset]); + Map value = {}; - bag.add(Codec.parse(data, offset, connection, sizeObject)); - length -= sizeObject.size + len + 1; - offset += sizeObject.size; - } + for (var i = 0; i < template.properties.length; i++) + value[template.properties[i].name] = ar[i]; + + record.deserialize(value); + + reply.trigger(null); + } else { + var record = new Record(); + + for (var i = 0; i < template.properties.length; i++) + record.add(template.properties[i].name, ar[i]); + + reply.trigger(record); } - else if (types == null) - { - keylist.addAll(keys); + }); + } else { + connection.getTemplate(classId).then((tmp) { + parseVarArray(data, offset, length, connection).then((ar) { + var record = new Record(); - while (length > 0) - { - typelist.add(data[offset]); + for (var i = 0; i < tmp.properties.length; i++) + record.add(tmp.properties[i].name, ar[i]); - bag.add(Codec.parse(data, offset, connection, sizeObject)); - length -= sizeObject.size; - offset += sizeObject.size; - } - } - else - { - keylist.addAll(keys); - typelist.addAll(types); - - var i = 0; - while (length > 0) - { - bag.add(parse(data, offset, connection, sizeObject, types[i])); - length -= sizeObject.size; - offset += sizeObject.size; - i++; - } - } - - bag.seal(); - - bag.then((res) - { - // compose the list - var s = new Structure(); - for (var i = 0; i < keylist.length; i++) - s[keylist[i]] = res[i]; - reply.trigger(s); + reply.trigger(record); }); - - if (metadata != null) - { - metadata.keys = keylist; - metadata.types = typelist; - } - - return reply; + }).error((x) => reply.triggerError(x)); } - + return reply; + } - /// - /// Parse a value - /// - /// Bytes array - /// Zero-indexed offset. - /// Output the number of bytes parsed - /// DistributedConnection is required in case a structure in the array holds items at the other end. - /// DataType, in case the data is not prepended with DataType - /// Value - static AsyncReply parse(DC data, int offset, DistributedConnection connection, [SizeObject sizeObject, int dataType = DataType.Unspecified]) - { + static DC composeRecord(IRecord record, DistributedConnection connection, + [bool includeClassId = true, bool prependLength = false]) { + var rt = new BinaryList(); - bool isArray; - int t; + var template = Warehouse.getTemplateByType(record.runtimeType); + if (includeClassId) rt.addGuid(template.classId); - if (dataType == DataType.Unspecified) - { - sizeObject?.size = 1; - dataType = data[offset++]; - } - else - sizeObject?.size = 0; + var kv = record.serialize(); - t = dataType & 0x7F; + template.properties.forEach((pt) { + var value = kv[pt.name]; + rt.addDC(compose(value, connection)); - isArray = (dataType & 0x80) == 0x80; + // @TODO: serialize + // var value = pt.propertyInfo.GetValue(record, null); + // rt.addDC(compose(value, connection)); + }); - var payloadSize = DataType.size(dataType); + if (prependLength) rt.insertInt32(0, rt.length); + return rt.toDC(); + } - int contentLength = 0; + static DC composeRecordArray( + List records, DistributedConnection connection, + [bool prependLength = false]) { + if (records == null || records?.length == 0) + return prependLength ? new DC(4) : new DC(0); - // check if we have the enough data - if (payloadSize == -1) - { - contentLength = data.getUint32(offset); - offset += 4; - sizeObject?.size += 4 + contentLength; - } - else - sizeObject?.size += payloadSize; + var rt = new BinaryList(); + var comparsion = compareRecords(null, records[0]); - if (isArray) - { - switch (t) - { - // VarArray ? - case DataType.Void: - return parseVarArray(data, offset, contentLength, connection); + //var type = records.getType().GetElementType(); + var isTyped = T == IRecord; // != typeof(IRecord); - case DataType.Bool: - return new AsyncReply>.ready(data.getBooleanArray(offset, contentLength)); + if (isTyped) { + var template = Warehouse.getTemplateByType(T); - case DataType.UInt8: - return new AsyncReply.ready(data.getUint8Array(offset, contentLength)); + if (template != null) { + // typed array ... no need to add class id , it will be included at the first entry + rt.addUint8(0x10 | comparsion); + rt.addGuid(template.classId); + } else // something wrong + { + throw new Exception("Template for type `${T}` not found."); + } - case DataType.Int8: - return new AsyncReply.ready(data.getInt8Array(offset, contentLength)); + if (comparsion == RecordComparisonResult.Record) + rt.addDC(composeRecord(records[0], connection, false, true)); - case DataType.Char: - return new AsyncReply>.ready(data.getCharArray(offset, contentLength)); - - case DataType.Int16: - return new AsyncReply.ready(data.getInt16Array(offset, contentLength)); - - case DataType.UInt16: - return new AsyncReply.ready(data.getUint16Array(offset, contentLength)); - - case DataType.Int32: - return new AsyncReply.ready(data.getInt32Array(offset, contentLength)); - - case DataType.UInt32: - return new AsyncReply.ready(data.getUint32Array(offset, contentLength)); - - case DataType.Int64: - return new AsyncReply.ready(data.getInt64Array(offset, contentLength)); - - case DataType.UInt64: - return new AsyncReply.ready(data.getUint64Array(offset, contentLength)); - - case DataType.Float32: - return new AsyncReply.ready(data.getFloat32Array(offset, contentLength)); - - case DataType.Float64: - return new AsyncReply.ready(data.getFloat64Array(offset, contentLength)); - - case DataType.String: - return new AsyncReply>.ready(data.getStringArray(offset, contentLength)); - - case DataType.Resource: - case DataType.DistributedResource: - return parseResourceArray(data, offset, contentLength, connection); - - case DataType.DateTime: - return new AsyncReply>.ready(data.getDateTimeArray(offset, contentLength)); - - case DataType.Structure: - return parseStructureArray(data, offset, contentLength, connection); - } - } - else - { - switch (t) - { - case DataType.NotModified: - return new AsyncReply.ready(new NotModified()); - - case DataType.Void: - return new AsyncReply.ready(null); - - case DataType.Bool: - return new AsyncReply.ready(data.getBoolean(offset)); - - case DataType.UInt8: - return new AsyncReply.ready(data[offset]); - - case DataType.Int8: - return new AsyncReply.ready(data[offset]); - - case DataType.Char: - return new AsyncReply.ready(data.getChar(offset)); - - case DataType.Int16: - return new AsyncReply.ready(data.getInt16(offset)); - - case DataType.UInt16: - return new AsyncReply.ready(data.getUint16(offset)); - - case DataType.Int32: - return new AsyncReply.ready(data.getInt32(offset)); - - case DataType.UInt32: - return new AsyncReply.ready(data.getUint32(offset)); - - case DataType.Int64: - return new AsyncReply.ready(data.getInt64(offset)); - - case DataType.UInt64: - return new AsyncReply.ready(data.getUint64(offset)); - - case DataType.Float32: - return new AsyncReply.ready(data.getFloat32(offset)); - - case DataType.Float64: - return new AsyncReply.ready(data.getFloat64(offset)); - - case DataType.String: - return new AsyncReply.ready(data.getString(offset, contentLength)); - - case DataType.Resource: - return parseResource(data, offset); - - case DataType.DistributedResource: - return parseDistributedResource(data, offset, connection); - - case DataType.DateTime: - return new AsyncReply.ready(data.getDateTime(offset)); - - case DataType.Structure: - return parseStructure(data, offset, contentLength, connection); - } - } - - - return null; - } - - /// - /// Parse a resource - /// - /// Bytes array - /// Zero-indexed offset. - /// Resource - static AsyncReply parseResource(DC data, int offset) - { - return Warehouse.get(data.getUint32(offset)); - } - - /// - /// Parse a DistributedResource - /// - /// Bytes array - /// Zero-indexed offset. - /// DistributedConnection is required. - /// DistributedResource - static AsyncReply parseDistributedResource(DC data, int offset, DistributedConnection connection) - { - //var g = data.GetGuid(offset); - //offset += 16; - - // find the object - var iid = data.getUint32(offset); - - return connection.fetch(iid);// Warehouse.Get(iid); - } - - /// - /// Check if a resource is local to a given connection. - /// - /// Resource to check. - /// DistributedConnection to check if the resource is local to it. - /// True, if the resource owner is the given connection, otherwise False. - static bool isLocalResource(IResource resource, DistributedConnection connection) - { - if (resource is DistributedResource) - if ((resource as DistributedResource).connection == connection) - return true; - - return false; - } - - /// - /// Compare two resources - /// - /// Initial resource to make comparison with. - /// Next resource to compare with the initial. - /// DistributedConnection is required to check locality. - /// Null, same, local, distributed or same class distributed. - - static int compareResources(IResource initial, IResource next, DistributedConnection connection) - { - if (next == null) - return ResourceComparisonResult.Null; - else if (next == initial) - return ResourceComparisonResult.Same; - else if (isLocalResource(next, connection)) - return ResourceComparisonResult.Local; - else - return ResourceComparisonResult.Distributed; - } - - /// - /// Compose a resource - /// - /// Resource to compose. - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - static DC composeResource(IResource resource, DistributedConnection connection) - { - if (isLocalResource(resource, connection)) - return DC.uint32ToBytes((resource as DistributedResource).id); - else - { - return new BinaryList().addGuid(resource.instance.template.classId).addUint32(resource.instance.id).toDC(); - //return BinaryList.ToBytes(resource.Instance.Template.ClassId, resource.Instance.Id); - } - } - - /// - /// Compose an array of resources - /// - /// Array of resources. - /// DistributedConnection is required to check locality. - /// If True, prepend the length of the output at the beginning. - /// Array of bytes in the network byte order. - - static DC composeResourceArray(List resources, DistributedConnection connection, [bool prependLength = false]) - { - if (resources == null || resources?.length == 0) - return prependLength ? new DC(4) : new DC(0); - - var rt = new BinaryList(); - var comparsion = compareResources(null, resources[0], connection); + for (var i = 1; i < records.length; i++) { + comparsion = compareRecords(records[i - 1], records[i]); rt.addUint8(comparsion); - if (comparsion == ResourceComparisonResult.Local) - rt.addUint32((resources[0] as DistributedResource).id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.addUint32(resources[0].instance.id); - - for (var i = 1; i < resources.length; i++) - { - comparsion = compareResources(resources[i - 1], resources[i], connection); - rt.addUint8(comparsion); - if (comparsion == ResourceComparisonResult.Local) - rt.addUint32((resources[i] as DistributedResource).id); - else if (comparsion == ResourceComparisonResult.Distributed) - rt.addUint32(resources[i].instance.id); - } + if (comparsion == RecordComparisonResult.RecordSameType || + comparsion == RecordComparisonResult.Record) + rt.addDC(composeRecord(records[i], connection, false, true)); + } + } else { + rt.addUint8(comparsion); - if (prependLength) - rt.insertInt32(0, rt.length); + if (comparsion == RecordComparisonResult.Record) + rt.addDC(composeRecord(records[0], connection, true, true)); - return rt.toDC(); + for (var i = 1; i < records.length; i++) { + comparsion = compareRecords(records[i - 1], records[i]); + + rt.addUint8(comparsion); + + if (comparsion == RecordComparisonResult.Record) + rt.addDC(composeRecord(records[i], connection, true, true)); + else if (comparsion == RecordComparisonResult.RecordSameType) + rt.addDC(composeRecord(records[i], connection, false, true)); + } } - /// - /// Parse an array of bytes into array of resources - /// - /// Array of bytes. - /// Number of bytes to parse. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Array of resources. - static AsyncBag parseResourceArray(DC data, int offset, int length, DistributedConnection connection) - { - //print("parseResourceArray ${offset} ${length}"); + if (prependLength) rt.insertInt32(0, rt.length); - var reply = new AsyncBag(); - if (length == 0) - { - reply.seal(); - return reply; - } + return rt.toDC(); - var end = offset + length; + // if (records == null || records?.length == 0) + // return prependLength ? new DC(4) : new DC(0); - // - var result = data[offset++]; + // var rt = new BinaryList(); + // var comparsion = compareRecords(null, records[0]); - AsyncReply previous = null; + // rt.addUint8(comparsion); - if (result == ResourceComparisonResult.Null) - previous = new AsyncReply.ready(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; - } + // if (comparsion == RecordComparisonResult.Record) + // rt.addDC(composeRecord(records[0], connection, true, true)); - reply.add(previous); + // for (var i = 1; i < records.length; i++) { + // comparsion = compareRecords(records[i - 1], records[i]); + // rt.addUint8(comparsion); + // if (comparsion == RecordComparisonResult.Record) + // rt.addDC(composeRecord(records[i], connection, true, true)); + // else if (comparsion == RecordComparisonResult.RecordSameType) + // rt.addDC(composeRecord(records[i], connection, false, true)); + // } - while (offset < end) - { - result = data[offset++]; + // if (prependLength) rt.insertInt32(0, rt.length); - AsyncReply current = null; + // return rt.toDC(); + } - if (result == ResourceComparisonResult.Null) - { - current = new AsyncReply.ready(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; - } + /// + /// Compose an array of structures into an array of bytes + /// + /// Array of Structure to compose + /// DistributedConnection is required in case a structure in the array holds items at the other end + /// If true, prepend the length as UInt32 at the beginning of the returned bytes array + /// Array of bytes in the network byte order + static DC composeStructureArray( + List structures, DistributedConnection connection, + [bool prependLength = false]) { + if (structures == null || structures?.length == 0) + return prependLength ? new DC(4) : new DC(0); - reply.add(current); + var rt = new BinaryList(); + var comparsion = StructureComparisonResult.Structure; - previous = current; - } + rt + .addUint8(comparsion) + .addDC(composeStructure(structures[0], connection, true, true, true)); - reply.seal(); - return reply; + for (var i = 1; i < structures.length; i++) { + comparsion = + compareStructures(structures[i - 1], structures[i], connection); + rt.addUint8(comparsion); + + if (comparsion == StructureComparisonResult.Structure) + rt.addDC(composeStructure(structures[i], connection, true, true, true)); + else if (comparsion == StructureComparisonResult.StructureSameKeys) + rt.addDC( + composeStructure(structures[i], connection, false, true, true)); + else if (comparsion == StructureComparisonResult.StructureSameTypes) + rt.addDC( + composeStructure(structures[i], connection, false, false, true)); } - /// - /// Compose an array of variables - /// - /// Variables. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - static DC composeVarArray(List array, DistributedConnection connection, [bool prependLength = false]) - { - var rt = new BinaryList(); + if (prependLength) rt.insertInt32(0, rt.length); - for (var i = 0; i < array.length; i++) - rt.addDC(compose(array[i], connection)); + return rt.toDC(); + } - if (prependLength) - rt.insertUint32(0, rt.length); - - return rt.toDC(); - } - - - /// - /// Parse an array of bytes into an array of varialbes. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Array of variables. - static AsyncBag parseVarArray(DC data, int offset, int length, DistributedConnection connection) - { - var rt = new AsyncBag(); - var sizeObject = new SizeObject(); - - while (length > 0) - { - rt.add(parse(data, offset, connection, sizeObject)); - - if (sizeObject.size > 0) - { - offset += sizeObject.size; - length -= sizeObject.size; - } - else - throw new Exception("Error while parsing structured data"); - - } - - rt.seal(); - return rt; + /// + /// Parse an array of structures + /// + /// Bytes array + /// Zero-indexed offset + /// Number of bytes to parse + /// DistributedConnection is required in case a structure in the array holds items at the other end + /// Array of structures + static AsyncBag parseStructureArray( + DC data, int offset, int length, DistributedConnection connection) { + var reply = new AsyncBag(); + if (length == 0) { + reply.seal(); + return reply; } - /// - /// Compose an array of property values. - /// - /// PropertyValue array. - /// DistributedConnection is required to check locality. - /// If True, prepend the length as UInt32 at the beginning of the output. - /// Array of bytes in the network byte order. - /// //, bool includeAge = true - static DC composePropertyValueArray(List array, DistributedConnection connection, [bool prependLength = false]) - { - var rt = new BinaryList(); + var end = offset + length; - for (var i = 0; i < array.length; i++) - rt.addDC(composePropertyValue(array[i], connection)); - if (prependLength) - rt.insertUint32(0, rt.length); + var result = data[offset++]; - return rt.toDC(); + AsyncReply previous = null; + // string[] previousKeys = null; + // DataType[] previousTypes = null; + + StructureMetadata metadata = new StructureMetadata(); + + if (result == StructureComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == StructureComparisonResult.Structure) { + int cs = data.getUint32(offset); + offset += 4; + previous = parseStructure(data, offset, cs, connection, metadata); + offset += cs; } - /// - /// Compose a property value. - /// - /// Property value - /// DistributedConnection is required to check locality. - /// Array of bytes in the network byte order. - static DC composePropertyValue(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true) - { + reply.add(previous); - return new BinaryList() - .addUint64(propertyValue.age) - .addDateTime(propertyValue.date) - .addDC(compose(propertyValue.value, connection)) - .toDC(); + while (offset < end) { + result = data[offset++]; + + if (result == StructureComparisonResult.Null) + previous = new AsyncReply.ready(null); + else if (result == StructureComparisonResult.Structure) { + int cs = data.getUint32(offset); + offset += 4; + previous = parseStructure(data, offset, cs, connection, + metadata); // out previousKeys, out previousTypes); + offset += cs; + } else if (result == StructureComparisonResult.StructureSameKeys) { + int cs = data.getUint32(offset); + offset += 4; + previous = parseStructure( + data, offset, cs, connection, metadata, metadata.keys); + offset += cs; + } else if (result == StructureComparisonResult.StructureSameTypes) { + int cs = data.getUint32(offset); + offset += 4; + previous = parseStructure(data, offset, cs, connection, metadata, + metadata.keys, metadata.types); + offset += cs; + } + + reply.add(previous); } + reply.seal(); + return reply; + } - /// - /// Parse property value. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// DistributedConnection is required to fetch resources. - /// Output content size. - /// PropertyValue. - static AsyncReply parsePropertyValue(DC data, int offset, SizeObject sizeObject, DistributedConnection connection) - { - var reply = new AsyncReply(); + /// + /// Compose a structure into an array of bytes + /// + /// Structure to compose + /// DistributedConnection is required in case an item in the structure is at the other end + /// Whether to include the structure keys + /// Whether to include each item DataType + /// If true, prepend the length as UInt32 at the beginning of the returned bytes array + /// Array of bytes in the network byte order + static DC composeStructure(Structure value, DistributedConnection connection, + [bool includeKeys = true, + bool includeTypes = true, + bool prependLength = false]) { + var rt = new BinaryList(); - var age = data.getUint64(offset); - offset += 8; - - DateTime date = data.getDateTime(offset); - offset += 8; - - parse(data, offset, connection, sizeObject).then((value) - { - reply.trigger(new PropertyValue(value, age, date)); - }); - - sizeObject.size += 16; - - return reply; + if (includeKeys) { + for (var k in value.keys) { + var key = DC.stringToBytes(k); + rt.addUint8(key.length).addDC(key).addDC(compose(value[k], connection)); + } + } else { + for (var k in value.keys) + rt.addDC(compose(value[k], connection, includeTypes)); } + if (prependLength) rt.insertInt32(0, rt.length); - /// - /// Parse resource history - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// Resource - /// Starting age. - /// Ending age. - /// DistributedConnection is required to fetch resources. - /// - static AsyncReply>> parseHistory(DC data, int offset, int length, IResource resource, DistributedConnection connection) - { + return rt.toDC(); //.toArray(); + } - var list = new KeyList>(); + /// + /// Parse a structure + /// + /// Bytes array + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// Array to store keys in. + /// Array to store DataTypes in. + /// Array of keys, in case the data doesn't include keys + /// Array of DataTypes, in case the data doesn't include DataTypes + /// Structure + static AsyncReply parseStructure( + DC data, int offset, int length, DistributedConnection connection, + [StructureMetadata metadata = null, + List keys = null, + List types = + null]) // out string[] parsedKeys, out DataType[] parsedTypes, string[] keys = null, DataType[] types = null) + { + var reply = new AsyncReply(); + var bag = new AsyncBag(); + var keylist = new List(); + var typelist = new List(); + var sizeObject = new SizeObject(); - var reply = new AsyncReply>>(); + if (keys == null) { + while (length > 0) { + var len = data[offset++]; + keylist.add(data.getString(offset, len)); + offset += len; - var bagOfBags = new AsyncBag>(); + typelist.add(data[offset]); - var ends = offset + length; + bag.add(Codec.parse(data, offset, connection, sizeObject)); + length -= sizeObject.size + len + 1; + offset += sizeObject.size; + } + } else if (types == null) { + keylist.addAll(keys); - //var sizeObject = new SizeObject(); + while (length > 0) { + typelist.add(data[offset]); - 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(parsePropertyValueArray(data, offset, cs, connection)); - offset += cs; - } + bag.add(Codec.parse(data, offset, connection, sizeObject)); + length -= sizeObject.size; + offset += sizeObject.size; + } + } else { + keylist.addAll(keys); + typelist.addAll(types); - bagOfBags.seal(); - - bagOfBags.then((x) - { - for(var i = 0; i < list.length; i++) - list[list.keys.elementAt(i)] = x[i]; - - reply.trigger(list); - }); - - return reply; - + var i = 0; + while (length > 0) { + bag.add(parse(data, offset, connection, sizeObject, types[i])); + length -= sizeObject.size; + offset += sizeObject.size; + i++; + } } - /// - /// Compose resource history - /// - /// History - /// DistributedConnection is required to fetch resources. - /// - static DC composeHistory(KeyList> history, - DistributedConnection connection, [bool prependLength = false]) - { - var rt = new BinaryList(); + bag.seal(); - for (var i = 0; i < history.length; i++) - rt.addUint8(history.keys.elementAt(i).index) - .addDC(composePropertyValueArray(history.values.elementAt(i), connection, true)); + bag.then((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 (prependLength) - rt.insertInt32(0, rt.length); - - return rt.toDC(); + if (metadata != null) { + metadata.keys = keylist; + metadata.types = typelist; } - /// - /// Parse an array of PropertyValue. - /// - /// Array of bytes. - /// Zero-indexed offset. - /// Number of bytes to parse. - /// DistributedConnection is required to fetch resources. - /// Whether property age is represented in the data. - /// - static AsyncBag parsePropertyValueArray(DC data, int offset, int length, DistributedConnection connection)//, bool ageIncluded = true) - { + return reply; + } - //print("parsePropertyValueArray ${offset} ${length}"); + /// + /// Parse a value + /// + /// Bytes array + /// Zero-indexed offset. + /// Output the number of bytes parsed + /// DistributedConnection is required in case a structure in the array holds items at the other end. + /// DataType, in case the data is not prepended with DataType + /// Value + static AsyncReply parse( + DC data, int offset, DistributedConnection connection, + [SizeObject sizeObject, int dataType = DataType.Unspecified]) { + bool isArray; + int t; - var rt = new AsyncBag(); + if (dataType == DataType.Unspecified) { + sizeObject?.size = 1; + dataType = data[offset++]; + } else + sizeObject?.size = 0; - var sizeObject = new SizeObject(); + t = dataType & 0x7F; - while (length > 0) - { + isArray = (dataType & 0x80) == 0x80; - rt.add(parsePropertyValue(data, offset, sizeObject, connection)); + var payloadSize = DataType.size(dataType); - if (sizeObject.size > 0) - { - offset += sizeObject.size; - length -= sizeObject.size; - } - else - throw new Exception("Error while parsing ValueInfo structured data"); - } + int contentLength = 0; - rt.seal(); - return rt; + // check if we have the enough data + if (payloadSize == -1) { + contentLength = data.getUint32(offset); + offset += 4; + sizeObject?.size += 4 + contentLength; + } else + sizeObject?.size += payloadSize; + + if (isArray) { + switch (t) { + // VarArray ? + case DataType.Void: + return parseVarArray(data, offset, contentLength, connection); + + case DataType.Bool: + return new AsyncReply>.ready( + data.getBooleanArray(offset, contentLength)); + + case DataType.UInt8: + return new AsyncReply.ready( + data.getUint8Array(offset, contentLength)); + + case DataType.Int8: + return new AsyncReply.ready( + data.getInt8Array(offset, contentLength)); + + case DataType.Char: + return new AsyncReply>.ready( + data.getCharArray(offset, contentLength)); + + case DataType.Int16: + return new AsyncReply.ready( + data.getInt16Array(offset, contentLength)); + + case DataType.UInt16: + return new AsyncReply.ready( + data.getUint16Array(offset, contentLength)); + + case DataType.Int32: + return new AsyncReply.ready( + data.getInt32Array(offset, contentLength)); + + case DataType.UInt32: + return new AsyncReply.ready( + data.getUint32Array(offset, contentLength)); + + case DataType.Int64: + return new AsyncReply.ready( + data.getInt64Array(offset, contentLength)); + + case DataType.UInt64: + return new AsyncReply.ready( + data.getUint64Array(offset, contentLength)); + + case DataType.Float32: + return new AsyncReply.ready( + data.getFloat32Array(offset, contentLength)); + + case DataType.Float64: + return new AsyncReply.ready( + data.getFloat64Array(offset, contentLength)); + + case DataType.String: + return new AsyncReply>.ready( + data.getStringArray(offset, contentLength)); + + case DataType.Resource: + case DataType.DistributedResource: + return parseResourceArray(data, offset, contentLength, connection); + + case DataType.DateTime: + return new AsyncReply>.ready( + data.getDateTimeArray(offset, contentLength)); + + case DataType.Structure: + return parseStructureArray(data, offset, contentLength, connection); + + case DataType.Record: + return parseRecordArray(data, offset, contentLength, connection); + } + } else { + switch (t) { + case DataType.NotModified: + return new AsyncReply.ready(new NotModified()); + + case DataType.Void: + return new AsyncReply.ready(null); + + case DataType.Bool: + return new AsyncReply.ready(data.getBoolean(offset)); + + case DataType.UInt8: + return new AsyncReply.ready(data[offset]); + + case DataType.Int8: + return new AsyncReply.ready(data[offset]); + + case DataType.Char: + return new AsyncReply.ready(data.getChar(offset)); + + case DataType.Int16: + return new AsyncReply.ready(data.getInt16(offset)); + + case DataType.UInt16: + return new AsyncReply.ready(data.getUint16(offset)); + + case DataType.Int32: + return new AsyncReply.ready(data.getInt32(offset)); + + case DataType.UInt32: + return new AsyncReply.ready(data.getUint32(offset)); + + case DataType.Int64: + return new AsyncReply.ready(data.getInt64(offset)); + + case DataType.UInt64: + return new AsyncReply.ready(data.getUint64(offset)); + + case DataType.Float32: + return new AsyncReply.ready(data.getFloat32(offset)); + + case DataType.Float64: + return new AsyncReply.ready(data.getFloat64(offset)); + + case DataType.String: + return new AsyncReply.ready( + data.getString(offset, contentLength)); + + case DataType.Resource: + return parseResource(data, offset); + + case DataType.DistributedResource: + return parseDistributedResource(data, offset, connection); + + case DataType.DateTime: + return new AsyncReply.ready(data.getDateTime(offset)); + + case DataType.Structure: + return parseStructure(data, offset, contentLength, connection); + + case DataType.Record: + return parseRecord(data, offset, contentLength, connection); + } } - /// - /// Compose a variable - /// - /// Value to compose. - /// DistributedConnection is required to check locality. - /// If True, prepend the DataType at the beginning of the output. - /// Array of bytes in the network byte order. - static DC compose(dynamic value, DistributedConnection connection, [bool prependType = true]) - { + return null; + } - if (value is Function(DistributedConnection)) - value = Function.apply(value, [connection]); - else if (value is DistributedPropertyContext) - value = (value as DistributedPropertyContext).method(connection); - - var type = getDataType(value, connection); - var rt = new BinaryList(); + /// + /// Parse a resource + /// + /// Bytes array + /// Zero-indexed offset. + /// Resource + static AsyncReply parseResource(DC data, int offset) { + return Warehouse.get(data.getUint32(offset)); + } - switch (type) - { - - case DataType.Void: - // nothing to do; - break; + /// + /// Parse a DistributedResource + /// + /// Bytes array + /// Zero-indexed offset. + /// DistributedConnection is required. + /// DistributedResource + static AsyncReply parseDistributedResource( + DC data, int offset, DistributedConnection connection) { + //var g = data.GetGuid(offset); + //offset += 16; - case DataType.String: - var st = DC.stringToBytes(value); - rt.addInt32(st.length).addDC(st); - break; + // find the object + var iid = data.getUint32(offset); - case DataType.Resource: - rt.addUint32((value as DistributedResource).id); - break; + return connection.fetch(iid); // Warehouse.Get(iid); + } - case DataType.DistributedResource: - rt.addUint32((value as IResource).instance.id); - break; + /// + /// Check if a resource is local to a given connection. + /// + /// Resource to check. + /// DistributedConnection to check if the resource is local to it. + /// True, if the resource owner is the given connection, otherwise False. + static bool isLocalResource( + IResource resource, DistributedConnection connection) { + if (resource is DistributedResource) if ((resource as DistributedResource) + .connection == + connection) return true; - case DataType.Structure: - rt.addDC(composeStructure(value, connection, true, true, true)); - break; + return false; + } - case DataType.VarArray: - rt.addDC(composeVarArray(value, connection, true)); - break; + /// + /// Compare two resources + /// + /// Initial resource to make comparison with. + /// Next resource to compare with the initial. + /// DistributedConnection is required to check locality. + /// Null, same, local, distributed or same class distributed. - case DataType.ResourceArray: - rt.addDC(composeResourceArray(value, connection, true)); - break; + static int compareResources( + IResource initial, IResource next, DistributedConnection connection) { + if (next == null) + return ResourceComparisonResult.Null; + else if (next == initial) + return ResourceComparisonResult.Same; + else if (isLocalResource(next, connection)) + return ResourceComparisonResult.Local; + else + return ResourceComparisonResult.Distributed; + } - case DataType.StructureArray: - rt.addDC(composeStructureArray(value, connection, true)); - break; + /// + /// Compose a resource + /// + /// Resource to compose. + /// DistributedConnection is required to check locality. + /// Array of bytes in the network byte order. + static DC composeResource( + IResource resource, DistributedConnection connection) { + if (isLocalResource(resource, connection)) + return DC.uint32ToBytes((resource as DistributedResource).id); + else { + return new BinaryList() + .addGuid(resource.instance.template.classId) + .addUint32(resource.instance.id) + .toDC(); + //return BinaryList.ToBytes(resource.Instance.Template.ClassId, resource.Instance.Id); + } + } - default: - rt.add(type, value); - if (DataType.isArray(type)) - rt.insertInt32(0, rt.length); - break; - } + /// + /// Compose an array of resources + /// + /// Array of resources. + /// DistributedConnection is required to check locality. + /// If True, prepend the length of the output at the beginning. + /// Array of bytes in the network byte order. - if (prependType) - rt.insertUint8(0, type); + static DC composeResourceArray( + List resources, DistributedConnection connection, + [bool prependLength = false]) { + if (resources == null || resources?.length == 0) + return prependLength ? new DC(4) : new DC(0); - return rt.toDC(); + var rt = new BinaryList(); + var comparsion = compareResources(null, resources[0], connection); + + if (T != IResource) { + // get template + var tmp = Warehouse.getTemplateByType(T); + + if (tmp == null) // something wrong + rt.addUint8(comparsion); + else { + // typed array + rt.addUint8((tmp.type == TemplateType.Resource + ? ResourceArrayType.Static + : ResourceArrayType.Wrapper) | + comparsion); + // add type + rt.addGuid(tmp.classId); + } + } else { + rt.addUint8(comparsion); } - /// - /// Get the DataType of a given value. - /// This function is needed to compose a value. - /// - /// Value to find its DataType. - /// DistributedConnection is required to check locality of resources. - /// DataType. - static int getDataType(value, DistributedConnection connection) - { - if (value == null) - return DataType.Void; + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32((resources[0] as DistributedResource).id); + else if (comparsion == ResourceComparisonResult.Distributed) + rt.addUint32(resources[0].instance.id); - if (value is bool) - return DataType.Bool; - else if (value is List) - return DataType.BoolArray; - else if (value is int) - return DataType.Int64; - else if (value is List || value is Int64List) - return DataType.Int64Array; - else if (value is double) - return DataType.Float64; - else if (value is List) - return DataType.Float64Array; - else if (value is String) - return DataType.String; - else if (value is List) - return DataType.StringArray; - else if (value is Uint8List) - return DataType.UInt8Array; - else if (value is Int8List) - return DataType.Int8Array; - else if (value is Uint16List) - return DataType.UInt16Array; - else if (value is Int16List) - return DataType.Int16Array; - else if (value is Uint32List) - return DataType.UInt32Array; - else if (value is Int32List) - return DataType.Int32Array; - else if (value is Uint64List) - return DataType.Int64Array; - else if (value is DateTime) - return DataType.DateTime; - else if (value is List) - return DataType.DateTimeArray; - else if (value is IResource) - return isLocalResource(value, connection) ? DataType.Resource : DataType.DistributedResource; - else if (value is List) - return DataType.ResourceArray; - else if (value is Structure) - return DataType.Structure; - else if (value is List) - return DataType.StructureArray; - else if (value is List) - return DataType.VarArray; - else - return DataType.Void; + for (var i = 1; i < resources.length; i++) { + comparsion = compareResources(resources[i - 1], resources[i], connection); + rt.addUint8(comparsion); + if (comparsion == ResourceComparisonResult.Local) + rt.addUint32((resources[i] as DistributedResource).id); + else if (comparsion == ResourceComparisonResult.Distributed) + rt.addUint32(resources[i].instance.id); } - /// - /// Check if a type implements an interface - /// - /// Sub-class type. - /// Super-interface type. - /// True, if implements . - static bool implementsInterface() => _DummyClass() is _DummyClass; + if (prependLength) rt.insertInt32(0, rt.length); + + return rt.toDC(); + } + + /// + /// Parse an array of bytes into array of resources + /// + /// Array of bytes. + /// Number of bytes to parse. + /// Zero-indexed offset. + /// DistributedConnection is required to fetch resources. + /// Array of resources. + static AsyncBag parseResourceArray( + DC data, int offset, int length, DistributedConnection connection) { + //print("parseResourceArray ${offset} ${length}"); + + var reply = new AsyncBag(); + if (length == 0) { + reply.seal(); + return reply; + } + + var end = offset + length; + + // + var result = data[offset++]; + + AsyncReply previous = null; + + if (result == ResourceComparisonResult.Null) + previous = new AsyncReply.ready(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++]; + + AsyncReply current = null; + + if (result == ResourceComparisonResult.Null) { + current = new AsyncReply.ready(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; + } + + /// + /// Compose an array of variables + /// + /// Variables. + /// DistributedConnection is required to check locality. + /// If True, prepend the length as UInt32 at the beginning of the output. + /// Array of bytes in the network byte order. + static DC composeVarArray(List array, DistributedConnection connection, + [bool prependLength = false]) { + var rt = new BinaryList(); + + for (var i = 0; i < array.length; i++) + rt.addDC(compose(array[i], connection)); + + if (prependLength) rt.insertUint32(0, rt.length); + + return rt.toDC(); + } + + /// + /// Parse an array of bytes into an array of varialbes. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required to fetch resources. + /// Array of variables. + static AsyncBag parseVarArray( + DC data, int offset, int length, DistributedConnection connection) { + var rt = new AsyncBag(); + var sizeObject = new SizeObject(); + + while (length > 0) { + rt.add(parse(data, offset, connection, sizeObject)); + + if (sizeObject.size > 0) { + offset += sizeObject.size; + length -= sizeObject.size; + } else + throw new Exception("Error while parsing structured data"); + } + + rt.seal(); + return rt; + } + + /// + /// Compose an array of property values. + /// + /// PropertyValue array. + /// DistributedConnection is required to check locality. + /// If True, prepend the length as UInt32 at the beginning of the output. + /// Array of bytes in the network byte order. + /// //, bool includeAge = true + static DC composePropertyValueArray( + List array, DistributedConnection connection, + [bool prependLength = false]) { + var rt = new BinaryList(); + + for (var i = 0; i < array.length; i++) + rt.addDC(composePropertyValue(array[i], connection)); + if (prependLength) rt.insertUint32(0, rt.length); + + return rt.toDC(); + } + + /// + /// Compose a property value. + /// + /// Property value + /// DistributedConnection is required to check locality. + /// Array of bytes in the network byte order. + static DC composePropertyValue(PropertyValue propertyValue, + DistributedConnection connection) //, bool includeAge = true) + { + return new BinaryList() + .addUint64(propertyValue.age) + .addDateTime(propertyValue.date) + .addDC(compose(propertyValue.value, connection)) + .toDC(); + } + + /// + /// Parse property value. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// DistributedConnection is required to fetch resources. + /// Output content size. + /// PropertyValue. + static AsyncReply parsePropertyValue(DC data, int offset, + SizeObject sizeObject, DistributedConnection connection) { + var reply = new AsyncReply(); + + var age = data.getUint64(offset); + offset += 8; + + DateTime date = data.getDateTime(offset); + offset += 8; + + parse(data, offset, connection, sizeObject).then((value) { + reply.trigger(new PropertyValue(value, age, date)); + }); + + sizeObject.size += 16; + + return reply; + } + + /// + /// Parse resource history + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// Resource + /// Starting age. + /// Ending age. + /// DistributedConnection is required to fetch resources. + /// + static AsyncReply>> + parseHistory(DC data, int offset, int length, IResource resource, + DistributedConnection connection) { + var list = new KeyList>(); + + var reply = + new AsyncReply>>(); + + var bagOfBags = new AsyncBag>(); + + var ends = offset + length; + + //var sizeObject = new SizeObject(); + + 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(parsePropertyValueArray(data, offset, cs, connection)); + offset += cs; + } + + bagOfBags.seal(); + + bagOfBags.then((x) { + for (var i = 0; i < list.length; i++) list[list.keys.elementAt(i)] = x[i]; + + reply.trigger(list); + }); + + return reply; + } + + /// + /// Compose resource history + /// + /// History + /// DistributedConnection is required to fetch resources. + /// + static DC composeHistory( + KeyList> history, + DistributedConnection connection, + [bool prependLength = false]) { + var rt = new BinaryList(); + + for (var i = 0; i < history.length; i++) + rt.addUint8(history.keys.elementAt(i).index).addDC( + composePropertyValueArray( + history.values.elementAt(i), connection, true)); + + if (prependLength) rt.insertInt32(0, rt.length); + + return rt.toDC(); + } + + /// + /// Parse an array of PropertyValue. + /// + /// Array of bytes. + /// Zero-indexed offset. + /// Number of bytes to parse. + /// DistributedConnection is required to fetch resources. + /// Whether property age is represented in the data. + /// + static AsyncBag parsePropertyValueArray(DC data, int offset, + int length, DistributedConnection connection) //, bool ageIncluded = true) + { + //print("parsePropertyValueArray ${offset} ${length}"); + + var rt = new AsyncBag(); + + var sizeObject = new SizeObject(); + + while (length > 0) { + rt.add(parsePropertyValue(data, offset, sizeObject, connection)); + + if (sizeObject.size > 0) { + offset += sizeObject.size; + length -= sizeObject.size; + } else + throw new Exception("Error while parsing ValueInfo structured data"); + } + + rt.seal(); + return rt; + } + + /// + /// Compose a variable + /// + /// Value to compose. + /// DistributedConnection is required to check locality. + /// If True, prepend the DataType at the beginning of the output. + /// Array of bytes in the network byte order. + static DC compose(dynamic value, DistributedConnection connection, + [bool prependType = true]) { + if (value is Function(DistributedConnection)) + value = Function.apply(value, [connection]); + else if (value is DistributedPropertyContext) + value = (value as DistributedPropertyContext).method(connection); + + var type = 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.addInt32(st.length).addDC(st); + break; + + case DataType.Resource: + rt.addUint32((value as DistributedResource).id); + break; + + case DataType.DistributedResource: + rt.addUint32((value as IResource).instance.id); + break; + + case DataType.Structure: + rt.addDC(composeStructure(value, connection, true, true, true)); + break; + + case DataType.VarArray: + rt.addDC(composeVarArray(value, connection, true)); + break; + + case DataType.Record: + rt.addDC(composeRecord(value, connection, true, true)); + break; + + case DataType.ResourceArray: + rt.addDC(composeResourceArray(value, connection, true)); + break; + + case DataType.StructureArray: + rt.addDC(composeStructureArray(value, connection, true)); + break; + + case DataType.RecordArray: + rt.addDC(composeRecordArray(value, connection, true)); + break; + + default: + rt.add(type, value); + if (DataType.isArray(type)) rt.insertInt32(0, rt.length); + break; + } + + if (prependType) rt.insertUint8(0, type); + + return rt.toDC(); + } + + /// + /// Get the DataType of a given value. + /// This function is needed to compose a value. + /// + /// Value to find its DataType. + /// DistributedConnection is required to check locality of resources. + /// DataType. + static int getDataType(value, DistributedConnection connection) { + if (value == null) return DataType.Void; + + if (value is bool) + return DataType.Bool; + else if (value is List) + return DataType.BoolArray; + else if (value is int) + return DataType.Int64; + else if (value is List || value is Int64List) + return DataType.Int64Array; + else if (value is double) + return DataType.Float64; + else if (value is List) + return DataType.Float64Array; + else if (value is String) + return DataType.String; + else if (value is List) + return DataType.StringArray; + else if (value is Uint8List) + return DataType.UInt8Array; + else if (value is Int8List) + return DataType.Int8Array; + else if (value is Uint16List) + return DataType.UInt16Array; + else if (value is Int16List) + return DataType.Int16Array; + else if (value is Uint32List) + return DataType.UInt32Array; + else if (value is Int32List) + return DataType.Int32Array; + else if (value is Uint64List) + return DataType.Int64Array; + else if (value is DateTime) + return DataType.DateTime; + else if (value is List) + return DataType.DateTimeArray; + else if (value is IResource) + return isLocalResource(value, connection) + ? DataType.Resource + : DataType.DistributedResource; + else if (value is List) + return DataType.ResourceArray; + else if (value is Structure) + return DataType.Structure; + else if (value is List) + return DataType.StructureArray; + else if (value is List) + return DataType.VarArray; + else if (value is IRecord) + return DataType.Record; + else if (value is List) + return DataType.RecordArray; + else + return DataType.Void; + } + + /// + /// Check if a type implements an interface + /// + /// Sub-class type. + /// Super-interface type. + /// True, if implements . + static bool implementsInterface() => + _DummyClass() is _DummyClass; } // related to implementsInterface -class _DummyClass { } \ No newline at end of file +class _DummyClass {} diff --git a/lib/src/Data/DC.dart b/lib/src/Data/DC.dart index 1e751f2..16aeff4 100644 --- a/lib/src/Data/DC.dart +++ b/lib/src/Data/DC.dart @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + import 'dart:typed_data'; import 'dart:convert'; import 'BinaryList.dart'; @@ -30,507 +30,408 @@ import 'Guid.dart'; * Created by Ahmed Zamil on 6/10/2019. */ - const UNIX_EPOCH = 621355968000000000; const TWO_PWR_32 = (1 << 16) * (1 << 16); -class DC with IterableMixin -{ +class DC with IterableMixin { + Uint8List _data; + ByteData _dv; + + DC(int length) { + _data = new Uint8List(length); + _dv = ByteData.view(_data.buffer); + } + + DC.fromUint8Array(Uint8List array) { + _data = array; + _dv = ByteData.view(_data.buffer); + } + + DC.fromList(List list) { + _data = Uint8List.fromList(list); + _dv = ByteData.view(_data.buffer); + } + + int operator [](int index) => _data[index]; + operator []=(int index, int value) => _data[index] = value; + int get length => _data.length; + + Iterator get iterator => _data.iterator; + + static DC hexToBytes(String value) { + // convert hex to Uint8Array + var rt = new DC(value.length ~/ 2); + for (var i = 0; i < rt.length; i++) + rt[i] = int.parse(value.substring(i * 2, 2), radix: 16); + return rt; + } + + static DC boolToBytes(value) { + var rt = new DC(1); + rt.setBoolean(0, value); + return rt; + } + + static DC guidToBytes(Guid value) { + var rt = new DC(16); + rt.setGuid(0, value); + return rt; + } + + static DC guidArrayToBytes(List value) { + var rt = new DC(value.length * 16); + for (var i = 0; i < value.length; i++) rt.setGuid(i * 16, value[i]); + return rt; + } + + static DC boolArrayToBytes(List value) { + var rt = new DC(value.length); + for (var i = 0; i < value.length; i++) rt[i] = value[i] ? 1 : 0; + return rt; + } + + static DC int8ToBytes(value) { + var rt = new DC(1); + rt.setInt8(0, value); + return rt; + } + + static DC int8ArrayToBytes(Int8List value) { + var rt = new DC(value.length); + for (var i = 0; i < value.length; i++) rt.setInt8(i, value[i]); + return rt; + } + + static DC uint8ToBytes(value) { + var rt = new DC(1); + rt.setUint8(0, value); + return rt; + } + + static DC uint8ArrayToBytes(Uint8List value) { + var rt = new DC(value.length); + for (var i = 0; i < value.length; i++) rt.setUint8(i, value[i]); + return rt; + } + + static DC charToBytes(int value) { + var rt = new DC(2); + rt.setChar(0, value); + return rt; + } + + static DC charArrayToBytes(Uint16List value) { + var rt = new DC(value.length * 2); + for (var i = 0; i < value.length; i++) rt.setChar(i * 2, value[i]); + + return rt; + } + + static DC int16ToBytes(int value) { + var rt = new DC(2); + rt.setInt16(0, value); + return rt; + } + + static DC int16ArrayToBytes(List value) { + var rt = new DC(value.length * 2); + for (var i = 0; i < value.length; i++) rt.setInt16(i * 2, value[i]); + return rt; + } + + static DC uint16ToBytes(int value) { + var rt = new DC(2); + rt.setUint16(0, value); + return rt; + } + + static DC uint16ArrayToBytes(Uint16List value) { + var rt = new DC(value.length * 2); + for (var i = 0; i < value.length; i++) rt.setUint16(i * 2, value[i]); + return rt; + } + + static DC int32ToBytes(int value) { + var rt = new DC(4); + rt.setInt32(0, value); + return rt; + } + + static DC int32ArrayToBytes(Int32List value) { + var rt = new DC(value.length * 4); + for (var i = 0; i < value.length; i++) rt.setInt32(i * 4, value[i]); + return rt; + } + + static DC uint32ToBytes(int value) { + var rt = new DC(4); + rt.setUint32(0, value); + return rt; + } + + static DC uint32ArrayToBytes(Uint32List value) { + var rt = new DC(value.length * 4); + for (var i = 0; i < value.length; i++) rt.setUint32(i * 4, value[i]); + return rt; + } + + static DC float32ToBytes(double value) { + var rt = new DC(4); + rt.setFloat32(0, value); + return rt; + } + + static DC float32ArrayToBytes(Float32List value) { + var rt = new DC(value.length * 4); + for (var i = 0; i < value.length; i++) rt.setFloat32(i * 4, value[i]); + return rt; + } + + static DC int64ToBytes(int value) { + var rt = new DC(8); + rt.setInt64(0, value); + return rt; + } + + static DC int64ArrayToBytes(Int64List value) { + var rt = new DC(value.length * 8); + for (var i = 0; i < value.length; i++) rt.setInt64(i * 8, value[i]); + return rt; + } + + static DC uint64ToBytes(int value) { + var rt = new DC(8); + rt.setUint64(0, value); + return rt; + } + + static DC uint64ArrayToBytes(Uint64List value) { + var rt = new DC(value.length * 8); + for (var i = 0; i < value.length; i++) rt.setUint64(i * 8, value[i]); + return rt; + } + + static DC float64ToBytes(double value) { + var rt = new DC(8); + rt.setFloat64(0, value); + return rt; + } + + static DC float64ArrayToBytes(Float64List value) { + var rt = new DC(value.length * 8); + for (var i = 0; i < value.length; i++) rt.setFloat64(i * 8, value[i]); + return rt; + } + + static DC dateTimeToBytes(DateTime value) { + var rt = new DC(8); + rt.setDateTime(0, value); + return rt; + } + + static DC dateTimeArrayToBytes(List value) { + var rt = new DC(value.length * 8); + for (var i = 0; i < value.length; i++) rt.setDateTime(i * 8, value[i]); + return rt; + } + + static DC stringToBytes(String value) { + var bytes = utf8.encode(value); + var rt = new DC.fromList(bytes); + return rt; + } + + static DC stringArrayToBytes(List value) { + var list = new BinaryList(); + for (var i = 0; i < value.length; i++) { + var s = DC.stringToBytes(value[i]); + list.addUint32(s.length).addUint8Array(s.toArray()); + } + + return list.toDC(); + } + + DC append(DC src, int offset, int length) { + //if (!(src is 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); + + this._data = rt._data; + this._dv = rt._dv; + + return this; + } + + set(DC dc, int offset) { + _data.setRange(offset, offset + dc.length, dc._data); + } + + static combine(a, aOffset, aLength, b, bOffset, bLength) { + if (!(a is DC)) a = new DC(a); + if (!(b is 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; + } + + DC clip(offset, length) { + return DC.fromUint8Array( + Uint8List.fromList(_data.getRange(offset, offset + length).toList())); + } + + getInt8(int offset) { + return _dv.getInt8(offset); + } + + getUint8(int offset) { + return _data[offset]; // this.dv.getUint8(offset); + } + + getInt16(int offset) { + return _dv.getInt16(offset); + } + + getUint16(int offset) { + return _dv.getUint16(offset); + } + + getInt32(int offset) { + return _dv.getInt32(offset); + } + + getUint32(int offset) { + return _dv.getUint32(offset); + } + + getFloat32(int offset) { + return _dv.getFloat32(offset); + } + + getFloat64(int offset) { + return _dv.getFloat64(offset); + } + + setInt8(int offset, int value) { + return _dv.setInt8(offset, value); + } + + setUint8(int offset, int value) { + return _dv.setUint8(offset, value); + } - Uint8List _data; - ByteData _dv; + setInt16(int offset, int value) { + return _dv.setInt16(offset, value); + } - DC(int length) - { - _data = new Uint8List(length); - _dv = ByteData.view(_data.buffer); - } - - DC.fromUint8Array(Uint8List array) - { - _data = array; - _dv = ByteData.view(_data.buffer); - } - - DC.fromList(List list) - { - _data = Uint8List.fromList(list); - _dv = ByteData.view(_data.buffer); - } - - operator [](index) => _data[index]; - operator []=(index,value) => _data[index] = value; - int get length => _data.length; - - Iterator get iterator => _data.iterator; - - static DC hexToBytes(String value) - { - // convert hex to Uint8Array - var rt = new DC(value.length~/2); - for(var i = 0; i < rt.length; i++) - rt[i] = int.parse(value.substring(i*2, 2), radix: 16); - return rt; - } - - static DC boolToBytes(value) - { - var rt = new DC(1); - rt.setBoolean(0, value); - return rt; - } - - - static DC guidToBytes(Guid value) - { - var rt = new DC(16); - rt.setGuid(0, value); - return rt; - } - - static DC guidArrayToBytes(List value) - { - var rt = new DC(value.length * 16); - for(var i = 0; i < value.length; i++) - rt.setGuid(i * 16, value[i]); - return rt; - } - - static DC boolArrayToBytes(List value) - { - var rt = new DC(value.length); - for(var i = 0; i < value.length; i++) - rt[i] = value[i] ? 1 : 0; - return rt; - } - - static DC int8ToBytes(value) - { - var rt = new DC(1); - rt.setInt8(0, value); - return rt; - } - - static DC int8ArrayToBytes(Int8List value) - { - var rt = new DC(value.length); - for(var i = 0; i < value.length; i++) - rt.setInt8(i, value[i]); - return rt; - } - - - - static DC uint8ToBytes(value) - { - var rt = new DC(1); - rt.setUint8(0, value); - return rt; - } - - static DC uint8ArrayToBytes(Uint8List value) - { - var rt = new DC(value.length); - for(var i = 0; i < value.length; i++) - rt.setUint8(i, value[i]); - return rt; - } - - static DC charToBytes(int value) - { - var rt = new DC(2); - rt.setChar(0, value); - return rt; - } - - static DC charArrayToBytes(Uint16List value) - { - var rt = new DC(value.length * 2); - for(var i = 0; i < value.length; i++) - rt.setChar(i*2, value[i]); - - return rt; - } - - static DC int16ToBytes(int value) - { - var rt = new DC(2); - rt.setInt16(0, value); - return rt; - } + setUint16(int offset, int value) { + return _dv.setUint16(offset, value); + } - static DC int16ArrayToBytes(List value) - { - var rt = new DC(value.length * 2); - for(var i = 0; i < value.length; i++) - rt.setInt16(i*2, value[i]); - return rt; - } - - static DC uint16ToBytes(int value) - { - var rt = new DC(2); - rt.setUint16(0, value); - return rt; - } - - static DC uint16ArrayToBytes(Uint16List value) - { - var rt = new DC(value.length * 2); - for(var i = 0; i < value.length; i++) - rt.setUint16(i*2, value[i]); - return rt; - } - - static DC int32ToBytes(int value) - { - var rt = new DC(4); - rt.setInt32(0, value); - return rt; - } - - static DC int32ArrayToBytes(Int32List value) - { - var rt = new DC(value.length * 4); - for(var i = 0; i < value.length; i++) - rt.setInt32(i*4, value[i]); - return rt; - } - - static DC uint32ToBytes(int value) - { - var rt = new DC(4); - rt.setUint32(0, value); - return rt; - } - - static DC uint32ArrayToBytes(Uint32List value) - { - var rt = new DC(value.length * 4); - for(var i = 0; i < value.length; i++) - rt.setUint32(i*4, value[i]); - return rt; - } - - static DC float32ToBytes(double value) - { - var rt = new DC(4); - rt.setFloat32(0, value); - return rt; - } - - static DC float32ArrayToBytes(Float32List value) - { - var rt = new DC(value.length * 4); - for(var i = 0; i < value.length; i++) - rt.setFloat32(i*4, value[i]); - return rt; - } + setInt32(int offset, int value) { + return _dv.setInt32(offset, value); + } - static DC int64ToBytes(int value) - { - var rt = new DC(8); - rt.setInt64(0, value); - return rt; - } + setUint32(int offset, int value) { + return _dv.setUint32(offset, value); + } - static DC int64ArrayToBytes(Int64List value) - { - var rt = new DC(value.length * 8); - for(var i = 0; i < value.length; i++) - rt.setInt64(i*8, value[i]); - return rt; - } + setFloat32(int offset, double value) { + return _dv.setFloat32(offset, value); + } - static DC uint64ToBytes(int value) - { - var rt = new DC(8); - rt.setUint64(0, value); - return rt; - } + setFloat64(int offset, double value) { + return _dv.setFloat64(offset, value); + } - static DC uint64ArrayToBytes(Uint64List value) - { - var rt = new DC(value.length * 8); - for(var i = 0; i < value.length; i++) - rt.setUint64(i*8, value[i]); - return rt; - } + Int8List getInt8Array(int offset, int length) { + return _data.buffer.asInt8List(offset, length); + } - static DC float64ToBytes(double value) - { - var rt = new DC(8); - rt.setFloat64(0, value); - return rt; - } + Uint8List getUint8Array(int offset, int length) { + return _data.buffer.asUint8List(offset, length); + } - static DC float64ArrayToBytes(Float64List value) - { - var rt = new DC(value.length * 8); - for(var i = 0; i < value.length; i++) - rt.setFloat64(i*8, value[i]); - return rt; - } + Int16List getInt16Array(int offset, int length) { + return _data.buffer.asInt16List(offset, length); + } - static DC dateTimeToBytes(DateTime value) - { - var rt = new DC(8); - rt.setDateTime(0, value); - return rt; - } + Uint16List getUint16Array(int offset, int length) { + return _data.buffer.asUint16List(offset, length); + } + Int32List getInt32Array(int offset, int length) { + return _data.buffer.asInt32List(offset, length); + } - - static DC dateTimeArrayToBytes(List value) - { - var rt = new DC(value.length * 8); - for(var i = 0; i < value.length; i++) - rt.setDateTime(i*8, value[i]); - return rt; - } + Uint32List getUint32Array(int offset, int length) { + return _data.buffer.asUint32List(offset, length); + } + Float32List getFloat32Array(int offset, int length) { + return _data.buffer.asFloat32List(offset, length); + } + + Float64List getFloat64Array(int offset, int length) { + return _data.buffer.asFloat64List(offset, length); + } + + Int64List getInt64Array(int offset, int length) { + return _data.buffer.asInt64List(offset, length); + } - static DC stringToBytes(String value) - { - var bytes = utf8.encode(value); - var rt = new DC.fromList(bytes); - return rt; - } + Uint64List getUint64Array(int offset, int length) { + return _data.buffer.asUint64List(offset, length); + } - static DC stringArrayToBytes(List value) - { - var list = new BinaryList(); - for(var i = 0; i < value.length; i++) - { - var s = DC.stringToBytes(value[i]); - list.addUint32(s.length).addUint8Array(s.toArray()); - } + bool getBoolean(int offset) { + return this.getUint8(offset) > 0; + } - return list.toDC(); - } - - DC append(DC src, int offset, int length) - { - //if (!(src is 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); - - this._data = rt._data; - this._dv = rt._dv; + setBoolean(int offset, bool value) { + this.setUint8(offset, value ? 1 : 0); + } - return this; - } - - set(DC dc, int offset) - { - _data.setRange(offset, offset + dc.length, dc._data); - } + List getBooleanArray(int offset, int length) { + List rt = []; + for (var i = 0; i < length; i++) rt.add(this.getBoolean(offset + i)); + return rt; + } - static combine(a, aOffset, aLength, b, bOffset, bLength) - { - if (!(a is DC)) - a = new DC(a); - if (!(b is DC)) - b = new DC(b); + String getChar(int offset) { + return String.fromCharCode(this.getUint16(offset)); + } - a = a.clip(aOffset, aLength); - b = b.clip(bOffset, bLength); + setChar(int offset, int value) { + this.setUint16(offset, value); //value.codeUnitAt(0)); + } - var rt = new DC(a.length + b.length); + List getCharArray(int offset, int length) { + List rt = []; + for (var i = 0; i < length; i += 2) rt.add(this.getChar(offset + i)); + return rt; + } - - rt.set(a, 0); - rt.set(b, a.length); - return rt; + String getHex(offset, length) { + var rt = ""; + for (var i = offset; i < offset + length; i++) { + var h = _data[i].toRadixString(16); + rt += h.length == 1 ? "0" + h : h; } - DC clip(offset, length) - { - return DC.fromUint8Array(Uint8List.fromList(_data.getRange(offset, offset + length).toList())); - } - - getInt8(int offset) - { - return _dv.getInt8(offset); - } - - getUint8(int offset) - { - return _data[offset];// this.dv.getUint8(offset); - } - - getInt16(int offset) - { - return _dv.getInt16(offset); - } - - getUint16(int offset) - { - return _dv.getUint16(offset); - } - - getInt32(int offset) - { - return _dv.getInt32(offset); - } - - getUint32(int offset) - { - return _dv.getUint32(offset); - } - - getFloat32(int offset) - { - return _dv.getFloat32(offset); - } - - getFloat64(int offset) - { - return _dv.getFloat64(offset); - } - - setInt8(int offset, int value) - { - return _dv.setInt8(offset, value); - } - - setUint8(int offset, int value) - { - return _dv.setUint8(offset, value); - } - - setInt16(int offset, int value) - { - return _dv.setInt16(offset, value); - } - - setUint16(int offset, int value) - { - return _dv.setUint16(offset, value); - } - - setInt32(int offset, int value) - { - return _dv.setInt32(offset, value); - } - - setUint32(int offset, int value) - { - return _dv.setUint32(offset, value); - } - - setFloat32(int offset, double value) - { - return _dv.setFloat32(offset, value); - } - - setFloat64(int offset, double value) - { - return _dv.setFloat64(offset, value); - } - - Int8List getInt8Array(int offset, int length) - { - return _data.buffer.asInt8List(offset, length); - } - - Uint8List getUint8Array(int offset, int length) - { - return _data.buffer.asUint8List(offset, length); - } - - Int16List getInt16Array(int offset, int length) - { - return _data.buffer.asInt16List(offset, length); - } - - Uint16List getUint16Array(int offset, int length) - { - return _data.buffer.asUint16List(offset, length); - } - - Int32List getInt32Array(int offset, int length) - { - return _data.buffer.asInt32List(offset, length); - } - - Uint32List getUint32Array(int offset, int length) - { - return _data.buffer.asUint32List(offset, length); - } - - Float32List getFloat32Array(int offset, int length) - { - return _data.buffer.asFloat32List(offset, length); - } - - Float64List getFloat64Array(int offset, int length) - { - return _data.buffer.asFloat64List(offset, length); - } - - Int64List getInt64Array(int offset, int length) - { - return _data.buffer.asInt64List(offset, length); - } - - Uint64List getUint64Array(int offset, int length) - { - return _data.buffer.asUint64List(offset, length); - } - - bool getBoolean(int offset) - { - return this.getUint8(offset) > 0; - } - - setBoolean(int offset, bool value) - { - this.setUint8(offset, value ? 1: 0); - } - - List getBooleanArray(int offset, int length) - { - var rt = new List(); - for(var i = 0; i < length; i++) - rt.add(this.getBoolean(offset+i)); - return rt; - } - - String getChar(int offset) - { - return String.fromCharCode(this.getUint16(offset)); - } - - setChar(int offset, int value) - { - this.setUint16(offset, value); //value.codeUnitAt(0)); - } - - List getCharArray(int offset, int length) - { - var rt = new List(); - for(var i = 0; i < length; i+=2) - rt.add(this.getChar(offset+i)); - return rt; - } - - String 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; - } + return rt; + } - /* + /* List toList(offset, length) { var rt = new List(); @@ -538,106 +439,84 @@ class DC with IterableMixin rt[i] = _data[offset+i] as T; return rt; }*/ - - Uint8List toArray() => _data; - + Uint8List toArray() => _data; - String getString(offset, length) - { - var bytes = clip(offset, length)._data;// toList(offset, length); - var str = utf8.decode(bytes); - return str; + String getString(offset, length) { + var bytes = clip(offset, length)._data; // toList(offset, length); + var str = utf8.decode(bytes); + return str; + } + + List getStringArray(offset, length) { + List rt = []; + var i = 0; + + while (i < length) { + var cl = this.getUint32(offset + i); + i += 4; + rt.add(this.getString(offset + i, cl)); + i += cl; } - List getStringArray(offset, length) - { - var rt = List(); - var i = 0; + return rt; + } - while (i < length) - { - var cl = this.getUint32(offset + i); - i += 4; - rt.add(this.getString(offset + i, cl)); - i += cl; - } + getInt64(offset) { + return _dv.getUint64(offset); + } - return rt; + getUint64(offset) { + return _dv.getInt64(offset); + } + + void setInt64(offset, value) { + _dv.setInt64(offset, value); + } + + void setUint64(offset, value) { + _dv.setUint64(offset, value); + } + + setDateTime(offset, DateTime value) { + // Unix Epoch + var ticks = UNIX_EPOCH + (value.millisecondsSinceEpoch * 10000); + this.setUint64(offset, ticks); + } + + DateTime getDateTime(int offset) { + var ticks = this.getUint64(offset); + // there are 10,000 ticks in a millisecond + return DateTime.fromMillisecondsSinceEpoch((ticks - UNIX_EPOCH) ~/ 10000); + } + + List getDateTimeArray(int offset, int length) { + List rt = []; + for (var i = 0; i < length; i += 8) rt.add(this.getDateTime(offset + i)); + return rt; + } + + Guid getGuid(int offset) { + return new Guid(this.clip(offset, 16)); + } + + setGuid(int offset, Guid guid) { + set(guid.value, offset); + } + + List getGuidArray(int offset, int length) { + List rt = []; + for (var i = 0; i < length; i += 16) rt.add(this.getGuid(offset + i)); + return rt; + } + + bool 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; } - getInt64(offset) - { - return _dv.getUint64(offset); - } - - getUint64(offset) - { - return _dv.getInt64(offset); - } - - void setInt64(offset, value) - { - _dv.setInt64(offset, value); - } - - void setUint64(offset, value) - { - - _dv.setUint64(offset, value); - } - - setDateTime(offset, DateTime value) - { - // Unix Epoch - var ticks = UNIX_EPOCH + (value.millisecondsSinceEpoch * 10000); - this.setUint64(offset, ticks); - } - - DateTime getDateTime(int offset) - { - var ticks = this.getUint64(offset); - // there are 10,000 ticks in a millisecond - return DateTime.fromMillisecondsSinceEpoch((ticks-UNIX_EPOCH)~/10000); - } - - List getDateTimeArray(int offset, int length) - { - var rt = new List(); - for(var i = 0; i < length; i+=8) - rt.add(this.getDateTime(offset+i)); - return rt; - } - - Guid getGuid(int offset) - { - return new Guid(this.clip(offset, 16)); - } - - setGuid(int offset, Guid guid) - { - set(guid.value, offset); - } - - List getGuidArray(int offset, int length) - { - var rt = []; - for(var i = 0; i < length; i+=16) - rt.add(this.getGuid(offset+i)); - return rt; - } - - bool 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; - } -} \ No newline at end of file + return true; + } +} diff --git a/lib/src/Data/DataType.dart b/lib/src/Data/DataType.dart index 7af6f30..a142087 100644 --- a/lib/src/Data/DataType.dart +++ b/lib/src/Data/DataType.dart @@ -44,6 +44,7 @@ class DataType ResourceLink = 0x11, String = 0x12, Structure = 0x13, + Record = 0x14, //Stream, //Array = 0x80, VarArray = 0x80, @@ -66,6 +67,7 @@ class DataType ResourceLinkArray = 0x91, StringArray = 0x92, StructureArray = 0x93, + RecordArray = 0x94, NotModified = 0x7F, Unspecified = 0xFF; diff --git a/lib/src/Data/Guid.dart b/lib/src/Data/Guid.dart index 84c0c43..a42431b 100644 --- a/lib/src/Data/Guid.dart +++ b/lib/src/Data/Guid.dart @@ -1,18 +1,23 @@ import 'DC.dart'; -class Guid -{ +class Guid { DC _data; - Guid(DC data) - { + Guid(DC data) { _data = data; } - DC get value => _data; + DC get value => _data; + + bool operator ==(Object other) { + if (other is Guid) + return _data.sequenceEqual(other._data); + else + return false; + } @override String toString() { return _data.getString(0, _data.length); } -} \ No newline at end of file +} diff --git a/lib/src/Data/IRecord.dart b/lib/src/Data/IRecord.dart new file mode 100644 index 0000000..dea7214 --- /dev/null +++ b/lib/src/Data/IRecord.dart @@ -0,0 +1,32 @@ +/* + +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. + +*/ + +import '../Resource/Template/TemplateDescriber.dart'; + + +abstract class IRecord { + Map serialize(); + void deserialize(Map value); + TemplateDescriber get template; +} diff --git a/lib/src/Data/ParseResult.dart b/lib/src/Data/ParseResult.dart new file mode 100644 index 0000000..7442a02 --- /dev/null +++ b/lib/src/Data/ParseResult.dart @@ -0,0 +1,6 @@ +class ParseResult { + int size; + T value; + + ParseResult(this.size, this.value); +} diff --git a/lib/src/Data/Record.dart b/lib/src/Data/Record.dart new file mode 100644 index 0000000..cb8fed6 --- /dev/null +++ b/lib/src/Data/Record.dart @@ -0,0 +1,25 @@ +import 'package:esiur/src/Resource/Template/TemplateDescriber.dart'; + +import 'IRecord.dart'; +import 'KeyList.dart'; + +class Record extends KeyList with IRecord { + Map _props; + + @override + Map serialize() { + return _props; + } + + @override + deserialize(Map value) { + _props = value; + } + + operator [](index) => _props[index]; + operator []=(index, value) => _props[index] = value; + + @override + // TODO: implement template + TemplateDescriber get template => throw UnimplementedError(); +} diff --git a/lib/src/Data/RecordComparisonResult.dart b/lib/src/Data/RecordComparisonResult.dart new file mode 100644 index 0000000..a1b6f4f --- /dev/null +++ b/lib/src/Data/RecordComparisonResult.dart @@ -0,0 +1,6 @@ +class RecordComparisonResult { + static const Null = 0; + static const Record = 1; + static const RecordSameType = 2; + static const Same = 3; +} diff --git a/lib/src/Data/ResourceArrayType.dart b/lib/src/Data/ResourceArrayType.dart new file mode 100644 index 0000000..4690628 --- /dev/null +++ b/lib/src/Data/ResourceArrayType.dart @@ -0,0 +1,5 @@ +class ResourceArrayType { + static const int Dynamic = 0x0; + static const int Static = 0x10; + static const Wrapper = 0x20; +} diff --git a/lib/src/Misc/Global.dart b/lib/src/Misc/Global.dart new file mode 100644 index 0000000..5ace232 --- /dev/null +++ b/lib/src/Misc/Global.dart @@ -0,0 +1,13 @@ +import 'dart:math'; + +class Global { + static String generateCode( + [int length = 16, + chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"]) { + var rand = Random(); + + return String.fromCharCodes(Iterable.generate( + length, (_) => chars.codeUnitAt(rand.nextInt(chars.length)))); + } +} diff --git a/lib/src/Net/IIP/DistributedConnection.dart b/lib/src/Net/IIP/DistributedConnection.dart index ecc9893..f2252c3 100644 --- a/lib/src/Net/IIP/DistributedConnection.dart +++ b/lib/src/Net/IIP/DistributedConnection.dart @@ -23,7 +23,11 @@ SOFTWARE. */ import 'dart:ffi'; +import 'dart:typed_data'; +import 'package:esiur/esiur.dart'; +import 'package:esiur/src/Resource/Template/TemplateDescriber.dart'; +import 'package:esiur/src/Resource/Template/TemplateType.dart'; import 'package:esiur/src/Security/Authority/AuthenticationMethod.dart'; import '../../Core/AsyncBag.dart'; @@ -68,497 +72,522 @@ import '../Packets/IIPPacketReport.dart'; import '../../Data/BinaryList.dart'; import '../NetworkConnection.dart'; import '../../Data/Guid.dart'; -import '../../Resource/Template/ResourceTemplate.dart'; +import '../../Resource/Template/TypeTemplate.dart'; import '../../Security/Permissions/Ruling.dart'; import '../../Security/Permissions/ActionType.dart'; import '../../Data/Codec.dart'; -import '../../Data/DataType.dart'; import '../../Data/Structure.dart'; import '../../Core/ProgressType.dart'; import '../../Security/Integrity/SHA256.dart'; import '../../Resource/ResourceTrigger.dart'; +import './DistributedServer.dart'; -class DistributedConnection extends NetworkConnection with IStore -{ - //public delegate void ReadyEvent(DistributedConnection sender); - //public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); +class DistributedConnection extends NetworkConnection with IStore { + //public delegate void ReadyEvent(DistributedConnection sender); + //public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); - /// - /// Ready event is raised when the connection is fully established. - /// - //public event ReadyEvent OnReady; + /// + /// Ready event is raised when the connection is fully established. + /// + //public event ReadyEvent OnReady; - /// - /// Error event - /// - //public event ErrorEvent OnError; + /// + /// Error event + /// + //public event ErrorEvent OnError; - AsyncReply _openReply; + AsyncReply _openReply; - IIPPacket _packet = new IIPPacket(); - IIPAuthPacket _authPacket = new IIPAuthPacket(); + DistributedServer _server; - Session _session; + IIPPacket _packet = new IIPPacket(); + IIPAuthPacket _authPacket = new IIPAuthPacket(); - DC _localPasswordOrToken; - DC _localNonce, _remoteNonce; + Session _session; - String _hostname; - int _port; + DC _localPasswordOrToken; + DC _localNonce, _remoteNonce; - bool _ready = false, _readyToEstablish = false; + String _hostname; + int _port; + bool _ready = false, _readyToEstablish = false; - KeyList _resources = new KeyList(); + KeyList _resources = + new KeyList(); - KeyList> _resourceRequests = new KeyList>(); - KeyList> _templateRequests = new KeyList>(); - //KeyList> _pathRequests = new KeyList>(); - Map _templates = new Map(); - KeyList> _requests = new KeyList>(); - int _callbackCounter = 0; - AsyncQueue _queue = new AsyncQueue(); + KeyList> _resourceRequests = + new KeyList>(); + KeyList> _templateRequests = + new KeyList>(); + //KeyList> _pathRequests = new KeyList>(); + Map _templates = new Map(); + KeyList> _requests = + new KeyList>(); + int _callbackCounter = 0; + AsyncQueue _queue = + new AsyncQueue(); + Map> _subscriptions = new Map>(); - /// - /// Local username to authenticate ourselves. - /// - String get localUsername => _session.localAuthentication.username; + /// + /// Local username to authenticate ourselves. + /// + String get localUsername => _session.localAuthentication.username; - /// - /// Peer's username. - /// - String get remoteUsername => _session.remoteAuthentication.username;// { get; set; } + /// + /// Peer's username. + /// + String get remoteUsername => + _session.remoteAuthentication.username; // { get; set; } - /// - /// Working domain. - /// - //public string Domain { get { return domain; } } + /// + /// Working domain. + /// + //public string Domain { get { return domain; } } + /// + /// The session related to this connection. + /// + Session get session => _session; - /// - /// The session related to this connection. - /// - Session get session => _session; + /// + /// Distributed server responsible for this connection, usually for incoming connections. + /// + //public DistributedServer Server - /// - /// Distributed server responsible for this connection, usually for incoming connections. - /// - //public DistributedServer Server - - - bool remove(IResource resource) - { - // nothing to do - return true; + bool remove(IResource resource) { + // nothing to do + return true; + } + + /// + /// Send data to the other end as parameters + /// + /// Values will be converted to bytes then sent. + SendList sendParams([AsyncReply> reply = null]) { + return new SendList(this, reply); + } + + /// + /// Send raw data through the connection. + /// + /// Data to send. + void send(DC data) { + //Console.WriteLine("Client: {0}", Data.length); + + //Global.Counters["IIP Sent Packets"]++; + super.send(data); + } + + AsyncReply trigger(ResourceTrigger trigger) { + if (trigger == ResourceTrigger.Open) { + if (_server != null) return new AsyncReply.ready(true); + + var host = instance.name.split(":"); + + // assign domain from hostname if not provided + var address = host[0]; + var port = host.length > 1 ? int.parse(host[1]) : 10518; + + var domain = instance.attributes.containsKey("domain") + ? instance.attributes["domain"] + : address; + + if (instance.attributes.containsKey("username") && + instance.attributes.containsKey("password")) { + var username = instance.attributes["username"].toString(); + var password = + DC.stringToBytes(instance.attributes["password"].toString()); + + return connect( + method: AuthenticationMethod.Credentials, + domain: domain, + hostname: address, + port: port, + passwordOrToken: password, + username: username); + } else if (instance.attributes.containsKey("token")) { + var token = DC.stringToBytes(instance.attributes["token"].toString()); + var tokenIndex = instance.attributes["tokenIndex"] ?? 0; + return connect( + method: AuthenticationMethod.Credentials, + domain: domain, + hostname: address, + port: port, + passwordOrToken: token, + tokenIndex: tokenIndex); + } else { + return connect( + method: AuthenticationMethod.None, + hostname: address, + port: port, + domain: domain); + } } - /// - /// Send data to the other end as parameters - /// - /// Values will be converted to bytes then sent. - SendList sendParams([AsyncReply> reply = null]) - { - return new SendList(this, reply); + return new AsyncReply.ready(true); + } + + AsyncReply connect( + {AuthenticationMethod method, + ISocket socket, + String hostname, + int port, + String username, + int tokenIndex, + DC passwordOrToken, + String domain}) { + if (_openReply != null) + throw AsyncException(ErrorType.Exception, 0, "Connection in progress"); + + _openReply = new AsyncReply(); + + if (hostname != null) { + _session = + new Session(new ClientAuthentication(), new HostAuthentication()); + + _session.localAuthentication.method = method; + _session.localAuthentication.tokenIndex = tokenIndex; + _session.localAuthentication.domain = domain; + _session.localAuthentication.username = username; + _localPasswordOrToken = passwordOrToken; } - /// - /// Send raw data through the connection. - /// - /// Data to send. - void send(DC data) - { - //Console.WriteLine("Client: {0}", Data.length); + if (_session == null) + throw AsyncException(ErrorType.Exception, 0, "Session not initialized"); - //Global.Counters["IIP Sent Packets"]++; - super.send(data); - } + if (socket == null) socket = new TCPSocket(); + _port = port ?? _port; + _hostname = hostname ?? _hostname; - AsyncReply trigger(ResourceTrigger trigger) - { + socket.connect(_hostname, _port).then((x) { + assign(socket); + }).error((x) { + _openReply.triggerError(x); + _openReply = null; + }); - if (trigger == ResourceTrigger.Open) - { - if (instance.attributes.containsKey("username") - && instance.attributes.containsKey("password")) - { + return _openReply; + } - var host = instance.name.split(":"); - // assign domain from hostname if not provided + @override + void disconnected() { + // clean up + _ready = false; + _readyToEstablish = false; - var address = host[0]; - var port = int.parse(host[1]); - var username = instance.attributes["username"].toString(); + _requests.values.forEach((x) => x.triggerError( + AsyncException(ErrorType.Management, 0, "Connection closed"))); + _resourceRequests.values.forEach((x) => x.triggerError( + AsyncException(ErrorType.Management, 0, "Connection closed"))); + _templateRequests.values.forEach((x) => x.triggerError( + AsyncException(ErrorType.Management, 0, "Connection closed"))); - var domain = instance.attributes.containsKey("domain") ? instance.attributes["domain"] : address; + _requests.clear(); + _resourceRequests.clear(); + _templateRequests.clear(); - var password = DC.stringToBytes(instance.attributes["password"].toString()); + _resources.values.forEach((x) => x.suspend()); + } - return connect(method: AuthenticationMethod.Credentials, domain: domain, hostname: address, port: port, passwordOrToken: password, username: username); + Future reconnect() async { + if (await connect()) { + var bag = AsyncBag(); - } - else if (instance.attributes.containsKey("token")) - { - var host = instance.name.split(":"); - // assign domain from hostname if not provided - - var address = host[0]; - var port = int.parse(host[1]); - - var domain = instance.attributes.containsKey("domain") ? instance.attributes["domain"] : address; - - var token = DC.stringToBytes(instance.attributes["token"].toString()); - var tokenIndex = instance.attributes["tokenIndex"] ?? 0; - return connect(method: AuthenticationMethod.Credentials, domain: domain, hostname: address, port: port, passwordOrToken: token, tokenIndex: tokenIndex); - } + for (var i = 0; i < _resources.keys.length; i++) { + var index = _resources.keys.elementAt(i); + // print("Re $i ${_resources[index].instance.template.className}"); + bag.add(fetch(index)); } - return new AsyncReply.ready(true); + bag.seal(); + await bag; + + return true; } - AsyncReply connect({AuthenticationMethod method, ISocket socket, String hostname, int port, String username, int tokenIndex, DC passwordOrToken, String domain}) - { - if (_openReply != null) - throw AsyncException(ErrorType.Exception, 0, "Connection in progress"); + return false; + } - _openReply = new AsyncReply(); + /// + /// KeyList to store user variables related to this connection. + /// + final KeyList variables = new KeyList(); - if (hostname != null) - { - _session = new Session(new ClientAuthentication() - , new HostAuthentication()); + /// + /// IResource interface. + /// + Instance instance; - _session.localAuthentication.method = method; - _session.localAuthentication.tokenIndex = tokenIndex; - _session.localAuthentication.domain = domain; - _session.localAuthentication.username = username; - _localPasswordOrToken = passwordOrToken; - } - - if (_session == null) - throw AsyncException(ErrorType.Exception, 0, "Session not initialized"); + _declare() { + var dmn = DC.stringToBytes(session.localAuthentication.domain); - if (socket == null) - socket = new TCPSocket(); + if (session.localAuthentication.method == + AuthenticationMethod.Credentials) { + // declare (Credentials -> No Auth, No Enctypt) - _port = port ?? _port; - _hostname = hostname ?? _hostname; + var un = DC.stringToBytes(session.localAuthentication.username); - socket.connect(_hostname, _port).then((x){ - assign(socket); - }).error((x){ - _openReply.triggerError(x); - _openReply = null; - }); + sendParams() + .addUint8(0x60) + .addUint8(dmn.length) + .addDC(dmn) + .addDC(_localNonce) + .addUint8(un.length) + .addDC(un) + .done(); //, dmn, localNonce, (byte)un.Length, un); + } else if (session.localAuthentication.method == + AuthenticationMethod.Token) { + sendParams() + .addUint8(0x70) + .addUint8(dmn.length) + .addDC(dmn) + .addDC(_localNonce) + .addUint64(session.localAuthentication.tokenIndex) + .done(); //, dmn, localNonce, token - return _openReply; + } else if (session.localAuthentication.method == + AuthenticationMethod.None) { + sendParams() + .addUint8(0x40) + .addUint8(dmn.length) + .addDC(dmn) + .done(); //, dmn, localNonce, token + } + } + + /// + /// Assign a socket to the connection. + /// + /// Any socket that implements ISocket. + assign(ISocket socket) { + super.assign(socket); + + session.remoteAuthentication.source.attributes[SourceAttributeType.IPv4] = + socket.remoteEndPoint.address; + session.remoteAuthentication.source.attributes[SourceAttributeType.Port] = + socket.remoteEndPoint.port; + session.localAuthentication.source.attributes[SourceAttributeType.IPv4] = + socket.localEndPoint.address; + session.localAuthentication.source.attributes[SourceAttributeType.Port] = + socket.localEndPoint.port; + + if (session.localAuthentication.type == AuthenticationType.Client) { + // declare (Credentials -> No Auth, No Enctypt) + _declare(); + } + } + + /// + /// Create a new distributed connection. + /// + /// Socket to transfer data through. + /// Working domain. + /// Username. + /// Password. +/* + DistributedConnection.connect( + ISocket socket, String domain, String username, String password) { + _session = + new Session(new ClientAuthentication(), new HostAuthentication()); + + _session.localAuthentication.method = AuthenticationMethod.Credentials; + _session.localAuthentication.domain = domain; + _session.localAuthentication.username = username; + + _localPasswordOrToken = DC.stringToBytes(password); + + init(); + + assign(socket); + } + + DistributedConnection.connectWithToken( + ISocket socket, String domain, int tokenIndex, String token) { + _session = + new Session(new ClientAuthentication(), new HostAuthentication()); + + _session.localAuthentication.method = AuthenticationMethod.Token; + _session.localAuthentication.domain = domain; + _session.localAuthentication.tokenIndex = tokenIndex; + + _localPasswordOrToken = DC.stringToBytes(token); + + init(); + + assign(socket); + } +*/ + + /// + /// Create a new instance of a distributed connection + /// + DistributedConnection() { + //myId = Global.GenerateCode(12); + // localParams.Host = DistributedParameters.HostType.Host; + _session = + new Session(new HostAuthentication(), new ClientAuthentication()); + init(); + } + + String link(IResource resource) { + if (resource is DistributedResource) { + var r = resource as DistributedResource; + if (r.instance.store == this) + return this.instance.name + "/" + r.id.toString(); } + return null; + } - @override - void connectionClosed() - { - // clean up - _ready = false; - _readyToEstablish = false; - - _requests.values.forEach((x)=>x.triggerError(AsyncException(ErrorType.Management, 0, "Connection closed"))); - _resourceRequests.values.forEach((x)=>x.triggerError(AsyncException(ErrorType.Management, 0, "Connection closed"))); - _templateRequests.values.forEach((x)=>x.triggerError(AsyncException(ErrorType.Management, 0, "Connection closed"))); - - _requests.clear(); - _resourceRequests.clear(); - _templateRequests.clear(); + void init() { + _queue.then((x) { + if (x.type == DistributedResourceQueueItemType.Event) + x.resource.emitEventByIndex(x.index, x.value); + else + x.resource.updatePropertyByIndex(x.index, x.value); + }); - _resources.values.forEach((x)=>x.suspend()); - } + var r = new Random(); + _localNonce = new DC(32); + for (var i = 0; i < 32; i++) _localNonce[i] = r.nextInt(255); + } - Future reconnect() async - { - if (await connect()) - { - var bag = AsyncBag(); + int processPacket( + DC msg, int offset, int ends, NetworkBuffer data, int chunkId) { + var packet = new IIPPacket(); - for(var i = 0; i < _resources.keys.length; i++) - { - var index = _resources.keys.elementAt(i); - // print("Re $i ${_resources[index].instance.template.className}"); - bag.add(fetch(index)); + if (_ready) { + var rt = packet.parse(msg, offset, ends); + + if (rt <= 0) { + // print("hold"); + var size = ends - offset; + data.holdFor(msg, offset, size, size - rt); + return ends; + } else { + //print("CMD ${packet.command} ${offset} ${ends}"); + + offset += rt; + + if (packet.command == IIPPacketCommand.Event) { + switch (packet.event) { + case IIPPacketEvent.ResourceReassigned: + iipEventResourceReassigned( + packet.resourceId, packet.newResourceId); + break; + case IIPPacketEvent.ResourceDestroyed: + iipEventResourceDestroyed(packet.resourceId); + break; + case IIPPacketEvent.PropertyUpdated: + iipEventPropertyUpdated( + packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketEvent.EventOccurred: + iipEventEventOccurred( + packet.resourceId, packet.methodIndex, packet.content); + break; + + case IIPPacketEvent.ChildAdded: + iipEventChildAdded(packet.resourceId, packet.childId); + break; + case IIPPacketEvent.ChildRemoved: + iipEventChildRemoved(packet.resourceId, packet.childId); + break; + case IIPPacketEvent.Renamed: + iipEventRenamed(packet.resourceId, packet.content); + break; + case IIPPacketEvent.AttributesUpdated: + iipEventAttributesUpdated(packet.resourceId, packet.content); + break; } + } else if (packet.command == IIPPacketCommand.Request) { + switch (packet.action) { + // Manage + case IIPPacketAction.AttachResource: + iipRequestAttachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ReattachResource: + iipRequestReattachResource( + packet.callbackId, packet.resourceId, packet.resourceAge); + break; + case IIPPacketAction.DetachResource: + iipRequestDetachResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.CreateResource: + iipRequestCreateResource(packet.callbackId, packet.storeId, + packet.resourceId, packet.content); + break; + case IIPPacketAction.DeleteResource: + iipRequestDeleteResource(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.AddChild: + iipRequestAddChild( + packet.callbackId, packet.resourceId, packet.childId); + break; + case IIPPacketAction.RemoveChild: + iipRequestRemoveChild( + packet.callbackId, packet.resourceId, packet.childId); + break; + case IIPPacketAction.RenameResource: + iipRequestRenameResource( + packet.callbackId, packet.resourceId, packet.content); + break; - bag.seal(); - await bag; + // Inquire + case IIPPacketAction.TemplateFromClassName: + iipRequestTemplateFromClassName( + packet.callbackId, packet.className); + break; + case IIPPacketAction.TemplateFromClassId: + iipRequestTemplateFromClassId(packet.callbackId, packet.classId); + break; + case IIPPacketAction.TemplateFromResourceId: + iipRequestTemplateFromResourceId( + packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.QueryLink: + iipRequestQueryResources(packet.callbackId, packet.resourceLink); + break; - return true; - } - - return false; - } + case IIPPacketAction.ResourceChildren: + iipRequestResourceChildren(packet.callbackId, packet.resourceId); + break; + case IIPPacketAction.ResourceParents: + iipRequestResourceParents(packet.callbackId, packet.resourceId); + break; - /// - /// KeyList to store user variables related to this connection. - /// - final KeyList variables = new KeyList(); + case IIPPacketAction.ResourceHistory: + iipRequestInquireResourceHistory(packet.callbackId, + packet.resourceId, packet.fromDate, packet.toDate); + break; - /// - /// IResource interface. - /// - Instance instance; + case IIPPacketAction.LinkTemplates: + iipRequestLinkTemplates(packet.callbackId, packet.resourceLink); + break; - /// - /// Assign a socket to the connection. - /// - /// Any socket that implements ISocket. - assign(ISocket socket) - { - super.assign(socket); + // Invoke + case IIPPacketAction.InvokeFunctionArrayArguments: + iipRequestInvokeFunctionArrayArguments(packet.callbackId, + packet.resourceId, packet.methodIndex, packet.content); + break; - session.remoteAuthentication.source.attributes[SourceAttributeType.IPv4] = socket.remoteEndPoint.address; - session.remoteAuthentication.source.attributes[SourceAttributeType.Port] = socket.remoteEndPoint.port; - session.localAuthentication.source.attributes[SourceAttributeType.IPv4] = socket.localEndPoint.address; - session.localAuthentication.source.attributes[SourceAttributeType.Port] = socket.localEndPoint.port; - - if (session.localAuthentication.type == AuthenticationType.Client) - { - // declare (Credentials -> No Auth, No Enctypt) - - var un = DC.stringToBytes(session.localAuthentication.username); - var dmn = DC.stringToBytes(session.localAuthentication.domain);// domain); - - if (socket.state == SocketState.Established) - { - sendParams() - .addUint8(0x60) - .addUint8(dmn.length) - .addDC(dmn) - .addDC(_localNonce) - .addUint8(un.length) - .addDC(un) - .done(); - } - else - { - socket.on("connect", () - { // declare (Credentials -> No Auth, No Enctypt) - sendParams() - .addUint8(0x60) - .addUint8(dmn.length) - .addDC(dmn) - .addDC(_localNonce) - .addUint8(un.length) - .addDC(un) - .done(); - }); - } - } - } - - - /// - /// Create a new distributed connection. - /// - /// Socket to transfer data through. - /// Working domain. - /// Username. - /// Password. - DistributedConnection.connect(ISocket socket, String domain, String username, String password) - { - _session = new Session(new ClientAuthentication() - , new HostAuthentication()); - - _session.localAuthentication.method = AuthenticationMethod.Credentials; - _session.localAuthentication.domain = domain; - _session.localAuthentication.username = username; - - _localPasswordOrToken = DC.stringToBytes(password); - - init(); - - assign(socket); - } - - DistributedConnection.connectWithToken(ISocket socket, String domain, int tokenIndex, String token) - { - _session = new Session(new ClientAuthentication() - , new HostAuthentication()); - - _session.localAuthentication.method = AuthenticationMethod.Token; - _session.localAuthentication.domain = domain; - _session.localAuthentication.tokenIndex = tokenIndex; - - _localPasswordOrToken = DC.stringToBytes(token); - - init(); - - assign(socket); - } - - - /// - /// Create a new instance of a distributed connection - /// - DistributedConnection() - { - //myId = Global.GenerateCode(12); - // localParams.Host = DistributedParameters.HostType.Host; - _session = new Session(new HostAuthentication(), new ClientAuthentication()); - init(); - } - - - - String link(IResource resource) - { - if (resource is DistributedResource) - { - var r = resource as DistributedResource; - if (r.instance.store == this) - return this.instance.name + "/" + r.id.toString(); - } - - return null; - } - - - void init() - { - _queue.then((x) - { - if (x.type == DistributedResourceQueueItemType.Event) - x.resource.emitEventByIndex(x.index, x.value); - else - x.resource.updatePropertyByIndex(x.index, x.value); - }); - - var r = new Random(); - _localNonce = new DC(32); - for(var i = 0; i < 32; i++) - _localNonce[i] = r.nextInt(255); - } - - - - int processPacket(DC msg, int offset, int ends, NetworkBuffer data, int chunkId) - { - var packet = new IIPPacket(); - - if (_ready) - { - var rt = packet.parse(msg, offset, ends); - - if (rt <= 0) - { - // print("hold"); - var size = ends - offset; - data.holdFor(msg, offset, size, size - rt); - return ends; - } - else - { - //print("CMD ${packet.command} ${offset} ${ends}"); - - offset += rt; - - - if (packet.command == IIPPacketCommand.Event) - { - switch (packet.event) - { - case IIPPacketEvent.ResourceReassigned: - iipEventResourceReassigned(packet.resourceId, packet.newResourceId); - break; - case IIPPacketEvent.ResourceDestroyed: - iipEventResourceDestroyed(packet.resourceId); - break; - case IIPPacketEvent.PropertyUpdated: - iipEventPropertyUpdated(packet.resourceId, packet.methodIndex, packet.content); - break; - case IIPPacketEvent.EventOccurred: - iipEventEventOccurred(packet.resourceId, packet.methodIndex, packet.content); - break; - - case IIPPacketEvent.ChildAdded: - iipEventChildAdded(packet.resourceId, packet.childId); - break; - case IIPPacketEvent.ChildRemoved: - iipEventChildRemoved(packet.resourceId, packet.childId); - break; - case IIPPacketEvent.Renamed: - iipEventRenamed(packet.resourceId, packet.content); - break; - case IIPPacketEvent.AttributesUpdated: - iipEventAttributesUpdated(packet.resourceId, packet.content); - break; - } - } - else if (packet.command == IIPPacketCommand.Request) - { - switch (packet.action) - { - // Manage - case IIPPacketAction.AttachResource: - iipRequestAttachResource(packet.callbackId, packet.resourceId); - break; - case IIPPacketAction.ReattachResource: - iipRequestReattachResource(packet.callbackId, packet.resourceId, packet.resourceAge); - break; - case IIPPacketAction.DetachResource: - iipRequestDetachResource(packet.callbackId, packet.resourceId); - break; - case IIPPacketAction.CreateResource: - iipRequestCreateResource(packet.callbackId, packet.storeId, packet.resourceId, packet.content); - break; - case IIPPacketAction.DeleteResource: - iipRequestDeleteResource(packet.callbackId, packet.resourceId); - break; - case IIPPacketAction.AddChild: - iipRequestAddChild(packet.callbackId, packet.resourceId, packet.childId); - break; - case IIPPacketAction.RemoveChild: - iipRequestRemoveChild(packet.callbackId, packet.resourceId, packet.childId); - break; - case IIPPacketAction.RenameResource: - iipRequestRenameResource(packet.callbackId, packet.resourceId, packet.content); - break; - - // Inquire - case IIPPacketAction.TemplateFromClassName: - iipRequestTemplateFromClassName(packet.callbackId, packet.className); - break; - case IIPPacketAction.TemplateFromClassId: - iipRequestTemplateFromClassId(packet.callbackId, packet.classId); - break; - case IIPPacketAction.TemplateFromResourceId: - iipRequestTemplateFromResourceId(packet.callbackId, packet.resourceId); - break; - case IIPPacketAction.QueryLink: - iipRequestQueryResources(packet.callbackId, packet.resourceLink); - break; - - case IIPPacketAction.ResourceChildren: - iipRequestResourceChildren(packet.callbackId, packet.resourceId); - break; - case IIPPacketAction.ResourceParents: - iipRequestResourceParents(packet.callbackId, packet.resourceId); - break; - - case IIPPacketAction.ResourceHistory: - iipRequestInquireResourceHistory(packet.callbackId, packet.resourceId, - packet.fromDate, packet.toDate); - break; - - // Invoke - case IIPPacketAction.InvokeFunctionArrayArguments: - iipRequestInvokeFunctionArrayArguments(packet.callbackId, packet.resourceId, - packet.methodIndex, packet.content); - break; - - case IIPPacketAction.InvokeFunctionNamedArguments: - iipRequestInvokeFunctionNamedArguments(packet.callbackId, packet.resourceId, - packet.methodIndex, packet.content); - break; + case IIPPacketAction.InvokeFunctionNamedArguments: + iipRequestInvokeFunctionNamedArguments(packet.callbackId, + packet.resourceId, packet.methodIndex, packet.content); + break; + case IIPPacketAction.Listen: + iipRequestListen( + packet.callbackId, packet.resourceId, packet.methodIndex); + break; + case IIPPacketAction.Unlisten: + iipRequestUnlisten( + packet.callbackId, packet.resourceId, packet.methodIndex); + break; +/* case IIPPacketAction.GetProperty: iipRequestGetProperty(packet.callbackId, packet.resourceId, packet.methodIndex); break; @@ -566,149 +595,153 @@ class DistributedConnection extends NetworkConnection with IStore iipRequestGetPropertyIfModifiedSince(packet.callbackId, packet.resourceId, packet.methodIndex, packet.resourceAge); break; - case IIPPacketAction.SetProperty: - iipRequestSetProperty(packet.callbackId, packet.resourceId, packet.methodIndex, packet.content); - break; +*/ + case IIPPacketAction.SetProperty: + iipRequestSetProperty(packet.callbackId, packet.resourceId, + packet.methodIndex, packet.content); + break; - // Attribute - case IIPPacketAction.GetAllAttributes: - iipRequestGetAttributes(packet.callbackId, packet.resourceId, packet.content, true); - break; - case IIPPacketAction.UpdateAllAttributes: - iipRequestUpdateAttributes(packet.callbackId, packet.resourceId, packet.content, true); - break; - case IIPPacketAction.ClearAllAttributes: - iipRequestClearAttributes(packet.callbackId, packet.resourceId, packet.content, true); - break; - case IIPPacketAction.GetAttributes: - iipRequestGetAttributes(packet.callbackId, packet.resourceId, packet.content, false); - break; - case IIPPacketAction.UpdateAttributes: - iipRequestUpdateAttributes(packet.callbackId, packet.resourceId, packet.content, false); - break; - case IIPPacketAction.ClearAttributes: - iipRequestClearAttributes(packet.callbackId, packet.resourceId, packet.content, false); - break; - } - } - else if (packet.command == IIPPacketCommand.Reply) - { - switch (packet.action) - { - // Manage - case IIPPacketAction.AttachResource: - iipReply(packet.callbackId, [packet.classId, packet.resourceAge, packet.resourceLink, packet.content]); - break; + // Attribute + case IIPPacketAction.GetAllAttributes: + iipRequestGetAttributes( + packet.callbackId, packet.resourceId, packet.content, true); + break; + case IIPPacketAction.UpdateAllAttributes: + iipRequestUpdateAttributes( + packet.callbackId, packet.resourceId, packet.content, true); + break; + case IIPPacketAction.ClearAllAttributes: + iipRequestClearAttributes( + packet.callbackId, packet.resourceId, packet.content, true); + break; + case IIPPacketAction.GetAttributes: + iipRequestGetAttributes( + packet.callbackId, packet.resourceId, packet.content, false); + break; + case IIPPacketAction.UpdateAttributes: + iipRequestUpdateAttributes( + packet.callbackId, packet.resourceId, packet.content, false); + break; + case IIPPacketAction.ClearAttributes: + iipRequestClearAttributes( + packet.callbackId, packet.resourceId, packet.content, false); + break; + } + } else if (packet.command == IIPPacketCommand.Reply) { + switch (packet.action) { + // Manage + case IIPPacketAction.AttachResource: + iipReply(packet.callbackId, [ + packet.classId, + packet.resourceAge, + packet.resourceLink, + packet.content + ]); + break; - case IIPPacketAction.ReattachResource: - iipReply(packet.callbackId, [packet.resourceAge, packet.content]); + case IIPPacketAction.ReattachResource: + iipReply(packet.callbackId, [packet.resourceAge, packet.content]); - break; - case IIPPacketAction.DetachResource: - iipReply (packet.callbackId); - break; + break; + case IIPPacketAction.DetachResource: + iipReply(packet.callbackId); + break; - case IIPPacketAction.CreateResource: - iipReply(packet.callbackId, [packet.resourceId]); - break; + case IIPPacketAction.CreateResource: + iipReply(packet.callbackId, [packet.resourceId]); + break; - case IIPPacketAction.DeleteResource: - case IIPPacketAction.AddChild: - case IIPPacketAction.RemoveChild: - case IIPPacketAction.RenameResource: - iipReply(packet.callbackId); - break; + case IIPPacketAction.DeleteResource: + case IIPPacketAction.AddChild: + case IIPPacketAction.RemoveChild: + case IIPPacketAction.RenameResource: + iipReply(packet.callbackId); + break; - // Inquire + // Inquire - case IIPPacketAction.TemplateFromClassName: - case IIPPacketAction.TemplateFromClassId: - case IIPPacketAction.TemplateFromResourceId: - iipReply(packet.callbackId, [ResourceTemplate.parse(packet.content)]); - break; + case IIPPacketAction.TemplateFromClassName: + case IIPPacketAction.TemplateFromClassId: + case IIPPacketAction.TemplateFromResourceId: + iipReply( + packet.callbackId, [TypeTemplate.parse(packet.content)]); + break; - case IIPPacketAction.QueryLink: - case IIPPacketAction.ResourceChildren: - case IIPPacketAction.ResourceParents: - case IIPPacketAction.ResourceHistory: - iipReply(packet.callbackId, [packet.content]); - break; + case IIPPacketAction.QueryLink: + case IIPPacketAction.ResourceChildren: + case IIPPacketAction.ResourceParents: + case IIPPacketAction.ResourceHistory: + case IIPPacketAction.LinkTemplates: + iipReply(packet.callbackId, [packet.content]); + break; - // Invoke - case IIPPacketAction.InvokeFunctionArrayArguments: - case IIPPacketAction.InvokeFunctionNamedArguments: - iipReplyInvoke(packet.callbackId, packet.content); - break; + // Invoke + case IIPPacketAction.InvokeFunctionArrayArguments: + case IIPPacketAction.InvokeFunctionNamedArguments: + iipReplyInvoke(packet.callbackId, packet.content); + break; - case IIPPacketAction.GetProperty: - iipReply(packet.callbackId, [packet.content]); - break; + // case IIPPacketAction.GetProperty: + // iipReply(packet.callbackId, [packet.content]); + // break; - case IIPPacketAction.GetPropertyIfModified: - iipReply(packet.callbackId, [packet.content]); - break; - case IIPPacketAction.SetProperty: - iipReply(packet.callbackId); - break; + // case IIPPacketAction.GetPropertyIfModified: + // iipReply(packet.callbackId, [packet.content]); + // break; - // Attribute - case IIPPacketAction.GetAllAttributes: - case IIPPacketAction.GetAttributes: - iipReply(packet.callbackId, [packet.content]); - break; + case IIPPacketAction.Listen: + case IIPPacketAction.Unlisten: + case IIPPacketAction.SetProperty: + iipReply(packet.callbackId); + break; - case IIPPacketAction.UpdateAllAttributes: - case IIPPacketAction.UpdateAttributes: - case IIPPacketAction.ClearAllAttributes: - case IIPPacketAction.ClearAttributes: - iipReply(packet.callbackId); - break; + // Attribute + case IIPPacketAction.GetAllAttributes: + case IIPPacketAction.GetAttributes: + iipReply(packet.callbackId, [packet.content]); + break; - } - - } - else if (packet.command == IIPPacketCommand.Report) - { - switch (packet.report) - { - case IIPPacketReport.ManagementError: - iipReportError(packet.callbackId, ErrorType.Management, packet.errorCode, null); - break; - case IIPPacketReport.ExecutionError: - iipReportError(packet.callbackId, ErrorType.Exception, packet.errorCode, packet.errorMessage); - break; - case IIPPacketReport.ProgressReport: - iipReportProgress(packet.callbackId, ProgressType.Execution, packet.progressValue, packet.progressMax); - break; - case IIPPacketReport.ChunkStream: - iipReportChunk(packet.callbackId, packet.content); - break; - } - } - } + case IIPPacketAction.UpdateAllAttributes: + case IIPPacketAction.UpdateAttributes: + case IIPPacketAction.ClearAllAttributes: + case IIPPacketAction.ClearAttributes: + iipReply(packet.callbackId); + break; + } + } else if (packet.command == IIPPacketCommand.Report) { + switch (packet.report) { + case IIPPacketReport.ManagementError: + iipReportError(packet.callbackId, ErrorType.Management, + packet.errorCode, null); + break; + case IIPPacketReport.ExecutionError: + iipReportError(packet.callbackId, ErrorType.Exception, + packet.errorCode, packet.errorMessage); + break; + case IIPPacketReport.ProgressReport: + iipReportProgress(packet.callbackId, ProgressType.Execution, + packet.progressValue, packet.progressMax); + break; + case IIPPacketReport.ChunkStream: + iipReportChunk(packet.callbackId, packet.content); + break; + } } + } + } else { + var rt = _authPacket.parse(msg, offset, ends); - else - { - var rt = _authPacket.parse(msg, offset, ends); + if (rt <= 0) { + data.holdForNeeded(msg, ends - rt); + return ends; + } else { + offset += rt; - if (rt <= 0) - { - data.holdForNeeded(msg, ends -rt); - return ends; - } - else - { - offset += rt; - - if (session.localAuthentication.type == AuthenticationType.Host) - { - if (_authPacket.command == IIPAuthPacketCommand.Declare) - { - if (_authPacket.remoteMethod == AuthenticationMethod.Credentials && _authPacket.localMethod == AuthenticationMethod.None) - { - - /* + if (session.localAuthentication.type == AuthenticationType.Host) { + if (_authPacket.command == IIPAuthPacketCommand.Declare) { + if (_authPacket.remoteMethod == AuthenticationMethod.Credentials && + _authPacket.localMethod == AuthenticationMethod.None) { + /* server.membership.userExists(_authPacket.remoteUsername, _authPacket.domain).then((x) { if (x) @@ -728,15 +761,12 @@ class DistributedConnection extends NetworkConnection with IStore }); */ - } - } - else if (_authPacket.command == IIPAuthPacketCommand.Action) - { - if (_authPacket.action == IIPAuthPacketAction.AuthenticateHash) - { - var remoteHash = _authPacket.hash; + } + } else if (_authPacket.command == IIPAuthPacketCommand.Action) { + if (_authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + var remoteHash = _authPacket.hash; - /* + /* server.membership.getPassword(_session.remoteAuthentication.username, _session.remoteAuthentication.domain).then((pw) { @@ -767,377 +797,351 @@ class DistributedConnection extends NetworkConnection with IStore } }); */ - } - else if (_authPacket.action == IIPAuthPacketAction.NewConnection) - { - if (_readyToEstablish) - { - var r = new Random(); - session.id = new DC(32); - for(var i = 0; i < 32; i++) - session.id[i] = r.nextInt(255); + } else if (_authPacket.action == + IIPAuthPacketAction.NewConnection) { + if (_readyToEstablish) { + var r = new Random(); + session.id = new DC(32); + for (var i = 0; i < 32; i++) session.id[i] = r.nextInt(255); + sendParams().addUint8(0x28).addDC(session.id).done(); - sendParams() - .addUint8(0x28) - .addDC(session.id) - .done(); + _ready = true; - _ready = true; + _openReply.trigger(true); + _openReply = null; + emitArgs("ready", []); + //OnReady?.Invoke(this); + // server.membership.login(session); - _openReply.trigger(true); - _openReply = null; - emitArgs("ready", []); - //OnReady?.Invoke(this); - // server.membership.login(session); - - } - } - } - } - else if (_session.localAuthentication.type == AuthenticationType.Client) - { - if (_authPacket.command == IIPAuthPacketCommand.Acknowledge) - { - _remoteNonce = _authPacket.remoteNonce; - - // send our hash - var localHash = SHA256.compute(new BinaryList() - .addDC(_localPasswordOrToken) - .addDC(_localNonce) - .addDC(_remoteNonce) - .toDC()); - - sendParams() - .addUint8(0) - .addDC(localHash) - .done(); - - //SendParams((byte)0, localHash); - } - else if (_authPacket.command == IIPAuthPacketCommand.Action) - { - if (_authPacket.action == IIPAuthPacketAction.AuthenticateHash) - { - // check if the server knows my password - var remoteHash = SHA256.compute(new BinaryList() - .addDC(_remoteNonce) - .addDC(_localNonce) - .addDC(_localPasswordOrToken) - .toDC()); - - - if (remoteHash.sequenceEqual(_authPacket.hash)) - { - // send establish request - sendParams() - .addUint8(0x20) - .addUint16(0) - .done(); - } - else - { - sendParams() - .addUint8(0xc0) - .addUint8(ExceptionCode.ChallengeFailed.index) - .addUint16(16) - .addString("Challenge Failed") - .done(); - - //SendParams((byte)0xc0, 1, 5, DC.ToBytes("Error")); - } - } - else if (_authPacket.action == IIPAuthPacketAction.ConnectionEstablished) - { - session.id = _authPacket.sessionId; - - _ready = true; - - _openReply.trigger(true); - _openReply = null; - emitArgs("ready", []); - - //OnReady?.Invoke(this); - - } - } - else if (_authPacket.command == IIPAuthPacketCommand.Error) - { - var ex = AsyncException(ErrorType.Management, _authPacket.errorCode, _authPacket.errorMessage); - _openReply.triggerError(ex); - _openReply = null; - emitArgs("error", [ex]); - //OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); - close(); - } - } + } } + } + } else if (_session.localAuthentication.type == + AuthenticationType.Client) { + if (_authPacket.command == IIPAuthPacketCommand.Acknowledge) { + if (_authPacket.remoteMethod == AuthenticationMethod.None) { + sendParams().addUint8(0x20).addUint16(0).done(); + } else if (_authPacket.remoteMethod == + AuthenticationMethod.Credentials || + _authPacket.remoteMethod == AuthenticationMethod.Token) { + _remoteNonce = _authPacket.remoteNonce; + + // send our hash + var localHash = SHA256.compute(new BinaryList() + .addDC(_localPasswordOrToken) + .addDC(_localNonce) + .addDC(_remoteNonce) + .toDC()); + + sendParams().addUint8(0).addDC(localHash).done(); + } + //SendParams((byte)0, localHash); + } else if (_authPacket.command == IIPAuthPacketCommand.Action) { + if (_authPacket.action == IIPAuthPacketAction.AuthenticateHash) { + // check if the server knows my password + var remoteHash = SHA256.compute(new BinaryList() + .addDC(_remoteNonce) + .addDC(_localNonce) + .addDC(_localPasswordOrToken) + .toDC()); + + if (remoteHash.sequenceEqual(_authPacket.hash)) { + // send establish request + sendParams().addUint8(0x20).addUint16(0).done(); + } else { + sendParams() + .addUint8(0xc0) + .addUint8(ExceptionCode.ChallengeFailed.index) + .addUint16(16) + .addString("Challenge Failed") + .done(); + + //SendParams((byte)0xc0, 1, 5, DC.ToBytes("Error")); + } + } else if (_authPacket.action == + IIPAuthPacketAction.ConnectionEstablished) { + session.id = _authPacket.sessionId; + + _ready = true; + + _openReply.trigger(true); + _openReply = null; + emitArgs("ready", []); + + //OnReady?.Invoke(this); + + } + } else if (_authPacket.command == IIPAuthPacketCommand.Error) { + var ex = AsyncException(ErrorType.Management, _authPacket.errorCode, + _authPacket.errorMessage); + _openReply.triggerError(ex); + _openReply = null; + emitArgs("error", [ex]); + //OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); + close(); + } } - - return offset; - - //if (offset < ends) - // processPacket(msg, offset, ends, data, chunkId); + } } - @override - void dataReceived(NetworkBuffer data) - { - // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); - var msg = data.read(); - int offset = 0; - int ends = msg.length; + return offset; - var packs = new List(); + //if (offset < ends) + // processPacket(msg, offset, ends, data, chunkId); + } - var chunkId = (new Random()).nextInt(1000000); + @override + void dataReceived(NetworkBuffer data) { + // Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString()); + var msg = data.read(); + int offset = 0; + int ends = msg.length; - + //List packs = []; - while (offset < ends) - { - offset = processPacket(msg, offset, ends, data, chunkId); + var chunkId = (new Random()).nextInt(1000000); + + while (offset < ends) { + offset = processPacket(msg, offset, ends, data, chunkId); + } + } + + /// + /// Resource interface + /// + /// Resource trigger. + /// + //AsyncReply trigger(ResourceTrigger trigger) + //{ + // return new AsyncReply(); + //} + + /// + /// Store interface. + /// + /// Resource. + /// + AsyncReply put(IResource resource) { + if (Codec.isLocalResource(resource, this)) + _resources.add((resource as DistributedResource).id, resource); + // else .. put it in the server.... + return AsyncReply.ready(true); + } + + bool record(IResource resource, String propertyName, value, int age, + DateTime dateTime) { + // nothing to do + return true; + } + + bool modify(IResource resource, String propertyName, value, int age, + DateTime dateTime) { + // nothing to do + return true; + } + + /// + /// Send IIP request. + /// + /// Packet action. + /// Arguments to send. + /// + SendList sendRequest(int action) { + var reply = new AsyncReply>(); + var c = _callbackCounter++; // avoid thread racing + _requests.add(c, reply); + + return sendParams(reply).addUint8(0x40 | action).addUint32(c); + } + + //int _maxcallerid = 0; + + SendList sendReply(int action, int callbackId) { + return sendParams().addUint8((0x80 | action)).addUint32(callbackId); + } + + SendList sendEvent(int evt) { + return sendParams().addUint8((evt)); + } + + AsyncReply sendListenRequest(int instanceId, int index) { + var reply = new AsyncReply(); + var c = _callbackCounter++; + _requests.add(c, reply); + + sendParams() + .addUint8(0x40 | IIPPacketAction.Listen) + .addUint32(c) + .addUint32(instanceId) + .addUint8(index) + .done(); + return reply; + } + + AsyncReply sendUnlistenRequest(int instanceId, int index) { + var reply = new AsyncReply(); + var c = _callbackCounter++; + _requests.add(c, reply); + + sendParams() + .addUint8(0x40 | IIPPacketAction.Unlisten) + .addUint32(c) + .addUint32(instanceId) + .addUint8(index) + .done(); + return reply; + } + + AsyncReply sendInvokeByArrayArguments( + int instanceId, int index, List parameters) { + var pb = Codec.composeVarArray(parameters, this, true); + + var reply = new AsyncReply(); + var c = _callbackCounter++; + _requests.add(c, reply); + + sendParams() + .addUint8(0x40 | IIPPacketAction.InvokeFunctionArrayArguments) + .addUint32(c) + .addUint32(instanceId) + .addUint8(index) + .addDC(pb) + .done(); + return reply; + } + + AsyncReply sendDetachRequest(int instanceId) { + try { + return sendRequest(IIPPacketAction.DetachResource) + .addUint32(instanceId) + .done(); + } catch (ex) { + return null; + } + } + + AsyncReply sendInvokeByNamedArguments( + int instanceId, int index, Structure parameters) { + var pb = Codec.composeStructure(parameters, this, true, true, true); + + var reply = new AsyncReply(); + var c = _callbackCounter++; + _requests.add(c, reply); + + sendParams() + .addUint8(0x40 | IIPPacketAction.InvokeFunctionNamedArguments) + .addUint32(c) + .addUint32(instanceId) + .addUint8(index) + .addDC(pb) + .done(); + return reply; + } + + void sendError(ErrorType type, int callbackId, int errorCode, + [String errorMessage = ""]) { + var msg = DC.stringToBytes(errorMessage); + if (type == ErrorType.Management) + sendParams() + .addUint8(0xC0 | IIPPacketReport.ManagementError) + .addUint32(callbackId) + .addUint16(errorCode) + .done(); + else if (type == ErrorType.Exception) + sendParams() + .addUint8(0xC0 | IIPPacketReport.ExecutionError) + .addUint32(callbackId) + .addUint16(errorCode) + .addUint16(msg.length) + .addDC(msg) + .done(); + } + + void sendProgress(int callbackId, int value, int max) { + sendParams() + .addUint8(0xC0 | IIPPacketReport.ProgressReport) + .addUint32(callbackId) + .addInt32(value) + .addInt32(max) + .done(); + //SendParams(, callbackId, value, max); + } + + void sendChunk(int callbackId, dynamic chunk) { + var c = Codec.compose(chunk, this, true); + sendParams() + .addUint8(0xC0 | IIPPacketReport.ChunkStream) + .addUint32(callbackId) + .addDC(c) + .done(); + } + + void iipReply(int callbackId, [List results = null]) { + var req = _requests.take(callbackId); + req?.trigger(results); + } + + void iipReplyInvoke(int callbackId, DC result) { + var req = _requests.take(callbackId); + + Codec.parse(result, 0, this).then((rt) { + req?.trigger(rt); + }); + } + + void iipReportError( + int callbackId, ErrorType errorType, int errorCode, String errorMessage) { + var req = _requests.take(callbackId); + req?.triggerError(new AsyncException(errorType, errorCode, errorMessage)); + } + + void iipReportProgress( + int callbackId, ProgressType type, int value, int max) { + var req = _requests[callbackId]; + req?.triggerProgress(type, value, max); + } + + void iipReportChunk(int callbackId, DC data) { + if (_requests.containsKey(callbackId)) { + var req = _requests[callbackId]; + Codec.parse(data, 0, this).then((x) { + req.triggerChunk(x); + }); + } + } + + void iipEventResourceReassigned(int resourceId, int newResourceId) {} + + void iipEventResourceDestroyed(int resourceId) { + if (_resources.contains(resourceId)) { + var r = _resources[resourceId]; + _resources.remove(resourceId); + r.destroy(); + } + } + + void iipEventPropertyUpdated(int resourceId, int index, DC content) { + fetch(resourceId).then((r) { + var item = new AsyncReply(); + _queue.add(item); + + Codec.parse(content, 0, this).then((arguments) { + var pt = r.instance.template.getPropertyTemplateByIndex(index); + if (pt != null) { + item.trigger(new DistributedResourceQueueItem( + r as DistributedResource, + DistributedResourceQueueItemType.Propery, + arguments, + index)); + } else { + // ft found, fi not found, this should never happen + _queue.remove(item); } + }); + }); - } - - /// - /// Resource interface - /// - /// Resource trigger. - /// - //AsyncReply trigger(ResourceTrigger trigger) - //{ - // return new AsyncReply(); - //} - - /// - /// Store interface. - /// - /// Resource. - /// - AsyncReply put(IResource resource) - { - if (Codec.isLocalResource(resource, this)) - _resources.add((resource as DistributedResource).id, resource); - // else .. put it in the server.... - return AsyncReply.ready(true); - } - - - - - - bool record(IResource resource, String propertyName, value, int age, DateTime dateTime) - { - // nothing to do - return true; - } - - bool modify(IResource resource, String propertyName, value, int age, DateTime dateTime) - { - // nothing to do - return true; - } - - - - - /// - /// Send IIP request. - /// - /// Packet action. - /// Arguments to send. - /// - SendList sendRequest(int action) - { - var reply = new AsyncReply>(); - var c = _callbackCounter++; // avoid thread racing - _requests.add(c, reply); - - return sendParams(reply).addUint8(0x40 | action).addUint32(c); - } - - //int _maxcallerid = 0; - - SendList sendReply(int action, int callbackId) - { - return sendParams().addUint8((0x80 | action)).addUint32(callbackId); - } - - SendList sendEvent(int evt) - { - return sendParams().addUint8((evt)); - } - - AsyncReply sendInvokeByArrayArguments(int instanceId, int index, List parameters) - { - var pb = Codec.composeVarArray(parameters, this, true); - - var reply = new AsyncReply(); - var c = _callbackCounter++; - _requests.add(c, reply); - - sendParams().addUint8(0x40 | IIPPacketAction.InvokeFunctionArrayArguments) - .addUint32(c) - .addUint32(instanceId) - .addUint8(index) - .addDC(pb) - .done(); - return reply; - } - - AsyncReply sendDetachRequest(int instanceId) - { - try - { - return sendRequest(IIPPacketAction.DetachResource).addUint32(instanceId).done(); - } - catch(ex) - { - return null; - } - } - - AsyncReply sendInvokeByNamedArguments(int instanceId, int index, Structure parameters) - { - var pb = Codec.composeStructure(parameters, this, true, true, true); - - var reply = new AsyncReply(); - var c = _callbackCounter++; - _requests.add(c, reply); - - sendParams().addUint8(0x40 | IIPPacketAction.InvokeFunctionNamedArguments) - .addUint32(c) - .addUint32(instanceId) - .addUint8(index) - .addDC(pb) - .done(); - return reply; - } - - - void sendError(ErrorType type, int callbackId, int errorCode, [String errorMessage = ""]) - { - var msg = DC.stringToBytes(errorMessage); - if (type == ErrorType.Management) - sendParams() - .addUint8(0xC0 | IIPPacketReport.ManagementError) - .addUint32(callbackId) - .addUint16(errorCode) - .done(); - else if (type == ErrorType.Exception) - sendParams() - .addUint8(0xC0 | IIPPacketReport.ExecutionError) - .addUint32(callbackId) - .addUint16(errorCode) - .addUint16(msg.length) - .addDC(msg) - .done(); - } - - void sendProgress(int callbackId, int value, int max) - { - sendParams() - .addUint8(0xC0 | IIPPacketReport.ProgressReport) - .addUint32(callbackId) - .addInt32(value) - .addInt32(max) - .done(); - //SendParams(, callbackId, value, max); - } - - void sendChunk(int callbackId, dynamic chunk) - { - var c = Codec.compose(chunk, this, true); - sendParams() - .addUint8(0xC0 | IIPPacketReport.ChunkStream) - .addUint32(callbackId) - .addDC(c) - .done(); - } - - void iipReply(int callbackId, [List results = null]) - { - var req = _requests.take(callbackId); - req?.trigger(results); - } - - void iipReplyInvoke(int callbackId, DC result) - { - var req = _requests.take(callbackId); - - Codec.parse(result, 0, this).then((rt) - { - req?.trigger(rt); - }); - } - - void iipReportError(int callbackId, ErrorType errorType, int errorCode, String errorMessage) - { - var req = _requests.take(callbackId); - req?.triggerError(new AsyncException(errorType, errorCode, errorMessage)); - } - - void iipReportProgress(int callbackId, ProgressType type, int value, int max) - { - var req = _requests[callbackId]; - req?.triggerProgress(type, value, max); - } - - void iipReportChunk(int callbackId, DC data) - { - if (_requests.containsKey(callbackId)) - { - var req = _requests[callbackId]; - Codec.parse(data, 0, this).then((x) - { - req.triggerChunk(x); - }); - } - } - - void iipEventResourceReassigned(int resourceId, int newResourceId) - { - - } - - void iipEventResourceDestroyed(int resourceId) - { - if (_resources.contains(resourceId)) - { - var r = _resources[resourceId]; - _resources.remove(resourceId); - r.destroy(); - } - } - - void iipEventPropertyUpdated(int resourceId, int index, DC content) - { - - fetch(resourceId).then((r) - { - var item = new AsyncReply(); - _queue.add(item); - - Codec.parse(content, 0, this).then((arguments) - { - var pt = r.instance.template.getPropertyTemplateByIndex(index); - if (pt != null) - { - item.trigger(new DistributedResourceQueueItem(r as DistributedResource, - DistributedResourceQueueItemType.Propery, - arguments, index)); - } - else - { // ft found, fi not found, this should never happen - _queue.remove(item); - } - }); - - }); - - /* + /* if (resources.Contains(resourceId)) { // push to the queue to gaurantee serialization @@ -1172,34 +1176,27 @@ class DistributedConnection extends NetworkConnection with IStore }); } */ - } + } + void iipEventEventOccurred(int resourceId, int index, DC content) { + fetch(resourceId).then((r) { + // push to the queue to gaurantee serialization + var item = new AsyncReply(); + _queue.add(item); - void iipEventEventOccurred(int resourceId, int index, DC content) - { - fetch(resourceId).then((r) - { - // push to the queue to gaurantee serialization - var item = new AsyncReply(); - _queue.add(item); + Codec.parse(content, 0, this).then((arguments) { + var et = r.instance.template.getEventTemplateByIndex(index); + if (et != null) { + item.trigger(new DistributedResourceQueueItem( + r, DistributedResourceQueueItemType.Event, arguments, index)); + } else { + // ft found, fi not found, this should never happen + _queue.remove(item); + } + }); + }); - Codec.parse(content, 0, this).then((arguments) - { - var et = r.instance.template.getEventTemplateByIndex(index); - if (et != null) - { - item.trigger(new DistributedResourceQueueItem(r, - DistributedResourceQueueItemType.Event, arguments, index)); - } - else - { // ft found, fi not found, this should never happen - _queue.remove(item); - } - - }); - }); - - /* + /* if (resources.Contains(resourceId)) { // push to the queue to gaurantee serialization @@ -1233,812 +1230,847 @@ class DistributedConnection extends NetworkConnection with IStore }); } */ + } + + void iipEventChildAdded(int resourceId, int childId) { + fetch(resourceId).then((parent) { + fetch(childId).then((child) { + parent.instance.children.add(child); + }); + }); + } + + void iipEventChildRemoved(int resourceId, int childId) { + fetch(resourceId).then((parent) { + fetch(childId).then((child) { + parent.instance.children.remove(child); + }); + }); + } + + void iipEventRenamed(int resourceId, DC name) { + fetch(resourceId).then((resource) { + resource.instance.attributes["name"] = name.getString(0, name.length); + }); + } + + void iipEventAttributesUpdated(int resourceId, DC attributes) { + fetch(resourceId).then((resource) { + var attrs = attributes.getStringArray(0, attributes.length); + + getAttributes(resource, attrs).then((s) { + resource.instance.setAttributes(s); + }); + }); + } + + void iipRequestAttachResource(int callback, int resourceId) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + if (r.instance.applicable(session, ActionType.Attach, null) == + Ruling.Denied) { + sendError(ErrorType.Management, callback, 6); + return; + } + + _unsubscrive(r); + + var link = DC.stringToBytes(r.instance.link); + + if (r is DistributedResource) { + // reply ok + sendReply(IIPPacketAction.AttachResource, callback) + .addGuid(r.instance.template.classId) + .addUint64(r.instance.age) + .addUint16(link.length) + .addDC(link) + .addDC(Codec.composePropertyValueArray( + (r as DistributedResource).serialize(), this, true)) + .done(); + } else { + // reply ok + sendReply(IIPPacketAction.AttachResource, callback) + .addGuid(r.instance.template.classId) + .addUint64(r.instance.age) + .addUint16(link.length) + .addDC(link) + .addDC(Codec.composePropertyValueArray( + r.instance.serialize(), this, true)) + .done(); + } + + _subscribe(r); + //r.instance.children.on("add", _children_OnAdd); + //r.instance.children.on("removed", _children_OnRemoved); + //r.instance.attributes.on("modified", _attributes_OnModified); + } else { + // reply failed + //SendParams(0x80, r.instance.id, r.instance.Age, r.instance.serialize(false, this)); + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + } + }); + } + + void _attributes_OnModified( + String key, oldValue, newValue, KeyList sender) { + if (key == "name") { + var instance = (sender.owner as Instance); + var name = DC.stringToBytes(newValue.toString()); + sendEvent(IIPPacketEvent.ChildRemoved) + .addUint32(instance.id) + .addUint16(name.length) + .addDC(name) + .done(); + } + } + + void _children_OnRemoved(Instance sender, IResource value) { + sendEvent(IIPPacketEvent.ChildRemoved) + .addUint32(sender.id) + .addUint32(value.instance.id) + .done(); + } + + void _children_OnAdd(Instance sender, IResource value) { + //if (sender.applicable(sender.Resource, this.session, ActionType.)) + sendEvent(IIPPacketEvent.ChildAdded) + .addUint32(sender.id) + .addUint32(value.instance.id) + .done(); + } + + void _subscribe(IResource resource) { + resource.instance.on("resourceEventOccurred", _instance_EventOccurred); + resource.instance.on("resourceModified", _instance_PropertyModified); + resource.instance.on("resourceDestroyed", _instance_ResourceDestroyed); + _subscriptions[resource] = new List(); + } + + void _unsubscrive(IResource resource) { + resource.instance.off("resourceEventOccurred", _instance_EventOccurred); + resource.instance.off("resourceModified", _instance_PropertyModified); + resource.instance.off("resourceDestroyed", _instance_ResourceDestroyed); + _subscriptions.remove(resource); + } + + void iipRequestReattachResource( + int callback, int resourceId, int resourceAge) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + _unsubscrive(r); + _subscribe(r); + + // reply ok + sendReply(IIPPacketAction.ReattachResource, callback) + .addUint64(r.instance.age) + .addDC(Codec.composePropertyValueArray( + r.instance.serialize(), this, true)) + .done(); + } else { + // reply failed + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + } + }); + } + + void iipRequestDetachResource(int callback, int resourceId) { + Warehouse.getById(resourceId).then((res) { + if (res != null) { + _unsubscrive(res); + // reply ok + sendReply(IIPPacketAction.DetachResource, callback).done(); + } else { + // reply failed + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + } + }); + } + + void iipRequestCreateResource( + int callback, int storeId, int parentId, DC content) { + Warehouse.getById(storeId).then((store) { + if (store == null) { + sendError( + ErrorType.Management, callback, ExceptionCode.StoreNotFound.index); + return; } - void iipEventChildAdded(int resourceId, int childId) - { - fetch(resourceId).then((parent) - { - fetch(childId).then((child) - { - parent.instance.children.add(child); - }); - }); + if (!(store is IStore)) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceIsNotStore.index); + return; } - void iipEventChildRemoved(int resourceId, int childId) - { - fetch(resourceId).then((parent) - { - fetch(childId).then((child) - { - parent.instance.children.remove(child); - }); - }); + // check security + if (store.instance.applicable(session, ActionType.CreateResource, null) != + Ruling.Allowed) { + sendError( + ErrorType.Management, callback, ExceptionCode.CreateDenied.index); + return; } - void iipEventRenamed(int resourceId, DC name) - { - fetch(resourceId).then((resource) - { - resource.instance.attributes["name"] = name.getString(0, name.length); - }); - } + Warehouse.getById(parentId).then((parent) { + // check security + if (parent != null) if (parent.instance + .applicable(session, ActionType.AddChild, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.AddChildDenied.index); + return; + } - void iipEventAttributesUpdated(int resourceId, DC attributes) - { - fetch(resourceId).then((resource) - { - var attrs = attributes.getStringArray(0, attributes.length); + int offset = 0; - getAttributes(resource, attrs).then((s) - { - resource.instance.setAttributes(s); - }); - }); - } + var className = content.getString(offset + 1, content[0]); + offset += 1 + content[0]; - void iipRequestAttachResource(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((res) - { - if (res != null) - { - if (res.instance.applicable(session, ActionType.Attach, null) == Ruling.Denied) - { - sendError(ErrorType.Management, callback, 6); - return; + var nameLength = content.getUint16(offset); + offset += 2; + var name = content.getString(offset, nameLength); + + var cl = content.getUint32(offset); + offset += 4; + + var type = null; //Type.getType(className); + + if (type == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ClassNotFound.index); + return; + } + + Codec.parseVarArray(content, offset, cl, this).then((parameters) { + offset += cl; + cl = content.getUint32(offset); + Codec.parseStructure(content, offset, cl, this).then((attributes) { + offset += cl; + cl = content.length - offset; + + Codec.parseStructure(content, offset, cl, this).then((values) { + var constructors = + []; //Type.GetType(className).GetTypeInfo().GetConstructors(); + + var matching = constructors.where((x) { + var ps = x.GetParameters(); + // if (ps.length > 0 && ps.length == parameters.length + 1) + // if (ps.Last().ParameterType == typeof(DistributedConnection)) + // return true; + + return ps.length == parameters.length; + }).toList(); + + var pi = matching[0].getParameters(); + + // cast arguments + List args = null; + + if (pi.length > 0) { + int argsCount = pi.length; + args = new List(pi.length); + + if (pi[pi.length - 1].parameterType.runtimeType == + DistributedConnection) { + args[--argsCount] = this; + } + + if (parameters != null) { + for (int i = 0; i < argsCount && i < parameters.length; i++) { + //args[i] = DC.CastConvert(parameters[i], pi[i].ParameterType); } - - var r = res as IResource; - - var link = DC.stringToBytes(r.instance.link); - - if (r is DistributedResource) - { - // reply ok - sendReply(IIPPacketAction.AttachResource, callback) - .addGuid(r.instance.template.classId) - .addUint64(r.instance.age) - .addUint16(link.length) - .addDC(link) - .addDC(Codec.composePropertyValueArray((r as DistributedResource).serialize(), this, true)) - .done(); - } - else - { - // reply ok - sendReply(IIPPacketAction.AttachResource, callback) - .addGuid(r.instance.template.classId) - .addUint64(r.instance.age) - .addUint16(link.length) - .addDC(link) - .addDC(Codec.composePropertyValueArray(r.instance.serialize(), this, true)) - .done(); - } - - r.instance.on("resourceEventOccurred", _instance_EventOccurred); - r.instance.on("resourceModified", _instance_PropertyModified); - r.instance.on("resourceDestroyed", _instance_ResourceDestroyed); - r.instance.children.on("add", _children_OnAdd); - r.instance.children.on("removed", _children_OnRemoved); - r.instance.attributes.on("modified", _attributes_OnModified); - - } - else - { - // reply failed - //SendParams(0x80, r.instance.id, r.instance.Age, r.instance.serialize(false, this)); - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); + } } + + // create the resource + IResource resource = + null; //Activator.CreateInstance(type, args) as IResource; + + Warehouse.put(name, resource, store as IStore, parent) + .then((ok) { + sendReply(IIPPacketAction.CreateResource, callback) + .addUint32(resource.instance.id) + .done(); + }).error((ex) { + // send some error + sendError(ErrorType.Management, callback, + ExceptionCode.AddToStoreFailed.index); + }); + }); }); + }); + }); + }); + } + + void iipRequestDeleteResource(int callback, int resourceId) { + Warehouse.getById(resourceId).then((r) { + if (r == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; } - void _attributes_OnModified(String key, oldValue, newValue, KeyList sender) - { - if (key == "name") - { - var instance = (sender.owner as Instance); - var name = DC.stringToBytes(newValue.toString()); - sendEvent(IIPPacketEvent.ChildRemoved) - .addUint32(instance.id) - .addUint16(name.length) - .addDC(name) + if (r.instance.store.instance + .applicable(session, ActionType.Delete, null) != + Ruling.Allowed) { + sendError( + ErrorType.Management, callback, ExceptionCode.DeleteDenied.index); + return; + } + + if (Warehouse.remove(r)) + sendReply(IIPPacketAction.DeleteResource, callback).done(); + //SendParams((byte)0x84, callback); + else + sendError( + ErrorType.Management, callback, ExceptionCode.DeleteFailed.index); + }); + } + + void iipRequestGetAttributes(int callback, int resourceId, DC attributes, + [bool all = false]) { + Warehouse.getById(resourceId).then((r) { + if (r == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + // if (!r.instance.store.instance.applicable(r, session, ActionType.InquireAttributes, null)) + if (r.instance.applicable(session, ActionType.InquireAttributes, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.ViewAttributeDenied.index); + return; + } + + List attrs = null; + + if (!all) attrs = attributes.getStringArray(0, attributes.length); + + var st = r.instance.getAttributes(attrs); + + if (st != null) + sendReply( + all + ? IIPPacketAction.GetAllAttributes + : IIPPacketAction.GetAttributes, + callback) + .addDC(Codec.composeStructure(st, this, true, true, true)) + .done(); + else + sendError(ErrorType.Management, callback, + ExceptionCode.GetAttributesFailed.index); + }); + } + + void iipRequestAddChild(int callback, int parentId, int childId) { + Warehouse.getById(parentId).then((parent) { + if (parent == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + Warehouse.getById(childId).then((child) { + if (child == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + if (parent.instance + .applicable(this.session, ActionType.AddChild, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.AddChildDenied.index); + return; + } + + if (child.instance + .applicable(this.session, ActionType.AddParent, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.AddParentDenied.index); + return; + } + + parent.instance.children.add(child); + + sendReply(IIPPacketAction.AddChild, callback).done(); + //child.instance.Parents + }); + }); + } + + void iipRequestRemoveChild(int callback, int parentId, int childId) { + Warehouse.getById(parentId).then((parent) { + if (parent == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + Warehouse.getById(childId).then((child) { + if (child == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + if (parent.instance + .applicable(this.session, ActionType.RemoveChild, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.AddChildDenied.index); + return; + } + + if (child.instance + .applicable(this.session, ActionType.RemoveParent, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.AddParentDenied.index); + return; + } + + parent.instance.children.remove(child); + + sendReply(IIPPacketAction.RemoveChild, callback).done(); + //child.instance.Parents + }); + }); + } + + void iipRequestRenameResource(int callback, int resourceId, DC name) { + Warehouse.getById(resourceId).then((resource) { + if (resource == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + if (resource.instance.applicable(this.session, ActionType.Rename, null) != + Ruling.Allowed) { + sendError( + ErrorType.Management, callback, ExceptionCode.RenameDenied.index); + return; + } + + resource.instance.name = name.getString(0, name.length); + sendReply(IIPPacketAction.RenameResource, callback).done(); + }); + } + + void iipRequestResourceChildren(int callback, int resourceId) { + Warehouse.getById(resourceId).then((resource) { + if (resource == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + sendReply(IIPPacketAction.ResourceChildren, callback) + .addDC(Codec.composeResourceArray( + resource.instance.children.toList(), this, true)) + .done(); + }); + } + + void iipRequestResourceParents(int callback, int resourceId) { + Warehouse.getById(resourceId).then((resource) { + if (resource == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + sendReply(IIPPacketAction.ResourceParents, callback) + .addDC(Codec.composeResourceArray( + resource.instance.parents.toList(), this, true)) + .done(); + }); + } + + void iipRequestClearAttributes(int callback, int resourceId, DC attributes, + [bool all = false]) { + Warehouse.getById(resourceId).then((r) { + if (r == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + if (r.instance.store.instance + .applicable(session, ActionType.UpdateAttributes, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.UpdateAttributeDenied.index); + return; + } + + List attrs = null; + + if (!all) attrs = attributes.getStringArray(0, attributes.length); + + if (r.instance.removeAttributes(attrs)) + sendReply( + all + ? IIPPacketAction.ClearAllAttributes + : IIPPacketAction.ClearAttributes, + callback) + .done(); + else + sendError(ErrorType.Management, callback, + ExceptionCode.UpdateAttributeFailed.index); + }); + } + + void iipRequestUpdateAttributes(int callback, int resourceId, DC attributes, + [bool clearAttributes = false]) { + Warehouse.getById(resourceId).then((r) { + if (r == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + return; + } + + if (r.instance.store.instance + .applicable(session, ActionType.UpdateAttributes, null) != + Ruling.Allowed) { + sendError(ErrorType.Management, callback, + ExceptionCode.UpdateAttributeDenied.index); + return; + } + + Codec.parseStructure(attributes, 0, attributes.length, this) + .then((attrs) { + if (r.instance.setAttributes(attrs, clearAttributes)) + sendReply( + clearAttributes + ? IIPPacketAction.ClearAllAttributes + : IIPPacketAction.ClearAttributes, + callback) + .done(); + else + sendError(ErrorType.Management, callback, + ExceptionCode.UpdateAttributeFailed.index); + }); + }); + } + + void iipRequestLinkTemplates(int callback, String resourceLink) { + var queryCallback = (List r) { + if (r == null) + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + else { + var list = r.where((x) => + x.instance.applicable(session, ActionType.ViewTemplate, null) != + Ruling.Denied); + + if (list.length == 0) + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + else { + // get all templates related to this resource + var msg = new BinaryList(); + + List templates = []; + + list.forEach((resource) { + templates.addAll( + TypeTemplate.getDependencies(resource.instance.template) + .where((x) => !templates.contains(x))); + }); + + templates.forEach((t) { + msg.addInt32(t.content.length).addDC(t.content); + }); + + // digggg + sendReply(IIPPacketAction.LinkTemplates, callback) + .addInt32(msg.length) + .addUint8Array(msg.toArray()) + .done(); + } + } + }; + + if (_server?.entryPoint != null) + _server.entryPoint.query(resourceLink, this).then(queryCallback); + else + Warehouse.query(resourceLink).then(queryCallback); + } + + void iipRequestTemplateFromClassName(int callback, String className) { + var t = Warehouse.getTemplateByClassName(className); + if (t != null) { + sendReply(IIPPacketAction.TemplateFromClassName, callback) + .addInt32(t.content.length) + .addDC(t.content) + .done(); + } else { + // reply failed + sendError( + ErrorType.Management, callback, ExceptionCode.TemplateNotFound.index); + } + } + + void iipRequestTemplateFromClassId(int callback, Guid classId) { + var t = Warehouse.getTemplateByClassId(classId); + if (t != null) + sendReply(IIPPacketAction.TemplateFromClassId, callback) + .addInt32(t.content.length) + .addDC(t.content) + .done(); + else { + // reply failed + sendError( + ErrorType.Management, callback, ExceptionCode.TemplateNotFound.index); + } + } + + void iipRequestTemplateFromResourceId(int callback, int resourceId) { + Warehouse.getById(resourceId).then((r) { + if (r != null) + sendReply(IIPPacketAction.TemplateFromResourceId, callback) + .addInt32(r.instance.template.content.length) + .addDC(r.instance.template.content) + .done(); + else { + // reply failed + sendError(ErrorType.Management, callback, + ExceptionCode.TemplateNotFound.index); + } + }); + } + + void iipRequestQueryResources(int callback, String resourceLink) { + Warehouse.query(resourceLink).then((r) { + if (r == null) { + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + } else { + var list = r + .where((x) => + x.instance.applicable(session, ActionType.Attach, null) != + Ruling.Denied) + .toList(); + + if (list.length == 0) + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); + else + sendReply(IIPPacketAction.QueryLink, callback) + .addDC(Codec.composeResourceArray(list, this, true)) + .done(); + } + }); + } + + void IIPRequestResourceAttribute(int callback, int resourceId) {} + + void iipRequestInvokeFunctionArrayArguments( + int callback, int resourceId, int index, DC content) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + Codec.parseVarArray(content, 0, content.length, this).then((arguments) { + var ft = r.instance.template.getFunctionTemplateByIndex(index); + if (ft != null) { + if (r is DistributedResource) { + var rt = (r as DistributedResource) + .invokeByArrayArguments(index, arguments); + if (rt != null) { + rt.then((res) { + sendReply(IIPPacketAction.InvokeFunctionArrayArguments, + callback) + .addDC(Codec.compose(res, this)) .done(); + }); + } else { + // function not found on a distributed object + } + } else { + var fi = null; //r.GetType().GetTypeInfo().GetMethod(ft.name); + + if (fi != null) { + } else { + // ft found, fi not found, this should never happen + } + } + } else { + // no function at this index } + }); + } else { + // no resource with this id } + }); + } - void _children_OnRemoved(Instance sender, IResource value) - { - sendEvent(IIPPacketEvent.ChildRemoved) - .addUint32(sender.id) - .addUint32(value.instance.id) - .done(); - } - - void _children_OnAdd(Instance sender, IResource value) - { - //if (sender.applicable(sender.Resource, this.session, ActionType.)) - sendEvent(IIPPacketEvent.ChildAdded) - .addUint32(sender.id) - .addUint32(value.instance.id) - .done(); - } - - void iipRequestReattachResource(int callback, int resourceId, int resourceAge) - { - Warehouse.getById(resourceId).then((res) - { - if (res != null) - { - var r = res as IResource; - r.instance.on("resourceEventOccurred", _instance_EventOccurred); - r.instance.on("resourceModified", _instance_PropertyModified); - r.instance.on("resourceDestroyed", _instance_ResourceDestroyed); - - // reply ok - sendReply(IIPPacketAction.ReattachResource, callback) - .addUint64(r.instance.age) - .addDC(Codec.composePropertyValueArray(r.instance.serialize(), this, true)) - .done(); - } - else - { - // reply failed - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - } - }); - } - - void iipRequestDetachResource(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((res) - { - if (res != null) - { - var r = res as IResource; - r.instance.off("resourceEventOccurred", _instance_EventOccurred); - r.instance.off("resourceModified", _instance_PropertyModified); - r.instance.off("resourceDestroyed", _instance_ResourceDestroyed); - // reply ok - sendReply(IIPPacketAction.DetachResource, callback).done(); - } - else - { - // reply failed - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - } - }); - } - - void iipRequestCreateResource(int callback, int storeId, int parentId, DC content) - { - - Warehouse.getById(storeId).then((store) - { - if (store == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.StoreNotFound.index); - return; - } - - if (!(store is IStore)) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceIsNotStore.index); - return; - } - - // check security - if (store.instance.applicable(session, ActionType.CreateResource, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.CreateDenied.index); - return; - } - - Warehouse.getById(parentId).then((parent) - { - - // check security - - if (parent != null) - if (parent.instance.applicable(session, ActionType.AddChild, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied.index); - return; - } - - int 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 = null;//Type.getType(className); - - if (type == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ClassNotFound.index); - return; - } - - Codec.parseVarArray(content, offset, cl, this).then((parameters) - { - offset += cl; - cl = content.getUint32(offset); - Codec.parseStructure(content, offset, cl, this).then((attributes) - { - offset += cl; - cl = content.length - offset; - - Codec.parseStructure(content, offset, cl, this).then((values) - { - - - var constructors = [];//Type.GetType(className).GetTypeInfo().GetConstructors(); - - var matching = constructors.where((x) - { - var ps = x.GetParameters(); - // if (ps.length > 0 && ps.length == parameters.length + 1) - // if (ps.Last().ParameterType == typeof(DistributedConnection)) - // return true; - - return ps.length == parameters.length; - } - ).toList(); - - var pi = matching[0].getParameters(); - - // cast arguments - List args = null; - - if (pi.length > 0) - { - int argsCount = pi.length; - args = new List(pi.length); - - if (pi[pi.length - 1].parameterType.runtimeType == DistributedConnection) - { - args[--argsCount] = this; - } - - if (parameters != null) - { - for (int i = 0; i < argsCount && i < parameters.length; i++) - { - //args[i] = DC.CastConvert(parameters[i], pi[i].ParameterType); - } - } - } - - // create the resource - var resource = null; //Activator.CreateInstance(type, args) as IResource; - - Warehouse.put(resource, name, store as IStore, parent).then((ok) { - sendReply(IIPPacketAction.CreateResource, callback) - .addUint32(resource.instance.id) - .done(); - }).error((ex){ - // send some error - sendError(ErrorType.Management, callback, ExceptionCode.AddToStoreFailed.index); - }); - - }); - }); - }); - }); - }); - } - - void iipRequestDeleteResource(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((r) - { - if (r == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - if (r.instance.store.instance.applicable(session, ActionType.Delete, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.DeleteDenied.index); - return; - } - - if (Warehouse.remove(r)) - sendReply(IIPPacketAction.DeleteResource, callback).done(); - //SendParams((byte)0x84, callback); - else - sendError(ErrorType.Management, callback, ExceptionCode.DeleteFailed.index); - }); - } - - void iipRequestGetAttributes(int callback, int resourceId, DC attributes, [bool all = false]) - { - Warehouse.getById(resourceId).then((r) - { - if (r == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - // if (!r.instance.store.instance.applicable(r, session, ActionType.InquireAttributes, null)) - if (r.instance.applicable(session, ActionType.InquireAttributes, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.ViewAttributeDenied.index); - return; - } - - List attrs = null; - - if (!all) - attrs = attributes.getStringArray(0, attributes.length); - - var st = r.instance.getAttributes(attrs); - - if (st != null) - sendReply(all ? IIPPacketAction.GetAllAttributes : IIPPacketAction.GetAttributes, callback) - .addDC(Codec.composeStructure(st, this, true, true, true)) - .done(); - else - sendError(ErrorType.Management, callback, ExceptionCode.GetAttributesFailed.index); - - }); - } - - void iipRequestAddChild(int callback, int parentId, int childId) - { - Warehouse.getById(parentId).then((parent) - { - if (parent == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - Warehouse.getById(childId).then((child) - { - if (child == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - if (parent.instance.applicable(this.session, ActionType.AddChild, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied.index); - return; - } - - if (child.instance.applicable(this.session, ActionType.AddParent, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.AddParentDenied.index); - return; - } - - parent.instance.children.add(child); - - sendReply(IIPPacketAction.AddChild, callback).done(); - //child.instance.Parents - }); - - }); - } - - void iipRequestRemoveChild(int callback, int parentId, int childId) - { - Warehouse.getById(parentId).then((parent) - { - if (parent == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - Warehouse.getById(childId).then((child) - { - if (child == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - if (parent.instance.applicable(this.session, ActionType.RemoveChild, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.AddChildDenied.index); - return; - } - - if (child.instance.applicable(this.session, ActionType.RemoveParent, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.AddParentDenied.index); - return; - } - - parent.instance.children.remove(child); - - sendReply(IIPPacketAction.RemoveChild, callback).done(); - //child.instance.Parents - }); - - }); - } - - void iipRequestRenameResource(int callback, int resourceId, DC name) - { - Warehouse.getById(resourceId).then((resource) - { - if (resource == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - if (resource.instance.applicable(this.session, ActionType.Rename, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.RenameDenied.index); - return; - } - - - resource.instance.name = name.getString(0, name.length); - sendReply(IIPPacketAction.RenameResource, callback).done(); - }); - } - - void iipRequestResourceChildren(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((resource) - { - if (resource == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - sendReply(IIPPacketAction.ResourceChildren, callback) - .addDC(Codec.composeResourceArray(resource.instance.children.toList(), this, true)) - .done(); - - }); - } - - void iipRequestResourceParents(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((resource) - { - if (resource == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } - - sendReply(IIPPacketAction.ResourceParents, callback) - .addDC(Codec.composeResourceArray(resource.instance.parents.toList(), this, true)) + void iipRequestInvokeFunctionNamedArguments( + int callback, int resourceId, int index, DC content) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + Codec.parseStructure(content, 0, content.length, this) + .then((namedArgs) { + var ft = r.instance.template.getFunctionTemplateByIndex(index); + if (ft != null) { + if (r is DistributedResource) { + var rt = (r as DistributedResource) + .invokeByNamedArguments(index, namedArgs); + if (rt != null) { + rt.then((res) { + sendReply(IIPPacketAction.InvokeFunctionNamedArguments, + callback) + .addDC(Codec.compose(res, this)) .done(); - }); + }); + } else { + // function not found on a distributed object + } + } else { + var fi = null; + + if (fi != null) { + } else { + // ft found, fi not found, this should never happen + } + } + } else { + // no function at this index + } + }); + } else { + // no resource with this id } + }); + } - void iipRequestClearAttributes(int callback, int resourceId, DC attributes, [bool all = false]) - { - Warehouse.getById(resourceId).then((r) - { - if (r == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } + void iipRequestListen(int callback, int resourceId, int index) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + var et = r.instance.template.getEventTemplateByIndex(index); - if (r.instance.store.instance.applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeDenied.index); - return; - } + if (et != null) { + if (r is DistributedResource) { + r.listen(et.name).then((x) { + sendReply(IIPPacketAction.Listen, callback).done(); + }).error((x) => sendError(ErrorType.Exception, callback, + ExceptionCode.GeneralFailure.index)); + } else { + // if (!subscriptions.ContainsKey(r)) + // { + // sendError(ErrorType.Management, callback, ExceptionCode.NotAttached.index); + // return; + // } - List attrs = null; + // if (subscriptions[r].Contains(index)) + // { + // sendError(ErrorType.Management, callback, ExceptionCode.AlreadyListened.index); + // return; + // } - if (!all) - attrs = attributes.getStringArray(0, attributes.length); + // subscriptions[r].add(index); - if (r.instance.removeAttributes(attrs)) - sendReply(all ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes, callback).done(); - else - sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeFailed.index); - - }); + // sendReply(IIPPacketAction.Listen, callback).done(); + } + } else { + // pt not found + sendError(ErrorType.Management, callback, + ExceptionCode.MethodNotFound.index); + } + } else { + // resource not found + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); } + }); + } - void iipRequestUpdateAttributes(int callback, int resourceId, DC attributes, [bool clearAttributes = false]) - { - Warehouse.getById(resourceId).then((r) - { - if (r == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - return; - } + void iipRequestUnlisten(int callback, int resourceId, int index) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + var et = r.instance.template.getEventTemplateByIndex(index); - if (r.instance.store.instance.applicable(session, ActionType.UpdateAttributes, null) != Ruling.Allowed) - { - sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeDenied.index); - return; - } + if (et != null) { + if (r is DistributedResource) { + r.unlisten(et.name).then((x) { + sendReply(IIPPacketAction.Unlisten, callback).done(); + }).error((x) => sendError(ErrorType.Exception, callback, + ExceptionCode.GeneralFailure.index)); + } else { + // if (!subscriptions.ContainsKey(r)) + // { + // SendError(ErrorType.Management, callback, (ushort)ExceptionCode.NotAttached); + // return; + // } - Codec.parseStructure(attributes, 0, attributes.length, this).then((attrs) - { - if (r.instance.setAttributes(attrs, clearAttributes)) - sendReply(clearAttributes ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes, - callback).done(); - else - sendError(ErrorType.Management, callback, ExceptionCode.UpdateAttributeFailed.index); - }); + // if (!subscriptions[r].Contains(index)) + // { + // SendError(ErrorType.Management, callback, (ushort)ExceptionCode.AlreadyUnlistened); + // return; + // } - }); + // subscriptions[r].Remove(index); + // SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); + } + } else { + // pt not found + sendError(ErrorType.Management, callback, + ExceptionCode.MethodNotFound.index); + } + } else { + // resource not found + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); } + }); + } - void iipRequestTemplateFromClassName(int callback, String className) - { - Warehouse.getTemplateByClassName(className).then((t) - { - if (t != null) - sendReply(IIPPacketAction.TemplateFromClassName, callback) - .addInt32(t.content.length) - .addDC(t.content) - .done(); - else - { - // reply failed - sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound.index); - } - }); - } + // void iipRequestGetProperty(int callback, int resourceId, int index) { + // Warehouse.getById(resourceId).then((r) { + // if (r != null) { + // var pt = r.instance.template.getFunctionTemplateByIndex(index); + // if (pt != null) { + // if (r is DistributedResource) { + // sendReply(IIPPacketAction.GetProperty, callback) + // .addDC(Codec.compose( + // (r as DistributedResource).get(pt.index), this)) + // .done(); + // } else { + // var pi = null; //r.GetType().GetTypeInfo().GetProperty(pt.Name); - void iipRequestTemplateFromClassId(int callback, Guid classId) - { - Warehouse.getTemplateByClassId(classId).then((t) - { - if (t != null) - sendReply(IIPPacketAction.TemplateFromClassId, callback) - .addInt32(t.content.length) - .addDC(t.content) - .done(); - else - { - // reply failed - sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound.index); - } - }); - } + // if (pi != null) { + // sendReply(IIPPacketAction.GetProperty, callback) + // .addDC(Codec.compose(pi.GetValue(r), this)) + // .done(); + // } else { + // // pt found, pi not found, this should never happen + // } + // } + // } else { + // // pt not found + // } + // } else { + // // resource not found + // } + // }); + // } + void iipRequestInquireResourceHistory( + int callback, int resourceId, DateTime fromDate, DateTime toDate) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + r.instance.store.getRecord(r, fromDate, toDate).then((results) { + var history = Codec.composeHistory(results, this, true); - - void iipRequestTemplateFromResourceId(int callback, int resourceId) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - sendReply(IIPPacketAction.TemplateFromResourceId, callback) - .addInt32(r.instance.template.content.length) - .addDC(r.instance.template.content) - .done(); - else - { - // reply failed - sendError(ErrorType.Management, callback, ExceptionCode.TemplateNotFound.index); - } - }); - } - - - - - void iipRequestQueryResources(int callback, String resourceLink) - { - Warehouse.query(resourceLink).then((r) - { - if (r == null) - { - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - } - else - { - var list = r.where((x) => x.instance.applicable(session, ActionType.Attach, null) != Ruling.Denied).toList(); - - if (list.length == 0) - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - else - sendReply(IIPPacketAction.QueryLink, callback) - .addDC(Codec.composeResourceArray(list, this, true)) - .done(); - } - }); - } - - void IIPRequestResourceAttribute(int callback, int resourceId) - { - - } - - void iipRequestInvokeFunctionArrayArguments(int callback, int resourceId, int index, DC content) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - Codec.parseVarArray(content, 0, content.length, this).then((arguments) - { - var ft = r.instance.template.getFunctionTemplateByIndex(index); - if (ft != null) - { - if (r is DistributedResource) - { - var rt = (r as DistributedResource).invokeByArrayArguments(index, arguments); - if (rt != null) - { - rt.then((res) - { - sendReply(IIPPacketAction.InvokeFunctionArrayArguments, callback) - .addDC(Codec.compose(res, this)) - .done(); - }); - } - else - { - - // function not found on a distributed object - } - } - else - { - var fi = null ;//r.GetType().GetTypeInfo().GetMethod(ft.name); - - - if (fi != null) - { - - } - else - { - // ft found, fi not found, this should never happen - } - } - } - else - { - // no function at this index - } - }); - } - else - { - // no resource with this id - } - }); - } - - - void iipRequestInvokeFunctionNamedArguments(int callback, int resourceId, int index, DC content) - { - - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - Codec.parseStructure(content, 0, content.length, this).then((namedArgs) - { - var ft = r.instance.template.getFunctionTemplateByIndex(index); - if (ft != null) - { - if (r is DistributedResource) - { - var rt = (r as DistributedResource).invokeByNamedArguments(index, namedArgs); - if (rt != null) - { - rt.then((res) - { - sendReply(IIPPacketAction.InvokeFunctionNamedArguments, callback) - .addDC(Codec.compose(res, this)) - .done(); - }); - } - else - { - - // function not found on a distributed object - } - } - else - { - - var fi = null; - - - if (fi != null) - { - } - else - { - // ft found, fi not found, this should never happen - } - } - } - else - { - // no function at this index - } - }); - } - else - { - // no resource with this id - } - }); - } - - void iipRequestGetProperty(int callback, int resourceId, int index) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - var pt = r.instance.template.getFunctionTemplateByIndex(index); - if (pt != null) - { - if (r is DistributedResource) - { - sendReply(IIPPacketAction.GetProperty, callback) - .addDC(Codec.compose((r as DistributedResource).get(pt.index), this)) - .done(); - } - else - { - var pi = null; //r.GetType().GetTypeInfo().GetProperty(pt.Name); - - if (pi != null) - { - sendReply(IIPPacketAction.GetProperty, callback) - .addDC(Codec.compose(pi.GetValue(r), this)) - .done(); - } - else - { - // pt found, pi not found, this should never happen - } - } - } - else - { - // pt not found - } - } - else - { - // resource not found - } - }); - } - - void iipRequestInquireResourceHistory(int callback, int resourceId, DateTime fromDate, DateTime toDate) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - r.instance.store.getRecord(r, fromDate, toDate).then((results) - { - var history = Codec.composeHistory(results, this, true); - - /* + /* ulong fromAge = 0; ulong toAge = 0; @@ -2055,569 +2087,541 @@ class DistributedConnection extends NetworkConnection with IStore }*/ - sendReply(IIPPacketAction.ResourceHistory, callback) - .addDC(history) - .done(); - - }); - } - }); + sendReply(IIPPacketAction.ResourceHistory, callback) + .addDC(history) + .done(); + }); } + }); + } - void iipRequestGetPropertyIfModifiedSince(int callback, int resourceId,int index, int age) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - var pt = r.instance.template.getFunctionTemplateByIndex(index); - if (pt != null) - { - if (r.instance.getAge(index) > age) - { - var pi = null; //r.GetType().GetProperty(pt.Name); - if (pi != null) - { - sendReply(IIPPacketAction.GetPropertyIfModified, callback) - .addDC(Codec.compose(pi.GetValue(r), this)) - .done(); - } - else - { - // pt found, pi not found, this should never happen - } - } - else - { - sendReply(IIPPacketAction.GetPropertyIfModified, callback) - .addUint8(DataType.NotModified) - .done(); - } - } - else - { - // pt not found - } - } - else - { - // resource not found - } - }); - } + // void iipRequestGetPropertyIfModifiedSince( + // int callback, int resourceId, int index, int age) { + // Warehouse.getById(resourceId).then((r) { + // if (r != null) { + // var pt = r.instance.template.getFunctionTemplateByIndex(index); + // if (pt != null) { + // if (r.instance.getAge(index) > age) { + // var pi = null; //r.GetType().GetProperty(pt.Name); + // if (pi != null) { + // sendReply(IIPPacketAction.GetPropertyIfModified, callback) + // .addDC(Codec.compose(pi.GetValue(r), this)) + // .done(); + // } else { + // // pt found, pi not found, this should never happen + // } + // } else { + // sendReply(IIPPacketAction.GetPropertyIfModified, callback) + // .addUint8(DataType.NotModified) + // .done(); + // } + // } else { + // // pt not found + // } + // } else { + // // resource not found + // } + // }); + // } - void iipRequestSetProperty(int callback, int resourceId, int index, DC content) - { - Warehouse.getById(resourceId).then((r) - { - if (r != null) - { - - - var pt = r.instance.template.getPropertyTemplateByIndex(index); - if (pt != null) - { - Codec.parse(content, 0, this).then((value) - { - if (r is DistributedResource) - { - // propagation - (r as DistributedResource).set(index, value).then((x) - { - sendReply(IIPPacketAction.SetProperty, callback).done(); - }).error((x) - { - sendError(x.type, callback, x.code, x.message); - }); - } - else - { - - /* + void iipRequestSetProperty( + int callback, int resourceId, int index, DC content) { + Warehouse.getById(resourceId).then((r) { + if (r != null) { + var pt = r.instance.template.getPropertyTemplateByIndex(index); + if (pt != null) { + Codec.parse(content, 0, this).then((value) { + if (r is DistributedResource) { + // propagation + (r as DistributedResource).set(index, value).then((x) { + sendReply(IIPPacketAction.SetProperty, callback).done(); + }).error((x) { + sendError(x.type, callback, x.code, x.message); + }); + } else { + /* #if NETSTANDARD1_5 var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); #else var pi = r.GetType().GetProperty(pt.Name); #endif*/ - - var pi = null;// pt.Info; - - if (pi != null) - { - - if (r.instance.applicable(session, ActionType.SetProperty, pt, this) == Ruling.Denied) - { - sendError(ErrorType.Exception, callback, ExceptionCode.SetPropertyDenied.index); - return; - } - - if (!pi.CanWrite) - { - sendError(ErrorType.Management, callback, ExceptionCode.ReadOnlyProperty.index); - return; - } - - - if (pi.propertyType.runtimeType == DistributedPropertyContext) - { - value = new DistributedPropertyContext.setter(this, value); - } - else - { - // cast new value type to property type - // value = DC.castConvert(value, pi.PropertyType); - } - - - try - { - pi.setValue(r, value); - sendReply(IIPPacketAction.SetProperty, callback).done(); - } - catch (ex) - { - sendError(ErrorType.Exception, callback, 0, ex.message); - } - - } - else - { - // pt found, pi not found, this should never happen - sendError(ErrorType.Management, callback, ExceptionCode.PropertyNotFound.index); - } - } - - }); - } - else - { - // property not found - sendError(ErrorType.Management, callback, ExceptionCode.PropertyNotFound.index); - } - } - else - { - // resource not found - sendError(ErrorType.Management, callback, ExceptionCode.ResourceNotFound.index); - } - }); - } - - /// - /// Get the ResourceTemplate for a given class Id. - /// - /// Class GUID. - /// ResourceTemplate. - AsyncReply getTemplate(Guid classId) - { - if (_templates.containsKey(classId)) - return new AsyncReply.ready(_templates[classId]); - else if (_templateRequests.containsKey(classId)) - return _templateRequests[classId]; - - var reply = new AsyncReply(); - _templateRequests.add(classId, reply); - - sendRequest(IIPPacketAction.TemplateFromClassId) - .addGuid(classId) - .done() - .then((rt) - { - _templateRequests.remove(classId); - _templates[(rt[0] as ResourceTemplate).classId] = rt[0] as ResourceTemplate; - Warehouse.putTemplate(rt[0] as ResourceTemplate); - reply.trigger(rt[0]); - }).error((ex) - { - reply.triggerError(ex); - }); - - return reply; - } - - // IStore interface - /// - /// Get a resource by its path. - /// - /// Path to the resource. - /// Resource - AsyncReply get(String path) - { - - var rt = new AsyncReply(); - - query(path).then((ar) - { - if (ar?.length > 0) - rt.trigger(ar[0]); - else - rt.trigger(null); - }).error((ex) => rt.triggerError(ex)); - - return rt; - - - } - - /// - /// Retrive a resource by its instance Id. - /// - /// Instance Id - /// Resource - AsyncReply retrieve(int iid) - { - for (var r in _resources.values) - if (r.instance.id == iid) - return new AsyncReply.ready(r); - return new AsyncReply.ready(null); - } - - /// - /// Fetch a resource from the other end - /// - /// Class GUID - /// Resource IdGuid classId - /// DistributedResource - AsyncReply fetch(int id) - { - var resource = _resources[id]; - var request = _resourceRequests[id]; - - if (request != null) - { - // dig for dead locks - if (resource != null) // dead lock - return new AsyncReply.ready(_resources[id]); - else - return request; - } - else if (resource != null && !resource.suspended) - return new AsyncReply.ready(resource); - - var reply = new AsyncReply(); - _resourceRequests.add(id, reply); - - sendRequest(IIPPacketAction.AttachResource) - .addUint32(id) - .done() - .then((rt) - { - var dr = resource ?? new DistributedResource(this, id, rt[1], rt[2]); - - getTemplate(rt[0] as Guid).then((tmp) - { - //print("New template "); - - var d = rt[3] as DC; - - // ClassId, ResourceAge, ResourceLink, Content - if (resource == null) - { - Warehouse.put(dr, id.toString(), this, null, tmp).then((ok){ - Codec.parsePropertyValueArray(d, 0, d.length, this).then((ar) - { - //print("attached"); - dr.attach(ar); - _resourceRequests.remove(id); - reply.trigger(dr); - }); - }).error((ex) => reply.triggerError(ex)); - } - else - { - Codec.parsePropertyValueArray(d, 0, d.length, this).then((ar) - { - //print("attached"); - dr.attach(ar); - _resourceRequests.remove(id); - reply.trigger(dr); - }); - } - - }).error((ex) - { - reply.triggerError(ex); - }); - }).error((ex) - { - reply.triggerError(ex); - }); - - return reply; - } - - - AsyncReply> getChildren(IResource resource) - { - var rt = new AsyncReply>(); - - sendRequest(IIPPacketAction.ResourceChildren) - .addUint32(resource.instance.id) - .done() - .then((ar) - { - var d = ar[0] as DC; - Codec.parseResourceArray(d, 0, d.length, this).then((resources) - { - rt.trigger(resources); - }).error((ex) => rt.triggerError(ex)); - }); - - return rt; - } - - AsyncReply> getParents(IResource resource) - { - var rt = new AsyncReply>(); - - sendRequest(IIPPacketAction.ResourceParents) - .addUint32(resource.instance.id) - .done() - .then((ar) - { - var d = ar[0] as DC; - Codec.parseResourceArray(d, 0, d.length, this).then((resources) - { - rt.trigger(resources); - }).error((ex) => rt.triggerError(ex)); - }); - - return rt; - } - - AsyncReply removeAttributes(IResource resource, [List attributes = null]) - { - var rt = new AsyncReply(); - - if (attributes == null) - sendRequest(IIPPacketAction.ClearAllAttributes) - .addUint32(resource.instance.id) - .done() - .then((ar) => rt.trigger(true)) - .error((ex) => rt.triggerError(ex)); - else - { - var attrs = DC.stringArrayToBytes(attributes); - sendRequest(IIPPacketAction.ClearAttributes) - .addUint32(resource.instance.id) - .addInt32(attrs.length) - .addDC(attrs) - .done() - .then((ar) => rt.trigger(true)) - .error((ex) => rt.triggerError(ex)); - } - - return rt; - } - - AsyncReply setAttributes(IResource resource, Structure attributes, [ bool clearAttributes = false ]) - { - var rt = new AsyncReply(); - - sendRequest(clearAttributes ? IIPPacketAction.UpdateAllAttributes : IIPPacketAction.UpdateAttributes) - .addUint32(resource.instance.id) - .addDC(Codec.composeStructure(attributes, this, true, true, true)) - .done() - .then((ar) => rt.trigger(true)) - .error((ex) => rt.triggerError(ex)); - - return rt; - } - - AsyncReply getAttributes(IResource resource, [List attributes = null]) - { - var rt = new AsyncReply(); - - if (attributes == null) - { - sendRequest(IIPPacketAction.GetAllAttributes) - .addUint32(resource.instance.id) - .done() - .then((ar) - { - var d = ar[0] as DC; - Codec.parseStructure(d, 0, d.length, this).then((st) - { - resource.instance.setAttributes(st); - rt.trigger(st); - }).error((ex) => rt.triggerError(ex)); - }); - } - else - { - var attrs = DC.stringArrayToBytes(attributes); - sendRequest(IIPPacketAction.GetAttributes) - .addUint32(resource.instance.id) - .addInt32(attrs.length) - .addDC(attrs) - .done() - .then((ar) - { - var d = ar[0] as DC; - Codec.parseStructure(d, 0, d.length, this).then((st) - { - - resource.instance.setAttributes(st); - - rt.trigger(st); - }).error((ex) => rt.triggerError(ex)); - }); - } - - return rt; - } - - /// - /// Get resource history. - /// - /// IResource. - /// From date. - /// To date. - /// - AsyncReply>> getRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - if (resource is DistributedResource) - { - var dr = resource as DistributedResource; - - if (dr.connection != this) - return new AsyncReply>>.ready(null); - - var reply = new AsyncReply>>(); - - sendRequest(IIPPacketAction.ResourceHistory) - .addUint32(dr.id) - .addDateTime(fromDate) - .addDateTime(toDate) - .done() - .then((rt) - { - var content = rt[0] as DC; - - Codec.parseHistory(content, 0, content.length, resource, this) - .then((history) => reply.trigger(history)); - - }).error((ex) => reply.triggerError(ex)); - - return reply; - } - else - return new AsyncReply>>.ready(null); - } - - /// - /// Query resources at specific link. - /// - /// Link path. - /// - AsyncReply> query(String path) - { - var str = DC.stringToBytes(path); - var reply = new AsyncReply>(); - - sendRequest(IIPPacketAction.QueryLink) - .addUint16(str.length) - .addDC(str) - .done() - .then((args) - { - var content = args[0] as DC; - - Codec.parseResourceArray(content, 0, content.length, this) - .then((resources) => reply.trigger(resources)); - - }).error((ex)=>reply.triggerError(ex)); - - return reply; - } - - - /// - /// Create a new resource. - /// - /// The store in which the resource is saved. - /// Class full name. - /// Constructor parameters. - /// Resource attributeds. - /// Values for the resource properties. - /// New resource instance - AsyncReply create(IStore store, IResource parent, String className, List parameters, Structure attributes, Structure values) - { - var reply = new AsyncReply(); - var pkt = new BinaryList() - .addUint32(store.instance.id) - .addUint32(parent.instance.id) - .addUint8(className.length) - .addString(className) - .addDC(Codec.composeVarArray(parameters, this, true)) - .addDC(Codec.composeStructure(attributes, this, true, true, true)) - .addDC(Codec.composeStructure(values, this)); - - pkt.insertInt32(8, pkt.length); - - sendRequest(IIPPacketAction.CreateResource) - .addDC(pkt.toDC()) - .done() - .then((args) - { - var rid = args[0]; - - fetch(rid).then((r) - { - reply.trigger(r); - }); - - }); - - return reply; - } - - _instance_ResourceDestroyed(IResource resource) - { - // compose the packet - sendEvent(IIPPacketEvent.ResourceDestroyed) - .addUint32(resource.instance.id) - .done(); - } - - void _instance_PropertyModified(IResource resource, String name, newValue) - { - var pt = resource.instance.template.getPropertyTemplateByName(name); - - if (pt == null) - return; - - sendEvent(IIPPacketEvent.PropertyUpdated) - .addUint32(resource.instance.id) - .addUint8(pt.index) - .addDC(Codec.compose(newValue, this)) - .done(); - - } - - // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) - - void _instance_EventOccurred(IResource resource, issuer, List receivers, String name, dynamic args) - { - var et = resource.instance.template.getEventTemplateByName(name); - - if (et == null) - return; - - - if (receivers != null) - if (!receivers.contains(this.session)) + var pi = null; // pt.Info; + + if (pi != null) { + if (r.instance.applicable( + session, ActionType.SetProperty, pt, this) == + Ruling.Denied) { + sendError(ErrorType.Exception, callback, + ExceptionCode.SetPropertyDenied.index); return; + } - if (resource.instance.applicable(this.session, ActionType.ReceiveEvent, et, issuer) == Ruling.Denied) - return; + if (!pi.CanWrite) { + sendError(ErrorType.Management, callback, + ExceptionCode.ReadOnlyProperty.index); + return; + } - // compose the packet - sendEvent(IIPPacketEvent.EventOccurred) - .addUint32(resource.instance.id) - .addUint8(et.index) - .addDC(Codec.compose(args, this, true)) - .done(); + if (pi.propertyType.runtimeType == DistributedPropertyContext) { + value = new DistributedPropertyContext.setter(this, value); + } else { + // cast new value type to property type + // value = DC.castConvert(value, pi.PropertyType); + } + + try { + pi.setValue(r, value); + sendReply(IIPPacketAction.SetProperty, callback).done(); + } catch (ex) { + sendError(ErrorType.Exception, callback, 0, ex.message); + } + } else { + // pt found, pi not found, this should never happen + sendError(ErrorType.Management, callback, + ExceptionCode.PropertyNotFound.index); + } + } + }); + } else { + // property not found + sendError(ErrorType.Management, callback, + ExceptionCode.PropertyNotFound.index); + } + } else { + // resource not found + sendError(ErrorType.Management, callback, + ExceptionCode.ResourceNotFound.index); } + }); + } + + /// + /// Get the TypeTemplate for a given class Id. + /// + /// Class GUID. + /// TypeTemplate. + AsyncReply getTemplate(Guid classId) { + if (_templates.containsKey(classId)) + return new AsyncReply.ready(_templates[classId]); + else if (_templateRequests.containsKey(classId)) + return _templateRequests[classId]; + + var reply = new AsyncReply(); + _templateRequests.add(classId, reply); + + sendRequest(IIPPacketAction.TemplateFromClassId) + .addGuid(classId) + .done() + .then((rt) { + _templateRequests.remove(classId); + _templates[(rt[0] as TypeTemplate).classId] = + rt[0] as TypeTemplate; + Warehouse.putTemplate(rt[0] as TypeTemplate); + reply.trigger(rt[0]); + }).error((ex) { + reply.triggerError(ex); + }); + + return reply; + } + + // IStore interface + /// + /// Get a resource by its path. + /// + /// Path to the resource. + /// Resource + AsyncReply get(String path) { + var rt = new AsyncReply(); + + query(path).then((ar) { + if (ar?.length > 0) + rt.trigger(ar[0]); + else + rt.trigger(null); + }).error((ex) => rt.triggerError(ex)); + + return rt; + } + + /// + /// Retrive a resource by its instance Id. + /// + /// Instance Id + /// Resource + AsyncReply retrieve(int iid) { + for (var r in _resources.values) + if (r.instance.id == iid) return new AsyncReply.ready(r); + return new AsyncReply.ready(null); + } + + AsyncReply> getLinkTemplates(String link) { + var reply = new AsyncReply>(); + + var l = DC.stringToBytes(link); + + sendRequest(IIPPacketAction.LinkTemplates) + .addUint16(l.length) + .addDC(l) + .done() + .then((rt) { + List templates = []; + // parse templates + + DC data = rt[0]; + //var offset = 0; + for (int offset = 0; offset < data.length;) { + var cs = data.getUint32(offset); + offset += 4; + templates.add(TypeTemplate.parse(data, offset, cs)); + offset += cs; + } + + reply.trigger(templates); + }).error((ex) { + reply.triggerError(ex); + }); + + return reply; + } + + /// + /// Fetch a resource from the other end + /// + /// Class GUID + /// Resource IdGuid classId + /// DistributedResource + AsyncReply fetch(int id) { + var resource = _resources[id]; + var request = _resourceRequests[id]; + + if (request != null) { + // dig for dead locks + if (resource != null) // dead lock + return new AsyncReply.ready(_resources[id]); + else + return request; + } else if (resource != null && !resource.suspended) + return new AsyncReply.ready(resource); + + var reply = new AsyncReply(); + _resourceRequests.add(id, reply); + + sendRequest(IIPPacketAction.AttachResource) + .addUint32(id) + .done() + .then((rt) { + // @TODO: Generator code + DistributedResource dr; + + if (resource == null) { + var template = Warehouse.getTemplateByClassId(rt[0], TemplateType.Wrapper); + if (template?.definedType != null) { + dr = Warehouse.createInstance(template?.definedType); + dr.init(this, id, rt[1], rt[2]); + } else { + dr = new DistributedResource(this, id, rt[1], rt[2]); + } + } else + dr = resource; + + //var dr = resource ?? new DistributedResource(this, id, rt[1], rt[2]); + + getTemplate(rt[0] as Guid).then((tmp) { + //print("New template "); + + var d = rt[3] as DC; + + // ClassId, ResourceAge, ResourceLink, Content + if (resource == null) { + Warehouse.put(id.toString(), dr, this, null, tmp).then((ok) { + Codec.parsePropertyValueArray(d, 0, d.length, this).then((ar) { + //print("attached"); + dr.attach(ar); + _resourceRequests.remove(id); + reply.trigger(dr); + }); + }).error((ex) => reply.triggerError(ex)); + } else { + Codec.parsePropertyValueArray(d, 0, d.length, this).then((ar) { + //print("attached"); + dr.attach(ar); + _resourceRequests.remove(id); + reply.trigger(dr); + }); + } + }).error((ex) { + reply.triggerError(ex); + }); + }).error((ex) { + reply.triggerError(ex); + }); + + return reply; + } + + AsyncReply> getChildren(IResource resource) { + var rt = new AsyncReply>(); + + sendRequest(IIPPacketAction.ResourceChildren) + .addUint32(resource.instance.id) + .done() + .then((ar) { + var d = ar[0] as DC; + Codec.parseResourceArray(d, 0, d.length, this).then((resources) { + rt.trigger(resources); + }).error((ex) => rt.triggerError(ex)); + }); + + return rt; + } + + AsyncReply> getParents(IResource resource) { + var rt = new AsyncReply>(); + + sendRequest(IIPPacketAction.ResourceParents) + .addUint32(resource.instance.id) + .done() + .then((ar) { + var d = ar[0] as DC; + Codec.parseResourceArray(d, 0, d.length, this).then((resources) { + rt.trigger(resources); + }).error((ex) => rt.triggerError(ex)); + }); + + return rt; + } + + AsyncReply removeAttributes(IResource resource, + [List attributes = null]) { + var rt = new AsyncReply(); + + if (attributes == null) + sendRequest(IIPPacketAction.ClearAllAttributes) + .addUint32(resource.instance.id) + .done() + .then((ar) => rt.trigger(true)) + .error((ex) => rt.triggerError(ex)); + else { + var attrs = DC.stringArrayToBytes(attributes); + sendRequest(IIPPacketAction.ClearAttributes) + .addUint32(resource.instance.id) + .addInt32(attrs.length) + .addDC(attrs) + .done() + .then((ar) => rt.trigger(true)) + .error((ex) => rt.triggerError(ex)); + } + + return rt; + } + + AsyncReply setAttributes(IResource resource, Structure attributes, + [bool clearAttributes = false]) { + var rt = new AsyncReply(); + + sendRequest(clearAttributes + ? IIPPacketAction.UpdateAllAttributes + : IIPPacketAction.UpdateAttributes) + .addUint32(resource.instance.id) + .addDC(Codec.composeStructure(attributes, this, true, true, true)) + .done() + .then((ar) => rt.trigger(true)) + .error((ex) => rt.triggerError(ex)); + + return rt; + } + + AsyncReply getAttributes(IResource resource, + [List attributes = null]) { + var rt = new AsyncReply(); + + if (attributes == null) { + sendRequest(IIPPacketAction.GetAllAttributes) + .addUint32(resource.instance.id) + .done() + .then((ar) { + var d = ar[0] as DC; + Codec.parseStructure(d, 0, d.length, this).then((st) { + resource.instance.setAttributes(st); + rt.trigger(st); + }).error((ex) => rt.triggerError(ex)); + }); + } else { + var attrs = DC.stringArrayToBytes(attributes); + sendRequest(IIPPacketAction.GetAttributes) + .addUint32(resource.instance.id) + .addInt32(attrs.length) + .addDC(attrs) + .done() + .then((ar) { + var d = ar[0] as DC; + Codec.parseStructure(d, 0, d.length, this).then((st) { + resource.instance.setAttributes(st); + + rt.trigger(st); + }).error((ex) => rt.triggerError(ex)); + }); + } + + return rt; + } + + /// + /// Get resource history. + /// + /// IResource. + /// From date. + /// To date. + /// + AsyncReply>> getRecord( + IResource resource, DateTime fromDate, DateTime toDate) { + if (resource is DistributedResource) { + var dr = resource as DistributedResource; + + if (dr.connection != this) + return new AsyncReply< + KeyList>>.ready(null); + + var reply = + new AsyncReply>>(); + + sendRequest(IIPPacketAction.ResourceHistory) + .addUint32(dr.id) + .addDateTime(fromDate) + .addDateTime(toDate) + .done() + .then((rt) { + var content = rt[0] as DC; + + Codec.parseHistory(content, 0, content.length, resource, this) + .then((history) => reply.trigger(history)); + }).error((ex) => reply.triggerError(ex)); + + return reply; + } else + return new AsyncReply< + KeyList>>.ready(null); + } + + /// + /// Query resources at specific link. + /// + /// Link path. + /// + AsyncReply> query(String path) { + var str = DC.stringToBytes(path); + var reply = new AsyncReply>(); + + sendRequest(IIPPacketAction.QueryLink) + .addUint16(str.length) + .addDC(str) + .done() + .then((args) { + var content = args[0] as DC; + + Codec.parseResourceArray(content, 0, content.length, this) + .then((resources) => reply.trigger(resources)); + }).error((ex) => reply.triggerError(ex)); + + return reply; + } + + /// + /// Create a new resource. + /// + /// The store in which the resource is saved. + /// Class full name. + /// Constructor parameters. + /// Resource attributeds. + /// Values for the resource properties. + /// New resource instance + AsyncReply create( + IStore store, + IResource parent, + String className, + List parameters, + Structure attributes, + Structure values) { + var reply = new AsyncReply(); + var pkt = new BinaryList() + .addUint32(store.instance.id) + .addUint32(parent.instance.id) + .addUint8(className.length) + .addString(className) + .addDC(Codec.composeVarArray(parameters, this, true)) + .addDC(Codec.composeStructure(attributes, this, true, true, true)) + .addDC(Codec.composeStructure(values, this)); + + pkt.insertInt32(8, pkt.length); + + sendRequest(IIPPacketAction.CreateResource) + .addDC(pkt.toDC()) + .done() + .then((args) { + var rid = args[0]; + + fetch(rid).then((r) { + reply.trigger(r); + }); + }); + + return reply; + } + + _instance_ResourceDestroyed(IResource resource) { + // compose the packet + _unsubscrive(resource); + sendEvent(IIPPacketEvent.ResourceDestroyed) + .addUint32(resource.instance.id) + .done(); + } + + void _instance_PropertyModified(IResource resource, String name, newValue) { + var pt = resource.instance.template.getPropertyTemplateByName(name); + + if (pt == null) return; + + sendEvent(IIPPacketEvent.PropertyUpdated) + .addUint32(resource.instance.id) + .addUint8(pt.index) + .addDC(Codec.compose(newValue, this)) + .done(); + } + + // private void Instance_EventOccurred(IResource resource, string name, string[] users, DistributedConnection[] connections, object[] args) + + void _instance_EventOccurred(IResource resource, issuer, + List receivers, String name, dynamic args) { + var et = resource.instance.template.getEventTemplateByName(name); + + if (et == null) return; + + if (receivers != null) if (!receivers.contains(this.session)) return; + + if (resource.instance + .applicable(this.session, ActionType.ReceiveEvent, et, issuer) == + Ruling.Denied) return; + + // compose the packet + sendEvent(IIPPacketEvent.EventOccurred) + .addUint32(resource.instance.id) + .addUint8(et.index) + .addDC(Codec.compose(args, this, true)) + .done(); + } + + @override + getProperty(String name) => null; + + @override + invoke(String name, List arguments) => null; + + @override + setProperty(String name, value) => true; + + @override + TemplateDescriber get template => + TemplateDescriber("Esiur.Net.IIP.DistributedConnection"); } diff --git a/lib/src/Net/IIP/DistributedResource.dart b/lib/src/Net/IIP/DistributedResource.dart index ce74a12..1b47dc9 100644 --- a/lib/src/Net/IIP/DistributedResource.dart +++ b/lib/src/Net/IIP/DistributedResource.dart @@ -41,11 +41,12 @@ class DistributedResource extends IResource { //bool _isReady = false; String _link; + int _age; + List _properties; bool _destroyed = false; - List> _queued_updates = - List>(); + List> _queued_updates = []; /// /// Connection responsible for the distributed resource. @@ -111,6 +112,15 @@ class DistributedResource extends IResource { this._link = link; this._connection = connection; this._instanceId = instanceId; + this._age = age; + } + + void init( + DistributedConnection connection, int instanceId, int age, String link) { + this._link = link; + this._connection = connection; + this._instanceId = instanceId; + this._age = age; } //void _ready() @@ -165,6 +175,38 @@ class DistributedResource extends IResource { return true; } + AsyncReply listen(event) { + EventTemplate et = event is EventTemplate + ? event + : instance.template.getEventTemplateByName(event); + + if (et == null) + return AsyncReply().triggerError(new AsyncException( + ErrorType.Management, ExceptionCode.MethodNotFound.index, "")); + + if (!et.listenable) + return AsyncReply().triggerError(new AsyncException( + ErrorType.Management, ExceptionCode.NotListenable.index, "")); + + return _connection.sendListenRequest(_instanceId, et.index); + } + + AsyncReply unlisten(event) { + EventTemplate et = event is EventTemplate + ? event + : instance.template.getEventTemplateByName(event); + + if (et == null) + return AsyncReply().triggerError(new AsyncException( + ErrorType.Management, ExceptionCode.MethodNotFound.index, "")); + + if (!et.listenable) + return AsyncReply().triggerError(new AsyncException( + ErrorType.Management, ExceptionCode.NotListenable.index, "")); + + return connection.sendUnlistenRequest(_instanceId, et.index); + } + void emitEventByIndex(int index, dynamic args) { // neglect events when the object is not yet attached if (!_attached) return; diff --git a/lib/src/Net/IIP/DistributedServer.dart b/lib/src/Net/IIP/DistributedServer.dart new file mode 100644 index 0000000..16792c8 --- /dev/null +++ b/lib/src/Net/IIP/DistributedServer.dart @@ -0,0 +1,35 @@ +import 'package:esiur/src/Resource/Template/TemplateDescriber.dart'; + +import '../../Resource/IResource.dart'; +import '../../Core/AsyncReply.dart'; +import '../../Resource/ResourceTrigger.dart'; + +import './EntryPoint.dart'; + +class DistributedServer extends IResource { + @override + void destroy() { + this.emitArgs("destroy", []); + } + + @override + AsyncReply trigger(ResourceTrigger trigger) { + return AsyncReply.ready(true); + } + + EntryPoint entryPoint; + + @override + getProperty(String name) => null; + + @override + invoke(String name, List arguments) => null; + + @override + setProperty(String name, value) => true; + + @override + TemplateDescriber get template => + TemplateDescriber("Esiur.Net.IIP.DistributedServer"); + +} diff --git a/lib/src/Net/IIP/EntryPoint.dart b/lib/src/Net/IIP/EntryPoint.dart new file mode 100644 index 0000000..ed76c6d --- /dev/null +++ b/lib/src/Net/IIP/EntryPoint.dart @@ -0,0 +1,12 @@ + + +import '../../Resource/IResource.dart'; +import './DistributedConnection.dart'; +import '../../Core/AsyncReply.dart'; + +abstract class EntryPoint extends IResource +{ + + AsyncReply> query(String path, DistributedConnection sender); + bool create(); +} diff --git a/lib/src/Net/INetworkReceiver.dart b/lib/src/Net/INetworkReceiver.dart new file mode 100644 index 0000000..097365c --- /dev/null +++ b/lib/src/Net/INetworkReceiver.dart @@ -0,0 +1,9 @@ +import 'NetworkBuffer.dart'; + +abstract class INetworkReceiver +{ + void networkClose(T sender); + void networkReceive(T sender, NetworkBuffer buffer); + //void NetworkError(T sender); + void networkConnect(T sender); +} \ No newline at end of file diff --git a/lib/src/Net/NetworkConnection.dart b/lib/src/Net/NetworkConnection.dart index 7b93ac3..48fc5af 100644 --- a/lib/src/Net/NetworkConnection.dart +++ b/lib/src/Net/NetworkConnection.dart @@ -22,6 +22,8 @@ SOFTWARE. */ +import 'INetworkReceiver.dart'; + import '../Core/IDestructible.dart'; import 'Sockets/ISocket.dart'; import 'Sockets/SocketState.dart'; @@ -29,178 +31,145 @@ import 'NetworkBuffer.dart'; import '../Data/DC.dart'; import 'Sockets/IPEndPoint.dart'; -class NetworkConnection extends IDestructible -{ - ISocket _sock; +class NetworkConnection extends IDestructible with INetworkReceiver { + ISocket _sock; - DateTime _lastAction; + DateTime _lastAction; - //public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data); - //public delegate void ConnectionClosedEvent(NetworkConnection sender); - //public delegate void ConnectionEstablishedEvent(NetworkConnection sender); + //public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data); + //public delegate void ConnectionClosedEvent(NetworkConnection sender); + //public delegate void ConnectionEstablishedEvent(NetworkConnection sender); - //public event ConnectionEstablishedEvent OnConnect; - //public event DataReceivedEvent OnDataReceived; - //public event ConnectionClosedEvent OnClose; - //public event DestroyedEvent OnDestroy; - //object receivingLock = new object(); + //public event ConnectionEstablishedEvent OnConnect; + //public event DataReceivedEvent OnDataReceived; + //public event ConnectionClosedEvent OnClose; + //public event DestroyedEvent OnDestroy; + //object receivingLock = new object(); - bool _processing = false; + bool _processing = false; - // to be overridden - void connectionClosed() - { + void destroy() { + // if (connected) + close(); + //emitArgs("close", [this]); + //OnDestroy?.Invoke(this); + } + + NetworkConnection() {} + + ISocket get socket => _sock; + + void assign(ISocket socket) { + _lastAction = DateTime.now(); + _sock = socket; + + socket.receiver = this; + + //socket.on("receive", socket_OnReceive); + //socket.on("close", socket_OnClose); + //socket.on("connect", socket_OnConnect); + } + + ISocket unassign() { + if (_sock != null) { + // connected = false; + // _sock.off("close", socket_OnClose); + // _sock.off("connect", socket_OnConnect); + // _sock.off("receive", socket_OnReceive); + + _sock.receiver = null; + var rt = _sock; + _sock = null; + + return rt; + } else + return null; + } + + // to be overridden + void dataReceived(NetworkBuffer data) { + emitArgs("dataReceived", [data]); + } + + void connected(){ + + } + + void disconnected(){ + + } + + void close() { + try { + if (_sock != null) _sock.close(); + } catch (ex) { + //Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString()); } + } - void destroy() - { - // if (connected) - close(); - //emitArgs("close", [this]); - //OnDestroy?.Invoke(this); + DateTime get lastAction => _lastAction; + + IPEndPoint get remoteEndPoint => _sock?.remoteEndPoint; + + IPEndPoint get localEndPoint => _sock?.localEndPoint; + + bool get isConnected => _sock.state == SocketState.Established; + + void send(DC msg) { + try { + if (_sock != null) { + _lastAction = DateTime.now(); + _sock.send(msg); + } + } catch (ex) { + //Console.WriteLine(ex.ToString()); } + } - NetworkConnection() - { + void sendString(String data) { + send(DC.stringToBytes(data)); + } + @override + void networkClose(sender) { + disconnected(); + emitArgs("close", [this]); + } + + @override + void networkConnect(sender) { + connected(); + emitArgs("connect", [this]); + } + + @override + void networkReceive(sender, NetworkBuffer buffer) { + try { + // Unassigned ? + if (_sock == null) return; + + // Closed ? + if (_sock.state == SocketState.Closed || + _sock.state == SocketState.Terminated) // || !connected) + return; + + _lastAction = DateTime.now(); + + if (!_processing) { + _processing = true; + + try { + while (buffer.available > 0 && !buffer.protected) + dataReceived(buffer); + } catch (ex) {} + + _processing = false; + } + } catch (ex) { + print(ex); + //Global.Log("NetworkConnection", LogType.Warning, ex.ToString()); } - - - - ISocket get socket => _sock; - - void assign(ISocket socket) - { - _lastAction = DateTime.now(); - _sock = socket; - - socket.on("receive", socket_OnReceive); - socket.on("close", socket_OnClose); - socket.on("connect", socket_OnConnect); - } - - - void socket_OnConnect() - { - emitArgs("connect", [this]); - } - - void socket_OnClose() - { - connectionClosed(); - emitArgs("close", [this]); - } - - void socket_OnReceive(NetworkBuffer buffer) - { - try - { - - // Unassigned ? - if (_sock == null) - return; - - // Closed ? - if (_sock.state == SocketState.Closed || _sock.state == SocketState.Terminated) // || !connected) - return; - - _lastAction = DateTime.now(); - - if (!_processing) - { - _processing = true; - - try - { - while (buffer.available > 0 && !buffer.protected) - dataReceived(buffer); - } - catch(ex) - { - - } - - _processing = false; - } - - } - catch (ex) - { - print(ex); - //Global.Log("NetworkConnection", LogType.Warning, ex.ToString()); - } - - } - - ISocket unassign() - { - if (_sock != null) - { - // connected = false; - _sock.off("close", socket_OnClose); - _sock.off("connect", socket_OnConnect); - _sock.off("receive", socket_OnReceive); - - var rt = _sock; - _sock = null; - - return rt; - } - else - return null; - } - - void dataReceived(NetworkBuffer data) - { - emitArgs("dataReceived", [data]); - } - - void close() - { - try - { - if (_sock != null) - _sock.close(); - } - catch(ex) - { - //Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString()); - - } - } - - DateTime get lastAction => _lastAction; - - - IPEndPoint get remoteEndPoint => _sock?.remoteEndPoint; - - IPEndPoint get localEndPoint => _sock?.localEndPoint; - - bool get connected => _sock.state == SocketState.Established; - - - void send(DC msg) - { - - try - { - - if (_sock != null) - { - _lastAction = DateTime.now(); - _sock.send(msg); - } - } - catch (ex) - { - //Console.WriteLine(ex.ToString()); - } - } - - void sendString(String data) - { - send(DC.stringToBytes(data)); - } -} \ No newline at end of file + } +} diff --git a/lib/src/Net/Packets/IIPAuthPacket.dart b/lib/src/Net/Packets/IIPAuthPacket.dart index 600b34d..5586ae3 100644 --- a/lib/src/Net/Packets/IIPAuthPacket.dart +++ b/lib/src/Net/Packets/IIPAuthPacket.dart @@ -235,11 +235,14 @@ class IIPAuthPacket localMethod = AuthenticationMethod.values[ ((data[offset] >> 2) & 0x3)]; var encrypt = ((data[offset++] & 0x2) == 0x2); - if (_notEnough(offset, ends, 1)) - return -_dataLengthNeeded; - - - if (remoteMethod == AuthenticationMethod.Credentials + if (remoteMethod == AuthenticationMethod.None) + { + if (localMethod == AuthenticationMethod.None) + { + // do nothing + } + } + else if (remoteMethod == AuthenticationMethod.Credentials || remoteMethod == AuthenticationMethod.Token) { if (localMethod == AuthenticationMethod.None) diff --git a/lib/src/Net/Packets/IIPPacket.dart b/lib/src/Net/Packets/IIPPacket.dart index 5acbfec..732395d 100644 --- a/lib/src/Net/Packets/IIPPacket.dart +++ b/lib/src/Net/Packets/IIPPacket.dart @@ -361,7 +361,8 @@ class IIPPacket resourceId = data.getUint32(offset); offset += 4; } - else if (action == IIPPacketAction.QueryLink) + else if (action == IIPPacketAction.QueryLink + || action == IIPPacketAction.LinkTemplates) { if (_notEnough(offset, ends, 2)) return -_dataLengthNeeded; @@ -420,7 +421,8 @@ class IIPPacket offset += cl; } - else if (action == IIPPacketAction.GetProperty) + else if (action == IIPPacketAction.Listen + || action == IIPPacketAction.Unlisten) { if (_notEnough(offset, ends, 5)) return -_dataLengthNeeded; @@ -429,22 +431,32 @@ class IIPPacket offset += 4; methodIndex = data[offset++]; - } - else if (action == IIPPacketAction.GetPropertyIfModified) - { - if (_notEnough(offset, ends, 9)) - return -_dataLengthNeeded; + // else if (action == IIPPacketAction.GetProperty) + // { + // if (_notEnough(offset, ends, 5)) + // return -_dataLengthNeeded; - resourceId = data.getUint32(offset); - offset += 4; + // resourceId = data.getUint32(offset); + // offset += 4; - methodIndex = data[offset++]; + // methodIndex = data[offset++]; - resourceAge = data.getUint64(offset); - offset += 8; + // } + // else if (action == IIPPacketAction.GetPropertyIfModified) + // { + // if (_notEnough(offset, ends, 9)) + // return -_dataLengthNeeded; - } + // resourceId = data.getUint32(offset); + // offset += 4; + + // methodIndex = data[offset++]; + + // resourceAge = data.getUint64(offset); + // offset += 8; + + // } else if (action == IIPPacketAction.SetProperty) { if (_notEnough(offset, ends, 6)) @@ -567,6 +579,7 @@ class IIPPacket || action == IIPPacketAction.ResourceChildren || action == IIPPacketAction.ResourceParents || action == IIPPacketAction.ResourceHistory + || action == IIPPacketAction.LinkTemplates // Attribute || action == IIPPacketAction.GetAllAttributes || action == IIPPacketAction.GetAttributes) @@ -584,9 +597,9 @@ class IIPPacket offset += cl; } else if (action == IIPPacketAction.InvokeFunctionArrayArguments - || action == IIPPacketAction.InvokeFunctionNamedArguments - || action == IIPPacketAction.GetProperty - || action == IIPPacketAction.GetPropertyIfModified) + || action == IIPPacketAction.InvokeFunctionNamedArguments) + //|| action == IIPPacketAction.GetProperty + //|| action == IIPPacketAction.GetPropertyIfModified) { if (_notEnough(offset, ends, 1)) return -_dataLengthNeeded; @@ -617,7 +630,9 @@ class IIPPacket offset += size; } } - else if (action == IIPPacketAction.SetProperty) + else if (action == IIPPacketAction.SetProperty + || action == IIPPacketAction.Listen + || action == IIPPacketAction.Unlisten) { // nothing to do } diff --git a/lib/src/Net/Packets/IIPPacketAction.dart b/lib/src/Net/Packets/IIPPacketAction.dart index 14c9524..36e240a 100644 --- a/lib/src/Net/Packets/IIPPacketAction.dart +++ b/lib/src/Net/Packets/IIPPacketAction.dart @@ -1,36 +1,36 @@ -class IIPPacketAction -{ - // Request Manage - static const int AttachResource = 0x0; - static const int ReattachResource = 0x1; - static const int DetachResource = 0x2; - static const int CreateResource = 0x3; - static const int DeleteResource = 0x4; - static const int AddChild = 0x5; - static const int RemoveChild = 0x6; - static const int RenameResource = 0x7; +class IIPPacketAction { + // Request Manage + static const int AttachResource = 0x0; + static const int ReattachResource = 0x1; + static const int DetachResource = 0x2; + static const int CreateResource = 0x3; + static const int DeleteResource = 0x4; + static const int AddChild = 0x5; + static const int RemoveChild = 0x6; + static const int RenameResource = 0x7; - // Request Inquire - static const int TemplateFromClassName = 0x8; - static const int TemplateFromClassId = 0x9; - static const int TemplateFromResourceId = 0xA; - static const int QueryLink = 0xB; - static const int ResourceHistory = 0xC; - static const int ResourceChildren = 0xD; - static const int ResourceParents = 0xE; + // Request Inquire + static const int TemplateFromClassName = 0x8; + static const int TemplateFromClassId = 0x9; + static const int TemplateFromResourceId = 0xA; + static const int QueryLink = 0xB; + static const int ResourceHistory = 0xC; + static const int ResourceChildren = 0xD; + static const int ResourceParents = 0xE; + static const int LinkTemplates = 0xF; - // Request Invoke - static const int InvokeFunctionArrayArguments = 0x10; - static const int GetProperty = 0x11; - static const int GetPropertyIfModified = 0x12; - static const int SetProperty = 0x13; - static const int InvokeFunctionNamedArguments = 0x14; + // Request Invoke + static const int InvokeFunctionArrayArguments = 0x10; + static const int InvokeFunctionNamedArguments = 0x11; + static const int Listen = 0x12; + static const int Unlisten = 0x13; + static const int SetProperty = 0x14; - // Request Attribute - static const int GetAllAttributes = 0x18; - static const int UpdateAllAttributes = 0x19; - static const int ClearAllAttributes = 0x1A; - static const int GetAttributes = 0x1B; - static const int UpdateAttributes = 0x1C; - static const int ClearAttributes = 0x1D; -} \ No newline at end of file + // Request Attribute + static const int GetAllAttributes = 0x18; + static const int UpdateAllAttributes = 0x19; + static const int ClearAllAttributes = 0x1A; + static const int GetAttributes = 0x1B; + static const int UpdateAttributes = 0x1C; + static const int ClearAttributes = 0x1D; +} diff --git a/lib/src/Net/Sockets/ISocket.dart b/lib/src/Net/Sockets/ISocket.dart index c08d033..428ed39 100644 --- a/lib/src/Net/Sockets/ISocket.dart +++ b/lib/src/Net/Sockets/ISocket.dart @@ -23,25 +23,28 @@ SOFTWARE. */ import '../../Core/IDestructible.dart'; import '../../Data/DC.dart'; +import '../INetworkReceiver.dart'; import 'IPEndPoint.dart'; import '../../Core/AsyncReply.dart'; import 'SocketState.dart'; -abstract class ISocket extends IDestructible -{ - SocketState get state ; //{ get; } +abstract class ISocket extends IDestructible { + SocketState get state; //{ get; } - //event ISocketReceiveEvent OnReceive; - //event ISocketConnectEvent OnConnect; - //event ISocketCloseEvent OnClose; + //event ISocketReceiveEvent OnReceive; + //event ISocketConnectEvent OnConnect; + //event ISocketCloseEvent OnClose; - //void send(DC message); - void send(DC message, [int offset, int size]); - void close(); - AsyncReply connect(String hostname, int port); - bool begin(); + //void send(DC message); - AsyncReply accept(); - IPEndPoint remoteEndPoint; - IPEndPoint localEndPoint; + INetworkReceiver receiver; + + void send(DC message, [int offset, int size]); + void close(); + AsyncReply connect(String hostname, int port); + bool begin(); + + AsyncReply accept(); + IPEndPoint remoteEndPoint; + IPEndPoint localEndPoint; } diff --git a/lib/src/Net/Sockets/TCPSocket.dart b/lib/src/Net/Sockets/TCPSocket.dart index 55eef07..56e773e 100644 --- a/lib/src/Net/Sockets/TCPSocket.dart +++ b/lib/src/Net/Sockets/TCPSocket.dart @@ -32,24 +32,23 @@ import 'SocketState.dart'; import 'IPEndPoint.dart'; import '../../Core/AsyncReply.dart'; -class TCPSocket extends ISocket -{ - Socket sock; - NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); +class TCPSocket extends ISocket { + Socket sock; + NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); - //bool asyncSending; - bool began = false; + //bool asyncSending; + bool began = false; - SocketState _state = SocketState.Initial; + SocketState _state = SocketState.Initial; - //public event ISocketReceiveEvent OnReceive; - //public event ISocketConnectEvent OnConnect; - //public event ISocketCloseEvent OnClose; - //public event DestroyedEvent OnDestroy; + //public event ISocketReceiveEvent OnReceive; + //public event ISocketConnectEvent OnConnect; + //public event ISocketCloseEvent OnClose; + //public event DestroyedEvent OnDestroy; - //SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs(); + //SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs(); - /* + /* void connected(Task t) { state = SocketState.Established; @@ -58,143 +57,117 @@ class TCPSocket extends ISocket } */ - IPEndPoint _localEP, _remoteEP; + IPEndPoint _localEP, _remoteEP; - bool begin() - { - if (began) - return false; + bool begin() { + if (began) return false; - began = true; + began = true; - _localEP = IPEndPoint(sock.address.rawAddress, sock.port); - _remoteEP = IPEndPoint(sock.remoteAddress.rawAddress, sock.remotePort); - return true; - } + _localEP = IPEndPoint(sock.address.rawAddress, sock.port); + _remoteEP = IPEndPoint(sock.remoteAddress.rawAddress, sock.remotePort); + return true; + } - void dataHandler(List data){ - //print(new String.fromCharCodes(data).trim()); + void dataHandler(List data) { + //print(new String.fromCharCodes(data).trim()); + try { + if (_state == SocketState.Closed || _state == SocketState.Terminated) + return; - try - { - if (_state == SocketState.Closed || _state == SocketState.Terminated) - return; + var dc = new DC.fromList(data); + receiveNetworkBuffer.write(dc, 0, dc.length); + receiver.networkReceive(this, receiveNetworkBuffer); + //emitArgs("receive", [receiveNetworkBuffer]); - var dc = new DC.fromList(data); - receiveNetworkBuffer.write(dc, 0, dc.length); - emitArgs("receive", [receiveNetworkBuffer]); - - } - catch (ex) - { - if (_state != SocketState.Closed)// && !sock.connected) - { - _state = SocketState.Terminated; - close(); - } - - } - - } - - void errorHandler(error, StackTrace trace){ - print(error); - } - - void doneHandler(){ - close(); - sock.destroy(); - } - - AsyncReply connect(String hostname, int port) - { - var rt = new AsyncReply(); - - try - { - _state = SocketState.Connecting; - - Socket.connect(hostname, port).then((s){ - sock = s; - s.listen(dataHandler, - onError: errorHandler, - onDone: doneHandler, - cancelOnError: false); - _state = SocketState.Established; - emitArgs("connect", []); - begin(); - rt.trigger(true); - - }).catchError((ex){ - close(); - rt.triggerError(AsyncException(ErrorType.Management, ExceptionCode.HostNotReachable.index, ex.toString())); - }); - - - } - catch(ex) - { - rt.triggerError(AsyncException(ErrorType.Management, ExceptionCode.HostNotReachable.index, ex.toString())); - } - - return rt; - } - - - - - IPEndPoint get localEndPoint => _localEP; - IPEndPoint get remoteEndPoint => _remoteEP; - - - SocketState get state => _state; - - - TCPSocket.fromSocket(Socket socket) - { - sock = socket; - //if (socket.) - // _state = SocketState.Established; - } - - TCPSocket() - { - // default constructor - } - - void close() - { - if (state != SocketState.Closed && state != SocketState.Terminated) - _state = SocketState.Closed; - - sock?.close(); - - emitArgs("close", []); - } - - - void send(DC message, [int offset, int size]) - { - if (state == SocketState.Established) - sock.add(message.toList()); - } - - - - void destroy() - { + } catch (ex) { + if (_state != SocketState.Closed) // && !sock.connected) + { + _state = SocketState.Terminated; close(); - emitArgs("destroy", [this]); + } + } + } + + void errorHandler(error, StackTrace trace) { + print(error); + } + + void doneHandler() { + close(); + sock.destroy(); + } + + AsyncReply connect(String hostname, int port) { + var rt = new AsyncReply(); + + try { + _state = SocketState.Connecting; + + Socket.connect(hostname, port).then((s) { + sock = s; + s.listen(dataHandler, + onError: errorHandler, onDone: doneHandler, cancelOnError: false); + _state = SocketState.Established; + + //emitArgs("connect", []); + receiver?.networkConnect(this); + + begin(); + rt.trigger(true); + }).catchError((ex) { + close(); + rt.triggerError(AsyncException(ErrorType.Management, + ExceptionCode.HostNotReachable.index, ex.toString())); + }); + } catch (ex) { + rt.triggerError(AsyncException(ErrorType.Management, + ExceptionCode.HostNotReachable.index, ex.toString())); } - AsyncReply accept() - { + return rt; + } + IPEndPoint get localEndPoint => _localEP; + IPEndPoint get remoteEndPoint => _remoteEP; - var reply = new AsyncReply(); - return reply; + SocketState get state => _state; + + TCPSocket.fromSocket(Socket socket) { + sock = socket; + //if (socket.) + // _state = SocketState.Established; + } + + TCPSocket() { + // default constructor + } + + void close() { + if (state != SocketState.Closed && state != SocketState.Terminated) + _state = SocketState.Closed; + + sock?.close(); + + receiver?.networkClose(this); + + //emitArgs("close", []); + } + + void send(DC message, [int offset, int size]) { + if (state == SocketState.Established) sock.add(message.toList()); + } + + void destroy() { + close(); + emitArgs("destroy", [this]); + } + + AsyncReply accept() { + var reply = new AsyncReply(); + return reply; /* ServerSocket.bind(InternetAddress.ANY_IP_V4, 4567).then( @@ -212,5 +185,5 @@ class TCPSocket extends ISocket } */ - } -} \ No newline at end of file + } +} diff --git a/lib/src/Proxy/TemplateGenerator.dart b/lib/src/Proxy/TemplateGenerator.dart new file mode 100644 index 0000000..e7fe427 --- /dev/null +++ b/lib/src/Proxy/TemplateGenerator.dart @@ -0,0 +1,306 @@ +import 'dart:io'; + +import '../Data/DataType.dart'; +import '../Net/IIP/DistributedConnection.dart'; +import '../Resource/Template/TemplateType.dart'; +import '../Resource/Warehouse.dart'; + +import '../Resource/Template/TemplateDataType.dart'; + +import '../Resource/Template/TypeTemplate.dart'; + +class TemplateGenerator { +// static RegExp urlRegex = new RegExp("^(?:([\S]*)://([^/]*)/?)"); + static final _urlRegex = RegExp(r'^(?:([^\s|:]*):\/\/([^\/]*)\/?(.*))'); + + static String generateRecord( + TypeTemplate template, List templates) { + var className = template.className.split('.').last; + var rt = new StringBuffer(); + + rt.writeln("class ${className} extends IRecord {"); + + template.properties.forEach((p) { + var ptTypeName = getTypeName(template, p.valueType, templates); + rt.writeln("${ptTypeName} ${p.name};"); + rt.writeln(); + }); + + rt.writeln(); + + rt.writeln("@override"); + rt.writeln("void deserialize(Map value) {"); + + template.properties.forEach((p) { + rt.writeln("${p.name} = value['${p.name}'];"); + }); + + rt.writeln("}"); + rt.writeln(); + + rt.writeln("@override"); + rt.writeln("Map serialize() {"); + rt.writeln("var rt = Map();"); + + template.properties.forEach((p) { + rt.writeln("rt['${p.name}'] = ${p.name};"); + }); + + rt.writeln("return rt;"); + rt.writeln("}"); + rt.writeln("\r\n}"); + + return rt.toString(); + } + + static String getTypeName(TypeTemplate forTemplate, + TemplateDataType templateDataType, List templates) { + if (templateDataType.type == DataType.Resource) { + if (templateDataType.typeGuid == forTemplate.classId) + return forTemplate.className.split('.').last; + else { + var tmp = + templates.firstWhere((x) => x.classId == templateDataType.typeGuid); + + if (tmp == null) return "dynamic"; // something went wrong + + var cls = tmp.className.split('.'); + var nameSpace = cls.take(cls.length - 1).join('_'); + + return "$nameSpace.${cls.last}"; + } + } else if (templateDataType.type == DataType.ResourceArray) { + if (templateDataType.typeGuid == forTemplate.classId) + return "List<${forTemplate.className.split('.').last}>"; + else { + var tmp = + templates.firstWhere((x) => x.classId == templateDataType.typeGuid); + + if (tmp == null) return "dynamic"; // something went wrong + + var cls = tmp.className.split('.'); + var nameSpace = cls.take(cls.length - 1).join('_'); + + return "List<$nameSpace.${cls.last}>"; + } + } + + var name = ((x) { + switch (x) { + case DataType.Bool: + return "bool"; + case DataType.BoolArray: + return "List"; + case DataType.Char: + return "String"; + case DataType.CharArray: + return "List"; + case DataType.DateTime: + return "DateTime"; + case DataType.DateTimeArray: + return "List"; + case DataType.Decimal: + return "double"; + case DataType.DecimalArray: + return "List"; + case DataType.Float32: + return "List"; + case DataType.Float32Array: + return "List"; + case DataType.Float64: + return "double"; + case DataType.Float64Array: + return "List"; + case DataType.Int16: + return "int"; + case DataType.Int16Array: + return "List"; + case DataType.Int32: + return "int"; + case DataType.Int32Array: + return "List"; + case DataType.Int64: + return "int"; + case DataType.Int64Array: + return "List"; + case DataType.Int8: + return "int"; + case DataType.Int8Array: + return "List"; + case DataType.String: + return "String"; + case DataType.StringArray: + return "List"; + case DataType.Structure: + return "Structure"; + case DataType.StructureArray: + return "List"; + case DataType.UInt16: + return "int"; + case DataType.UInt16Array: + return "List"; + case DataType.UInt32: + return "int"; + case DataType.UInt32Array: + return "List"; + case DataType.UInt64: + return "int"; + case DataType.UInt64Array: + return "List"; + case DataType.UInt8: + return "int"; + case DataType.UInt8Array: + return "List"; + case DataType.VarArray: + return "List"; + case DataType.Void: + return "dynamic"; + default: + return "dynamic"; + } + })(templateDataType.type); + + return name; + } + + static isNullOrEmpty(v) { + return v == null || v == ""; + } + + static Future getTemplate(String url, + [String dir = null, + String username = null, + String password = null]) async { + try { + if (!_urlRegex.hasMatch(url)) throw new Exception("Invalid IIP URL"); + + var path = _urlRegex.allMatches(url).first; + var con = await Warehouse.get( + path[1] + "://" + path[2], + !isNullOrEmpty(username) && !isNullOrEmpty(password) + ? {username: username, password: password} + : null); + + if (con == null) throw new Exception("Can't connect to server"); + + if (isNullOrEmpty(dir)) dir = path[2].replaceAll(":", "_"); + + var templates = await con.getLinkTemplates(path[3]); + + var dstDir = Directory("lib/$dir"); + + if (!dstDir.existsSync()) dstDir.createSync(); + + //Map namesMap = Map(); + + var makeImports = (TypeTemplate skipTemplate) { + var imports = StringBuffer(); + imports.writeln("import 'dart:async';"); + imports.writeln("import 'package:esiur/esiur.dart';"); + // make import names + templates.forEach((tmp) { + if (tmp != skipTemplate) { + var cls = tmp.className.split('.'); + var nameSpace = cls.take(cls.length - 1).join('_'); + imports.writeln( + "import '${tmp.className}.Generated.dart' as $nameSpace;"); + } + }); + + imports.writeln(); + return imports.toString(); + }; + + // make sources + templates.forEach((tmp) { + if (tmp.type == TemplateType.Resource) { + var source = makeImports(tmp) + generateClass(tmp, templates); + var f = File("${dstDir.path}/${tmp.className}.Generated.dart"); + f.writeAsStringSync(source); + } else if (tmp.type == TemplateType.Record) { + var source = makeImports(tmp) + generateRecord(tmp, templates); + var f = File("${dstDir.path}/${tmp.className}.Generated.dart"); + f.writeAsStringSync(source); + } + }); + + // generate info class + var typesFile = + "using System; \r\n namespace Esiur { public static class Generated { public static Type[] Resources {get;} = new Type[] { " + + templates + .where((x) => x.type == TemplateType.Resource) + .map((x) => "typeof(${x.className})") + .join(',') + + " }; \r\n public static Type[] Records { get; } = new Type[] { " + + templates + .where((x) => x.type == TemplateType.Record) + .map((x) => "typeof(${x.className})") + .join(',') + + " }; " + + "\r\n } \r\n}"; + + var f = File("${dstDir.path}/Esiur.Generated.cs"); + f.writeAsStringSync(typesFile); + + return dstDir.path; + } catch (ex) { + //File.WriteAllText("C:\\gen\\gettemplate.err", ex.ToString()); + throw ex; + } + } + + static String generateClass( + TypeTemplate template, List templates) { + var className = template.className.split('.').last; + + var rt = new StringBuffer(); + rt.writeln("class $className extends DistributedResource {"); + + rt.writeln( + "$className(DistributedConnection connection, int instanceId, int age, String link) : super(connection, instanceId, age, link) {"); + + template.events.forEach((e) { + rt.writeln("on('${e.name}', (x) => _${e.name}Controller.add(x));"); + }); + + rt.writeln("}"); + + template.functions.forEach((f) { + var rtTypeName = getTypeName(template, f.returnType, templates); + rt.write("AsyncReply<$rtTypeName> ${f.name}("); + rt.write(f.arguments + .map((x) => getTypeName(template, x.type, templates) + " " + x.name) + .join(",")); + + rt.writeln(") {"); + rt.writeln("var rt = new AsyncReply<$rtTypeName>();"); + rt.writeln( + "invokeByArrayArguments(${f.index}, [${f.arguments.map((x) => x.name).join(',')}])"); + rt.writeln(".then((x) => rt.trigger(x))"); + rt.writeln(".error((x) => rt.triggerError(x))"); + rt.writeln(".chunk((x) => rt.triggerChunk(x));"); + rt.writeln("return rt; }"); + }); + + template.properties.forEach((p) { + var ptTypeName = getTypeName(template, p.valueType, templates); + rt.writeln("${ptTypeName} get ${p.name} { return get(${p.index}); }"); + rt.writeln( + "set ${p.name}(${ptTypeName} value) { set(${p.index}, value); }"); + }); + + template.events.forEach((e) { + var etTypeName = getTypeName(template, e.argumentType, templates); + + rt.writeln( + "final _${e.name}Controller = StreamController<$etTypeName>();"); + rt.writeln("Stream<$etTypeName> get ${e.name} { "); + rt.writeln("return _${e.name}Controller.stream;"); + rt.writeln("}"); + }); + + rt.writeln("\r\n}"); + + return rt.toString(); + } +} diff --git a/lib/src/Resource/IResource.dart b/lib/src/Resource/IResource.dart index cca8f9e..86695f9 100644 --- a/lib/src/Resource/IResource.dart +++ b/lib/src/Resource/IResource.dart @@ -22,25 +22,22 @@ SOFTWARE. */ +import 'package:esiur/src/Resource/Template/TemplateDescriber.dart'; + +import '../Resource/Template/TemplateDescriber.dart'; import '../Core/IDestructible.dart'; import 'ResourceTrigger.dart'; import '../Core/AsyncReply.dart'; import 'Instance.dart'; -abstract class IResource extends IDestructible -{ +abstract class IResource extends IDestructible { + AsyncReply trigger(ResourceTrigger trigger); - AsyncReply trigger(ResourceTrigger trigger); - /* - { - // do nothing - return new AsyncReply.ready(true); - } - - destroy() - { - // Destroyed - } - */ - Instance instance; -} \ No newline at end of file + Instance instance; + + invoke(String name, List arguments); + setProperty(String name, value); + getProperty(String name); + + TemplateDescriber get template; +} diff --git a/lib/src/Resource/Instance.dart b/lib/src/Resource/Instance.dart index d2f3cc7..80df889 100644 --- a/lib/src/Resource/Instance.dart +++ b/lib/src/Resource/Instance.dart @@ -11,7 +11,7 @@ import '../Core/IEventHandler.dart'; import '../Security/Permissions/Ruling.dart'; import '../Security/Permissions/IPermissionsManager.dart'; import '../Security/Permissions/ActionType.dart'; -import './Template/ResourceTemplate.dart'; +import 'Template/TypeTemplate.dart'; import './Template/PropertyTemplate.dart'; import './Template/FunctionTemplate.dart'; import './Template/EventTemplate.dart'; @@ -30,7 +30,7 @@ class Instance extends IEventHandler IStore _store; AutoList _parents; //bool inherit; - ResourceTemplate _template; + TypeTemplate _template; AutoList _managers; @@ -547,7 +547,7 @@ class Instance extends IEventHandler /// /// Resource template describes the properties, functions and events of the resource. /// - ResourceTemplate get template => _template; + TypeTemplate get template => _template; /// /// Check for permission. @@ -583,7 +583,7 @@ class Instance extends IEventHandler /// Name of the instance. /// Resource to manage. /// Store responsible for the resource. - Instance(int id, String name, IResource resource, IStore store, [ResourceTemplate customTemplate = null, int age = 0]) + Instance(int id, String name, IResource resource, IStore store, [TypeTemplate customTemplate = null, int age = 0]) { _store = store; _resource = resource; diff --git a/lib/src/Resource/Template/ArgumentTemplate.dart b/lib/src/Resource/Template/ArgumentTemplate.dart new file mode 100644 index 0000000..4fc6359 --- /dev/null +++ b/lib/src/Resource/Template/ArgumentTemplate.dart @@ -0,0 +1,34 @@ +import '../../Data/DC.dart'; +import '../../Data/BinaryList.dart'; +import "../../Data/ParseResult.dart"; +import './TemplateDataType.dart'; + +class ArgumentTemplate +{ + String name; + + TemplateDataType type; + + static ParseResult parse(DC data, int offset) + { + var cs = data[offset++]; + var name = data.getString(offset, cs); + offset += cs; + var tdr = TemplateDataType.parse(data, offset); + + return ParseResult(cs + 1 + tdr.size, ArgumentTemplate(name, tdr.value)); + } + + ArgumentTemplate(this.name, this.type); + + DC compose() + { + var name = DC.stringToBytes(this.name); + + return new BinaryList() + .addUint8(name.length) + .addDC(name) + .addDC(type.compose()) + .toDC(); + } + } diff --git a/lib/src/Resource/Template/EventTemplate.dart b/lib/src/Resource/Template/EventTemplate.dart index b32eed5..f36af58 100644 --- a/lib/src/Resource/Template/EventTemplate.dart +++ b/lib/src/Resource/Template/EventTemplate.dart @@ -1,45 +1,39 @@ - import 'MemberTemplate.dart'; import '../../Data/DC.dart'; import '../../Data/BinaryList.dart'; -import 'ResourceTemplate.dart'; +import 'TypeTemplate.dart'; import 'MemberType.dart'; +import 'TemplateDataType.dart'; -class EventTemplate extends MemberTemplate -{ - +class EventTemplate extends MemberTemplate { String expansion; + bool listenable; + TemplateDataType argumentType; + DC compose() { + var name = super.compose(); - DC compose() - { - var name = super.compose(); - - if (expansion != null) - { - var exp = DC.stringToBytes(expansion); - return new BinaryList() - .addUint8(0x50) - .addUint8(name.length) - .addDC(name) - .addInt32(exp.length) - .addDC(exp) - .toDC(); - } - else - { - return new BinaryList() - .addUint8(0x40) - .addUint8(name.length) - .addDC(name) - .toDC(); - } + if (expansion != null) { + var exp = DC.stringToBytes(expansion); + return new BinaryList() + .addUint8(listenable ? 0x58 : 0x50) + .addUint8(name.length) + .addDC(name) + .addDC(argumentType.compose()) + .addInt32(exp.length) + .addDC(exp) + .toDC(); + } else { + return new BinaryList() + .addUint8(listenable ? 0x48 : 0x40) + .addUint8(name.length) + .addDC(name) + .addDC(argumentType.compose()) + .toDC(); + } } - - EventTemplate(ResourceTemplate template, int index, String name, String expansion) - : super(template, MemberType.Property, index, name) - { - this.expansion = expansion; - } + EventTemplate(TypeTemplate template, int index, String name, + this.argumentType, this.expansion, this.listenable) + : super(template, MemberType.Property, index, name) {} } diff --git a/lib/src/Resource/Template/FunctionTemplate.dart b/lib/src/Resource/Template/FunctionTemplate.dart index 967023b..12938a8 100644 --- a/lib/src/Resource/Template/FunctionTemplate.dart +++ b/lib/src/Resource/Template/FunctionTemplate.dart @@ -1,42 +1,49 @@ import 'MemberTemplate.dart'; import '../../Data/DC.dart'; import '../../Data/BinaryList.dart'; -import 'ResourceTemplate.dart'; +import 'TypeTemplate.dart'; import 'MemberType.dart'; +import 'ArgumentTemplate.dart'; +import 'TemplateDataType.dart'; -class FunctionTemplate extends MemberTemplate -{ +class FunctionTemplate extends MemberTemplate { + String expansion; + bool isVoid; - String expansion; - bool isVoid; - + TemplateDataType returnType; + List arguments; - DC compose() - { - var name = super.compose(); + DC compose() { - if (expansion != null) - { - var exp = DC.stringToBytes(expansion); - return new BinaryList().addUint8((0x10 | (isVoid ? 0x8 : 0x0))) - .addUint8(name.length) - .addDC(name) - .addInt32(exp.length) - .addDC(exp) - .toDC(); - } - else - return new BinaryList().addUint8((isVoid ? 0x8 : 0x0)) - .addUint8(name.length) - .addDC(name) - .toDC(); - } + var name = super.compose(); + + var bl = new BinaryList() + .addUint8(name.length) + .addDC(name) + .addDC(returnType.compose()) + .addUint8(arguments.length); + + for (var i = 0; i < arguments.length; i++) + bl.addDC(arguments[i].compose()); - FunctionTemplate(ResourceTemplate template, int index, String name, bool isVoid, String expansion) - :super(template, MemberType.Property, index, name) - { - this.isVoid = isVoid; - this.expansion = expansion; - } + if (expansion != null) + { + var exp = DC.stringToBytes(expansion); + bl.addInt32(exp.length) + .addDC(exp); + bl.insertUint8(0, 0x10); + } + else + bl.insertUint8(0, 0x0); + + return bl.toDC(); + } + + FunctionTemplate(TypeTemplate template, int index, String name, + this.arguments, this.returnType, String expansion) + : super(template, MemberType.Property, index, name) { + this.isVoid = isVoid; + this.expansion = expansion; + } } diff --git a/lib/src/Resource/Template/MemberTemplate.dart b/lib/src/Resource/Template/MemberTemplate.dart index 1a21d3a..2d03fba 100644 --- a/lib/src/Resource/Template/MemberTemplate.dart +++ b/lib/src/Resource/Template/MemberTemplate.dart @@ -1,7 +1,7 @@ import 'MemberType.dart'; import '../../Data/DC.dart'; -import './ResourceTemplate.dart'; +import 'TypeTemplate.dart'; class MemberTemplate { @@ -10,14 +10,14 @@ class MemberTemplate String get name => _name; MemberType get type => _type; - ResourceTemplate _template; + TypeTemplate _template; String _name; MemberType _type; int _index; - ResourceTemplate get template => _template; + TypeTemplate get template => _template; - MemberTemplate(ResourceTemplate template, MemberType type, int index, String name) + MemberTemplate(TypeTemplate template, MemberType type, int index, String name) { this._template = template; this._type = type; diff --git a/lib/src/Resource/Template/PropertyTemplate.dart b/lib/src/Resource/Template/PropertyTemplate.dart index c5b3dcf..66bfc5d 100644 --- a/lib/src/Resource/Template/PropertyTemplate.dart +++ b/lib/src/Resource/Template/PropertyTemplate.dart @@ -1,80 +1,76 @@ +import 'TemplateDataType.dart'; import 'MemberTemplate.dart'; import '../../Data/DC.dart'; import '../../Data/BinaryList.dart'; -import 'ResourceTemplate.dart'; +import 'TypeTemplate.dart'; import 'MemberType.dart'; -import 'PropertyPermission.dart'; import '../StorageMode.dart'; -class PropertyTemplate extends MemberTemplate -{ - +class PropertyTemplate extends MemberTemplate { + TemplateDataType valueType; - int permission; + int permission; + int storage; - int storage; + String readExpansion; - String readExpansion; + String writeExpansion; - String writeExpansion; + DC compose() { + var name = super.compose(); + var pv = ((permission) << 1) | (storage == StorageMode.Recordable ? 1 : 0); - DC compose() - { - var name = super.compose(); - var pv = ((permission) << 1) | (storage == StorageMode.Recordable ? 1 : 0); + if (writeExpansion != null && readExpansion != null) { + var rexp = DC.stringToBytes(readExpansion); + var wexp = DC.stringToBytes(writeExpansion); + return new BinaryList() + .addUint8(0x38 | pv) + .addUint8(name.length) + .addDC(name) + .addDC(valueType.compose()) + .addInt32(wexp.length) + .addDC(wexp) + .addInt32(rexp.length) + .addDC(rexp) + .toDC(); + } else if (writeExpansion != null) { + var wexp = DC.stringToBytes(writeExpansion); + return new BinaryList() + .addUint8(0x30 | pv) + .addUint8(name.length) + .addDC(name) + .addDC(valueType.compose()) + .addInt32(wexp.length) + .addDC(wexp) + .toDC(); + } else if (readExpansion != null) { + var rexp = DC.stringToBytes(readExpansion); + return new BinaryList() + .addUint8(0x28 | pv) + .addUint8(name.length) + .addDC(name) + .addDC(valueType.compose()) + .addInt32(rexp.length) + .addDC(rexp) + .toDC(); + } else + return new BinaryList() + .addUint8(0x20 | pv) + .addUint8(name.length) + .addDC(name) + .addDC(valueType.compose()) + .toDC(); + } - if (writeExpansion != null && readExpansion != null) - { - var rexp = DC.stringToBytes(readExpansion); - var wexp = DC.stringToBytes(writeExpansion); - return new BinaryList() - .addUint8(0x38 | pv) - .addUint8(name.length) - .addDC(name) - .addInt32(wexp.length) - .addDC(wexp) - .addInt32(rexp.length) - .addDC(rexp) - .toDC(); - } - else if (writeExpansion != null) - { - var wexp = DC.stringToBytes(writeExpansion); - return new BinaryList() - .addUint8(0x30 | pv) - .addUint8(name.length) - .addDC(name) - .addInt32(wexp.length) - .addDC(wexp) - .toDC(); - } - else if (readExpansion != null) - { - var rexp = DC.stringToBytes(readExpansion); - return new BinaryList() - .addUint8(0x28 | pv) - .addUint8(name.length) - .addDC(name) - .addInt32(rexp.length) - .addDC(rexp) - .toDC(); - } - else - return new BinaryList() - .addUint8(0x20 | pv) - .addUint8(name.length) - .addDC(name) - .toDC(); - } - - PropertyTemplate(ResourceTemplate template, int index, String name, String read, String write, int storage) - :super(template, MemberType.Property, index, name) - { - //this.Recordable = recordable; - this.storage = storage; - this.readExpansion = read; - this.writeExpansion = write; - } -} \ No newline at end of file + PropertyTemplate(TypeTemplate template, int index, String name, + TemplateDataType valueType, String read, String write, int storage) + : super(template, MemberType.Property, index, name) { + //this.Recordable = recordable; + this.storage = storage; + this.readExpansion = read; + this.writeExpansion = write; + this.valueType = valueType; + } +} diff --git a/lib/src/Resource/Template/ResourceTemplate.dart b/lib/src/Resource/Template/ResourceTemplate.dart deleted file mode 100644 index e72705c..0000000 --- a/lib/src/Resource/Template/ResourceTemplate.dart +++ /dev/null @@ -1,330 +0,0 @@ - -import './MemberTemplate.dart'; -import '../../Data/Guid.dart'; -import '../../Data/DC.dart'; -import './EventTemplate.dart'; -import './PropertyTemplate.dart'; -import './FunctionTemplate.dart'; -import '../StorageMode.dart'; - -class ResourceTemplate -{ - Guid _classId; - String _className; - List _members = new List(); - List _functions = new List(); - List _events = new List(); - List _properties = new List(); - int _version; - //bool isReady; - - DC _content; - - DC get content => _content; - -/* - MemberTemplate getMemberTemplate(MemberInfo member) - { - if (member is MethodInfo) - return getFunctionTemplate(member.Name); - else if (member is EventInfo) - return getEventTemplate(member.Name); - else if (member is PropertyInfo) - return getPropertyTemplate(member.Name); - else - return null; - } - */ - - EventTemplate getEventTemplateByName(String eventName) - { - for (var i in _events) - if (i.name == eventName) - return i; - return null; - } - - EventTemplate getEventTemplateByIndex(int index) - { - for (var i in _events) - if (i.index == index) - return i; - return null; - } - - FunctionTemplate getFunctionTemplateByName(String functionName) - { - for (var i in _functions) - if (i.name == functionName) - return i; - return null; - } - - FunctionTemplate getFunctionTemplateByIndex(int index) - { - for (var i in _functions) - if (i.index == index) - return i; - return null; - } - - PropertyTemplate getPropertyTemplateByIndex(int index) - { - for (var i in _properties) - if (i.index == index) - return i; - return null; - } - - PropertyTemplate getPropertyTemplateByName(String propertyName) - { - for (var i in _properties) - if (i.name == propertyName) - return i; - return null; - } - - Guid get classId => _classId; - - String get className => _className; - - List get methods => _members; - - List get functions => _functions; - - List get events => _events; - - List get properties => _properties; - - ResourceTemplate() - { - - } - - - ResourceTemplate.fromType(Type type) - { - - } - -/* - ResourceTemplate(Type type) - { - - type = ResourceProxy.GetBaseType(type); - - // set guid - - var typeName = Encoding.UTF8.GetBytes(type.FullName); - var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16); - - classId = new Guid(hash); - className = type.FullName; - - -#if NETSTANDARD1_5 - PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - -#else - PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); -#endif - - //byte currentIndex = 0; - - byte i = 0; - - foreach (var pi in propsInfo) - { - var ps = (ResourceProperty[])pi.GetCustomAttributes(typeof(ResourceProperty), true); - if (ps.Length > 0) - { - var pt = new PropertyTemplate(this, i++, pi.Name, ps[0].ReadExpansion, ps[0].WriteExpansion, ps[0].Storage); - pt.Info = pi; - properties.Add(pt); - } - } - - i = 0; - - foreach (var ei in eventsInfo) - { - var es = (ResourceEvent[])ei.GetCustomAttributes(typeof(ResourceEvent), true); - if (es.Length > 0) - { - var et = new EventTemplate(this, i++, ei.Name, es[0].Expansion); - events.Add(et); - } - } - - i = 0; - foreach (MethodInfo mi in methodsInfo) - { - var fs = (ResourceFunction[])mi.GetCustomAttributes(typeof(ResourceFunction), true); - if (fs.Length > 0) - { - var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void), fs[0].Expansion); - functions.Add(ft); - } - } - - // append signals - for (i = 0; i < events.Count; i++) - members.Add(events[i]); - // append slots - for (i = 0; i < functions.Count; i++) - members.Add(functions[i]); - // append properties - for (i = 0; i < properties.Count; i++) - members.Add(properties[i]); - - // bake it binarily - var b = new BinaryList(); - b.AddGuid(classId) - .AddUInt8((byte)className.Length) - .AddString(className) - .AddInt32(version) - .AddUInt16((ushort)members.Count); - - - foreach (var ft in functions) - b.AddUInt8Array(ft.Compose()); - foreach (var pt in properties) - b.AddUInt8Array(pt.Compose()); - foreach (var et in events) - b.AddUInt8Array(et.Compose()); - - content = b.ToArray(); - } - -*/ - - - ResourceTemplate.parse(DC data, [int offset = 0, int contentLength]) - { - - // cool Dart feature - contentLength ??= data.length; - - - int ends = offset + contentLength; - - int oOffset = offset; - - // start parsing... - - //var od = new ResourceTemplate(); - _content = data.clip(offset, contentLength); - - _classId = data.getGuid(offset); - offset += 16; - _className = data.getString(offset + 1, data[offset]); - offset += data[offset] + 1; - - _version = data.getInt32(offset); - offset += 4; - - var methodsCount = data.getUint16(offset); - offset += 2; - - var functionIndex = 0; - var propertyIndex = 0; - var eventIndex = 0; - - for (int i = 0; i < methodsCount; i++) - { - var type = data[offset] >> 5; - - if (type == 0) // function - { - String expansion = null; - var hasExpansion = ((data[offset] & 0x10) == 0x10); - var isVoid = ((data[offset++] & 0x08) == 0x08); - var name = data.getString(offset + 1, data[offset]); - offset += data[offset] + 1; - - if (hasExpansion) // expansion ? - { - var cs = data.getUint32(offset); - offset += 4; - expansion = data.getString(offset, cs); - offset += cs; - } - - var ft = new FunctionTemplate(this, functionIndex++, name, isVoid, expansion); - - _functions.add(ft); - } - else if (type == 1) // property - { - - String readExpansion = null, writeExpansion = null; - - var hasReadExpansion = ((data[offset] & 0x8) == 0x8); - var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); - var recordable = ((data[offset] & 1) == 1); - var permission = (data[offset++] >> 1) & 0x3; - var name = data.getString(offset + 1, data[offset]); - - offset += data[offset] + 1; - - if (hasReadExpansion) // expansion ? - { - var cs = data.getUint32(offset); - offset += 4; - readExpansion = data.getString(offset, cs); - offset += cs; - } - - if (hasWriteExpansion) // expansion ? - { - var cs = data.getUint32(offset); - offset += 4; - writeExpansion = data.getString(offset, cs); - offset += cs; - } - - var pt = new PropertyTemplate(this, propertyIndex++, name, readExpansion, writeExpansion, recordable ? StorageMode.Recordable : StorageMode.Volatile); - - _properties.add(pt); - } - else if (type == 2) // Event - { - - String expansion = null; - var hasExpansion = ((data[offset++] & 0x10) == 0x10); - - var name = data.getString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]); - offset += data[offset] + 1; - - if (hasExpansion) // expansion ? - { - var cs = data.getUint32(offset); - offset += 4; - expansion = data.getString(offset, cs); - offset += cs; - } - - var et = new EventTemplate(this, eventIndex++, name, expansion); - - _events.add(et); - - } - } - - // append signals - for (int i = 0; i < _events.length; i++) - _members.add(_events[i]); - // append slots - for (int i = 0; i < _functions.length; i++) - _members.add(_functions[i]); - // append properties - for (int i = 0; i < _properties.length; i++) - _members.add(_properties[i]); - - } -} - diff --git a/lib/src/Resource/Template/TemplateDataType.dart b/lib/src/Resource/Template/TemplateDataType.dart new file mode 100644 index 0000000..53aabf3 --- /dev/null +++ b/lib/src/Resource/Template/TemplateDataType.dart @@ -0,0 +1,120 @@ +import 'dart:ffi'; + +import '../../Data/IRecord.dart'; +import '../../Resource/IResource.dart'; + +import '../../Data/Structure.dart'; + +import '../../Data/ParseResult.dart'; + +import '../../Data/DataType.dart'; +import '../../Data/Guid.dart'; +import '../../Data/DC.dart'; +import '../../Data/BinaryList.dart'; +import 'TypeTemplate.dart'; +import '../../Resource/Warehouse.dart'; +import 'TemplateType.dart'; + +class TemplateDataType { + int type; + TypeTemplate get typeTemplate => + typeGuid == null ? null : Warehouse.getTemplateByClassId(typeGuid); + + Guid typeGuid; + +// @TODO: implement fromType + TemplateDataType.fromType(type, bool isArray) { + int dt; + + if (type == null) + dt = DataType.Void; + else if (type is int) { + dt = type; + } else if (type == bool) + dt = DataType.Bool; + else if (type == Uint8) + dt = DataType.UInt8; + else if (type == Int8) + dt = DataType.Int8; + else if (type == Uint16) + dt = DataType.UInt16; + else if (type == Int16) + dt = DataType.Int16; + else if (type == Uint32) + dt = DataType.UInt32; + else if (type == Int32) + dt = DataType.Int32; + else if (type == Uint64) + dt = DataType.UInt64; + else if (type == Int64 || type == int) + dt = DataType.Int64; + else if (type == Float) + dt = DataType.Float32; + else if (type == Double) + dt = DataType.Float64; + else if (type == String) + dt = DataType.String; + else if (type == DateTime) + dt = DataType.DateTime; + else if (type == Structure) + dt = DataType.Structure; + else if (type == IResource) // Dynamic resource (unspecified type) + dt = DataType.Void; + else if (type == IRecord) // Dynamic record (unspecified type) + dt = DataType.Void; + else { + var template = Warehouse.getTemplateByType(type); + + if (template != null) { + typeGuid = template.classId; + dt = template.type == TemplateType.Resource + ? DataType.Resource + : DataType.Record; + } else + dt = DataType.Void; + + // if (template) + // try { + // var ins = Warehouse.createInstance(type); + // if (ins is IResource) { + // typeGuid = TypeTemplate.getTypeGuid(ins.template.nameSpace); + // } else if (ins is IRecord) { + // typeGuid = TypeTemplate.getTypeGuid(ins.template.nameSpace); + // } else { + // dt = DataType.Void; + // } + // } catch (ex) { + // dt = DataType.Void; + // } + } + + if (isArray) dt = dt | 0x80; + + this.type = dt; + } + + DC compose() { + if (type == DataType.Resource || + type == DataType.ResourceArray || + type == DataType.Record || + type == DataType.RecordArray) { + return BinaryList().addUint8(type).addDC(typeGuid.value).toDC(); + } else + return DC.fromList([type]); + } + + TemplateDataType(this.type, this.typeGuid); + + static ParseResult parse(DC data, int offset) { + var type = data[offset++]; + if (type == DataType.Resource || + type == DataType.ResourceArray || + type == DataType.Record || + type == DataType.RecordArray) { + var guid = data.getGuid(offset); + return ParseResult( + 17, new TemplateDataType(type, guid)); + } else + return ParseResult(1, new TemplateDataType(type, null)); + } +} diff --git a/lib/src/Resource/Template/TemplateDescriber.dart b/lib/src/Resource/Template/TemplateDescriber.dart new file mode 100644 index 0000000..41009b1 --- /dev/null +++ b/lib/src/Resource/Template/TemplateDescriber.dart @@ -0,0 +1,81 @@ +import '../../Data/DataType.dart'; + +class TemplateDescriber { + final List properties; + final List events; + final List functions; + final String nameSpace; + + TemplateDescriber(this.nameSpace, + {this.properties, this.functions, this.events}); +} + +// class Property { +// T _value; + +// Function(T) _setter; +// Function() _getter; +// Function(Property) notifier; + +// IResource resource; + +// operator <<(other) { +// set(other); +// } + +// void set(T value) { +// if (_setter != null) +// _setter(value); +// else +// _value = value; + +// if (notifier != null) notifier.call(this); +// } + +// T get() { +// if (_getter != null) +// return _getter(); +// else +// return _value; +// } + +// Property([Function() getter, Function(T) setter]) {} +// } + +class Prop { + final String name; + final Type type; + final bool isArray; + final String readAnnotation; + final String writeAnnotation; + Prop(this.name, this.type, this.isArray, [this.readAnnotation = null, this.writeAnnotation = null]); +} + +class Evt { + final String name; + final bool listenable; + final Type type; + final bool isArray; + final String annotation; + + Evt(this.name, this.type, this.isArray, [this.listenable = false, this.annotation]); +} + +class Func { + final String name; + final Type returnType; + final List argsType; + final bool isArray; + final String annotation; + + Func(this.name, this.returnType, this.argsType, this.isArray, + [this.annotation = null]); +} + +class Arg { + final String name; + final Type type; + final bool isArray; + + Arg(this.name, this.type, this.isArray); +} diff --git a/lib/src/Resource/Template/TemplateType.dart b/lib/src/Resource/Template/TemplateType.dart new file mode 100644 index 0000000..7dbc6bc --- /dev/null +++ b/lib/src/Resource/Template/TemplateType.dart @@ -0,0 +1,6 @@ +enum TemplateType { + Unspecified, + Resource, + Record, + Wrapper, +} diff --git a/lib/src/Resource/Template/TypeTemplate.dart b/lib/src/Resource/Template/TypeTemplate.dart new file mode 100644 index 0000000..c3d66f0 --- /dev/null +++ b/lib/src/Resource/Template/TypeTemplate.dart @@ -0,0 +1,550 @@ +import 'dart:ffi'; + +import '../../Data/BinaryList.dart'; +import '../../Security/Integrity/SHA256.dart'; + +import '../../Data/IRecord.dart'; +import '../IResource.dart'; +import '../Warehouse.dart'; +import './TemplateDescriber.dart'; + +import './MemberTemplate.dart'; +import '../../Data/Guid.dart'; +import '../../Data/DC.dart'; +import './EventTemplate.dart'; +import './PropertyTemplate.dart'; +import './FunctionTemplate.dart'; +import '../StorageMode.dart'; +import 'ArgumentTemplate.dart'; +import 'TemplateDataType.dart'; +import 'TemplateType.dart'; + +class TypeTemplate { + Guid _classId; + String _className; + List _members = []; + List _functions = []; + List _events = []; + List _properties = []; + int _version; + //bool isReady; + + TemplateType _templateType; + + DC _content; + + DC get content => _content; + + TemplateType get type => _templateType; + + Type _definedType; + + Type get definedType => _definedType; +/* + MemberTemplate getMemberTemplate(MemberInfo member) + { + if (member is MethodInfo) + return getFunctionTemplate(member.Name); + else if (member is EventInfo) + return getEventTemplate(member.Name); + else if (member is PropertyInfo) + return getPropertyTemplate(member.Name); + else + return null; + } + */ + +//@TODO: implement + static List getDependencies(TypeTemplate template) => + []; + + EventTemplate getEventTemplateByName(String eventName) { + for (var i in _events) if (i.name == eventName) return i; + return null; + } + + EventTemplate getEventTemplateByIndex(int index) { + for (var i in _events) if (i.index == index) return i; + return null; + } + + FunctionTemplate getFunctionTemplateByName(String functionName) { + for (var i in _functions) if (i.name == functionName) return i; + return null; + } + + FunctionTemplate getFunctionTemplateByIndex(int index) { + for (var i in _functions) if (i.index == index) return i; + return null; + } + + PropertyTemplate getPropertyTemplateByIndex(int index) { + for (var i in _properties) if (i.index == index) return i; + return null; + } + + PropertyTemplate getPropertyTemplateByName(String propertyName) { + for (var i in _properties) if (i.name == propertyName) return i; + return null; + } + + static Guid getTypeGuid(String typeName) { + var tn = DC.stringToBytes(typeName); + var hash = SHA256.compute(tn).clip(0, 16); + return new Guid(hash); + } + + Guid get classId => _classId; + + String get className => _className; + + List get methods => _members; + + List get functions => _functions; + + List get events => _events; + + List get properties => _properties; + + TypeTemplate.fromType(Type type, [bool addToWarehouse, bool isWrapper]) { + var instance = Warehouse.createInstance(type); + + if (instance is IRecord) + _templateType = TemplateType.Record; + else if (instance is IResource) + _templateType = TemplateType.Resource; + else + throw new Exception("Type is neither a resource nor a record."); + + TemplateDescriber describer = instance.template; + + _definedType = type; + + _className = describer.nameSpace; + + // set guid + _classId = getTypeGuid(_className); + + if (addToWarehouse) Warehouse.putTemplate(this); + // _templates.add(template.classId, template); + + for (var i = 0; i < describer.properties.length; i++) { + var pi = describer.properties[i]; + var pt = PropertyTemplate( + this, + i, + pi.name, + TemplateDataType.fromType(pi.type, pi.isArray), + pi.readAnnotation, + pi.writeAnnotation, + 0); + properties.add(pt); + } + + for (var i = 0; i < describer.functions.length; i++) { + var fi = describer.functions[i]; + + List args = fi.argsType.map((arg) => ArgumentTemplate( + arg.name, TemplateDataType.fromType(arg.type, arg.isArray))); + + var ft = FunctionTemplate(this, i, fi.name, args, + TemplateDataType.fromType(fi.returnType, fi.isArray), fi.annotation); + + functions.add(ft); + } + + for (var i = 0; i < describer.events.length; i++) { + var ei = describer.events[i]; + + var et = new EventTemplate( + this, + i, + ei.name, + TemplateDataType.fromType(ei.type, ei.isArray), + ei.annotation, + ei.listenable); + + events.add(et); + } + + // append signals + events.forEach(_members.add); + // append slots + functions.forEach(_members.add); +// append properties + properties.forEach(_members.add); + + // bake it binarily + var b = new BinaryList(); + b + .addUint8(_templateType.index) + .addGuid(classId) + .addUint8(className.length) + .addString(className) + .addInt32(_version) + .addUint16(_members.length); + + functions.forEach((ft) => b.addDC(ft.compose())); + properties.forEach((pt) => b.addDC(pt.compose())); + events.forEach((et) => b.addDC(et.compose())); + + _content = b.toDC(); + } + + // static Guid getTypeGuid(Type type) => getTypeGuid(type.toString()); + + // static Guid getTypeGuid(String typeName) + // { + // var tn = Encoding.UTF8.GetBytes(typeName); + // var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16); + + // return new Guid(hash); + // } + + // static Type GetElementType(Type type) => type switch + // { + // { IsArray: true } => type.GetElementType(), + // { IsEnum: true } => type.GetEnumUnderlyingType(), + // (_) => type + // }; + + // static TypeTemplate[] GetRuntimeTypes(TypeTemplate template) + // { + + // List list = []; + + // list.add(template); + + // var getRuntimeTypes = null; + + // getRuntimeTypes = (TypeTemplate tmp, List bag) + // { + // if (template.resourceType == null) + // return; + + // // functions + // tmp.functions.foreach((f){ + + // var frtt = Warehouse.GetTemplate(getElementType(f.MethodInfo.ReturnType)); + // if (frtt != null) + // { + // if (!bag.Contains(frtt)) + // { + // list.Add(frtt); + // getRuntimeTypes(frtt, bag); + // } + // } + + // var args = f.MethodInfo.GetParameters(); + + // for(var i = 0; i < args.Length - 1; i++) + // { + // var fpt = Warehouse.GetTemplate(GetElementType(args[i].ParameterType)); + // if (fpt != null) + // { + // if (!bag.Contains(fpt)) + // { + // bag.Add(fpt); + // getRuntimeTypes(fpt, bag); + // } + // } + // } + + // // skip DistributedConnection argument + // if (args.Length > 0) + // { + // var last = args.Last(); + // if (last.ParameterType != typeof(DistributedConnection)) + // { + // var fpt = Warehouse.GetTemplate(GetElementType(last.ParameterType)); + // if (fpt != null) + // { + // if (!bag.Contains(fpt)) + // { + // bag.Add(fpt); + // getRuntimeTypes(fpt, bag); + // } + // } + // } + // } + + // }); + + // // properties + // foreach (var p in tmp.properties) + // { + // var pt = Warehouse.GetTemplate(GetElementType(p.PropertyInfo.PropertyType)); + // if (pt != null) + // { + // if (!bag.Contains(pt)) + // { + // bag.Add(pt); + // getRuntimeTypes(pt, bag); + // } + // } + // } + + // // events + // foreach (var e in tmp.events) + // { + // var et = Warehouse.GetTemplate(GetElementType(e.EventInfo.EventHandlerType.GenericTypeArguments[0])); + + // if (et != null) + // { + // if (!bag.Contains(et)) + // { + // bag.Add(et); + // getRuntimeTypes(et, bag); + // } + // } + // } + // }; + + // getRuntimeTypes(template, list); + // return list.ToArray(); + // } + + // @TODO Create template from type + // TypeTemplate.fromType(Type type) { + + // } + +/* + TypeTemplate(Type type) + { + + type = ResourceProxy.GetBaseType(type); + + // set guid + + var typeName = Encoding.UTF8.GetBytes(type.FullName); + var hash = SHA256.Create().ComputeHash(typeName).Clip(0, 16); + + classId = new Guid(hash); + className = type.FullName; + + +#if NETSTANDARD1_5 + PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + +#else + PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); +#endif + + //byte currentIndex = 0; + + byte i = 0; + + foreach (var pi in propsInfo) + { + var ps = (ResourceProperty[])pi.GetCustomAttributes(typeof(ResourceProperty), true); + if (ps.Length > 0) + { + var pt = new PropertyTemplate(this, i++, pi.Name, ps[0].ReadExpansion, ps[0].WriteExpansion, ps[0].Storage); + pt.Info = pi; + properties.Add(pt); + } + } + + i = 0; + + foreach (var ei in eventsInfo) + { + var es = (ResourceEvent[])ei.GetCustomAttributes(typeof(ResourceEvent), true); + if (es.Length > 0) + { + var et = new EventTemplate(this, i++, ei.Name, es[0].Expansion); + events.Add(et); + } + } + + i = 0; + foreach (MethodInfo mi in methodsInfo) + { + var fs = (ResourceFunction[])mi.GetCustomAttributes(typeof(ResourceFunction), true); + if (fs.Length > 0) + { + var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void), fs[0].Expansion); + functions.Add(ft); + } + } + + // append signals + for (i = 0; i < events.Count; i++) + members.Add(events[i]); + // append slots + for (i = 0; i < functions.Count; i++) + members.Add(functions[i]); + // append properties + for (i = 0; i < properties.Count; i++) + members.Add(properties[i]); + + // bake it binarily + var b = new BinaryList(); + b.AddGuid(classId) + .AddUInt8((byte)className.Length) + .AddString(className) + .AddInt32(version) + .AddUInt16((ushort)members.Count); + + + foreach (var ft in functions) + b.AddUInt8Array(ft.Compose()); + foreach (var pt in properties) + b.AddUInt8Array(pt.Compose()); + foreach (var et in events) + b.AddUInt8Array(et.Compose()); + + content = b.ToArray(); + } + +*/ + + TypeTemplate.parse(DC data, [int offset = 0, int contentLength]) { + // cool Dart feature + contentLength ??= data.length; + + int ends = offset + contentLength; + + int oOffset = offset; + + // start parsing... + + //var od = new TypeTemplate(); + _content = data.clip(offset, contentLength); + + _templateType = TemplateType.values[data.getUint8(offset++)]; + + _classId = data.getGuid(offset); + offset += 16; + _className = data.getString(offset + 1, data[offset]); + offset += data[offset] + 1; + + _version = data.getInt32(offset); + offset += 4; + + var methodsCount = data.getUint16(offset); + offset += 2; + + var functionIndex = 0; + var propertyIndex = 0; + var eventIndex = 0; + + for (int i = 0; i < methodsCount; i++) { + var type = data[offset] >> 5; + + if (type == 0) // function + { + String expansion = null; + var hasExpansion = ((data[offset++] & 0x10) == 0x10); + + var name = data.getString(offset + 1, data[offset]); + offset += data[offset] + 1; + + var dt = TemplateDataType.parse(data, offset); + offset += dt.size; + + // arguments count + var argsCount = data[offset++]; + List arguments = []; + + for (var a = 0; a < argsCount; a++) { + var art = ArgumentTemplate.parse(data, offset); + arguments.add(art.value); + offset += art.size; + } + + if (hasExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + expansion = data.getString(offset, cs); + offset += cs; + } + + var ft = new FunctionTemplate( + this, functionIndex++, name, arguments, dt.value, expansion); + + _functions.add(ft); + } else if (type == 1) // property + { + String readExpansion = null, writeExpansion = null; + + var hasReadExpansion = ((data[offset] & 0x8) == 0x8); + var hasWriteExpansion = ((data[offset] & 0x10) == 0x10); + var recordable = ((data[offset] & 1) == 1); + var permission = (data[offset++] >> 1) & 0x3; + var name = data.getString(offset + 1, data[offset]); + + offset += data[offset] + 1; + + var dt = TemplateDataType.parse(data, offset); + + offset += dt.size; + + if (hasReadExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + readExpansion = data.getString(offset, cs); + offset += cs; + } + + if (hasWriteExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + writeExpansion = data.getString(offset, cs); + offset += cs; + } + + var pt = new PropertyTemplate( + this, + propertyIndex++, + name, + dt.value, + readExpansion, + writeExpansion, + recordable ? StorageMode.Recordable : StorageMode.Volatile); + + _properties.add(pt); + } else if (type == 2) // Event + { + String expansion = null; + var hasExpansion = ((data[offset] & 0x10) == 0x10); + var listenable = ((data[offset++] & 0x8) == 0x8); + + var name = data.getString(offset + 1, data[offset]); + offset += data[offset] + 1; + + var dt = TemplateDataType.parse(data, offset); + + offset += dt.size; + + if (hasExpansion) // expansion ? + { + var cs = data.getUint32(offset); + offset += 4; + expansion = data.getString(offset, cs); + offset += cs; + } + + var et = new EventTemplate( + this, eventIndex++, name, dt.value, expansion, listenable); + + _events.add(et); + } + } + + // append signals + for (int i = 0; i < _events.length; i++) _members.add(_events[i]); + // append slots + for (int i = 0; i < _functions.length; i++) _members.add(_functions[i]); + // append properties + for (int i = 0; i < _properties.length; i++) _members.add(_properties[i]); + } +} diff --git a/lib/src/Resource/Warehouse.dart b/lib/src/Resource/Warehouse.dart index 195bf64..03e2fe2 100644 --- a/lib/src/Resource/Warehouse.dart +++ b/lib/src/Resource/Warehouse.dart @@ -23,7 +23,8 @@ SOFTWARE. */ import '../Data/AutoList.dart'; -import './Template/ResourceTemplate.dart'; +import 'Template/TemplateType.dart'; +import 'Template/TypeTemplate.dart'; import '../Data/Guid.dart'; import '../Data/KeyList.dart'; import '../Data/Structure.dart'; @@ -44,20 +45,30 @@ class Warehouse { static Map _resources = new Map(); static int resourceCounter = 0; - static KeyList _templates = - new KeyList(); + + static KeyList> _templates = + _initTemplates(); // - //public delegate void StoreConnectedEvent(IStore store, string name); - //public delegate void StoreDisconnectedEvent(IStore store); + static _initTemplates() { + var rt = new KeyList>(); - //public static event StoreConnectedEvent StoreConnected; - ///public static event StoreDisconnectedEvent StoreDisconnected; + rt.add(TemplateType.Unspecified, new KeyList()); + rt.add(TemplateType.Resource, new KeyList()); + rt.add(TemplateType.Record, new KeyList()); + rt.add(TemplateType.Wrapper, new KeyList()); - static bool _warehouseIsOpen = false; + return rt; + } + + + static KeyList _factory = _getBuiltInTypes(); static KeyList Function(String, dynamic)> protocols = _getSupportedProtocols(); + + static bool _warehouseIsOpen = false; + static final _urlRegex = RegExp(r'^(?:([^\s|:]*):\/\/([^\/]*)\/?(.*))'); /// @@ -162,7 +173,7 @@ class Warehouse { static List qureyIn( List path, int index, AutoList resources) { - var rt = new List(); + List rt = []; if (index == path.length - 1) { if (path[index] == "") @@ -206,11 +217,11 @@ class Warehouse { /// /// /// Resource instance. - static AsyncReply get(String path, + static AsyncReply get(String path, [attributes = null, IResource parent = null, IPermissionsManager manager = null]) { - var rt = AsyncReply(); + var rt = AsyncReply(); // Should we create a new store ? if (_urlRegex.hasMatch(path)) { @@ -226,7 +237,7 @@ class Warehouse { rt.trigger(r); }).error((e) => rt.triggerError(e)); else - rt.trigger(store); + rt.trigger(store as T); }).error((e) { rt.triggerError(e); //Warehouse.remove(store); @@ -333,14 +344,74 @@ class Warehouse { /// Resource name. /// IStore that manages the resource. Can be null if the resource is a store. /// Parent resource. if not presented the store becomes the parent for the resource. - static AsyncReply put(IResource resource, String name, + static AsyncReply put(String name, T resource, [IStore store = null, IResource parent = null, - ResourceTemplate customTemplate = null, + TypeTemplate customTemplate = null, int age = 0, IPermissionsManager manager = null, attributes = null]) { - var rt = AsyncReply(); + var rt = AsyncReply(); + + if (resource.instance != null) { + rt.triggerError(Exception("Resource has a store.")); + return rt; + } + + // @TODO: Trim left '/' char + // var path = name.trimLeft().split("/"); + // if (path.length > 1) + // { + // if (parent != null) + // rt.triggerError(Exception("Parent can't be set when using path in instance name")); + + // Warehouse.get(path.take(path.length - 1).join("/")).then((value){ + // if (value == null) + // rt.triggerError(Exception("Can't find parent")); + + // parent = value; + + // store = store ?? parent.instance.store; + + // var instanceName = path.last; + + // if (store == null) + // { + // // assign parent as a store + // if (parent is IStore) + // { + // store = (IStore)parent; + // stores + // List> list; + // if (stores.TryGetValue(store, out list)) + // lock (((ICollection)list).SyncRoot) + // list.Add(resourceReference); + // //stores[store].Add(resourceReference); + // } + // // assign parent's store as a store + // else if (parent != null) + // { + // store = parent.instance.store; + + // List> list; + // if (stores.TryGetValue(store, out list)) + // lock (((ICollection)list).SyncRoot) + // list.Add(resourceReference); + + // //stores[store].Add(resourceReference); + // } + // // assign self as a store (root store) + // else if (resource is IStore) + // { + // store = resource; + // } + // else + // throw new Exception("Can't find a store for the resource."); + // } + + // }); + + // } resource.instance = new Instance( resourceCounter++, name, resource, store, customTemplate, age); @@ -364,11 +435,17 @@ class Warehouse { resource.trigger(ResourceTrigger.Initialize).then((value) { if (resource is IStore) resource.trigger(ResourceTrigger.Open).then((value) { - rt.trigger(value); - }).error((ex) => rt.triggerError(ex)); + rt.trigger(resource); + }).error((ex) { + Warehouse.remove(resource); + rt.triggerError(ex); + }); else - rt.trigger(value); - }).error((ex) => rt.triggerError(ex)); + rt.trigger(resource); + }).error((ex) { + Warehouse.remove(resource); + rt.triggerError(ex); + }); } }; @@ -380,8 +457,11 @@ class Warehouse { if (value) initResource(); else - rt.trigger(false); - }).error((ex) => rt.triggerError(ex)); + rt.trigger(null); + }).error((ex) { + Warehouse.remove(resource); + rt.triggerError(ex); + }); } // return new name @@ -389,12 +469,18 @@ class Warehouse { return rt; } - static AsyncReply New(T resource, String name, + static T createInstance(Type T) { + return _factory[T].call(); + } + + static AsyncReply newResource(String name, [IStore store = null, IResource parent = null, IPermissionsManager manager = null, attributes = null, properties = null]) { + var resource = _factory[T].call(); + if (properties != null) { dynamic d = resource; @@ -405,9 +491,9 @@ class Warehouse { var rt = AsyncReply(); - put(resource, name, store, parent, null, 0, manager, attributes) - .then((value) { - if (value) + put(name, resource, store, parent, null, 0, manager, attributes) + .then((value) { + if (value != null) rt.trigger(resource); else rt.trigger(null); @@ -427,49 +513,77 @@ class Warehouse { /// Put a resource template in the templates warehouse. /// /// Resource template. - static void putTemplate(ResourceTemplate template) { - if (!_templates.containsKey(template.classId)) - _templates.add(template.classId, template); + static void putTemplate(TypeTemplate template) { + _templates[template.type][template.classId] = template; } /// - /// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// Get a template by type from the templates warehouse. If not in the warehouse, a new TypeTemplate is created and added to the warehouse. /// /// .Net type. /// Resource template. - static ResourceTemplate getTemplateByType(Type type) { + static TypeTemplate getTemplateByType(Type type) { // loaded ? - for (var t in _templates.values) - if (t.className == type.toString()) return t; + for (var tmps in _templates.values) + for (var tmp in tmps.values) + if (tmp.className == type.toString()) return tmp; - var template = new ResourceTemplate.fromType(type); - _templates.add(template.classId, template); + var template = new TypeTemplate.fromType(type, true); return template; } /// - /// Get a template by class Id from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// Get a template by class Id from the templates warehouse. If not in the warehouse, a new TypeTemplate is created and added to the warehouse. /// /// Class Id. /// Resource template. - static AsyncReply getTemplateByClassId(Guid classId) { - if (_templates.containsKey(classId)) - return new AsyncReply.ready(_templates[classId]); - return null; + static TypeTemplate getTemplateByClassId(Guid classId, + [TemplateType templateType = TemplateType.Unspecified]) { + if (templateType == TemplateType.Unspecified) { + // look in resources + var template = _templates[TemplateType.Resource][classId]; + if (template != null) return template; + + // look in records + template = _templates[TemplateType.Record][classId]; + if (template != null) return template; + + // look in wrappers + template = _templates[TemplateType.Wrapper][classId]; + return template; + } else { + return _templates[templateType][classId]; + } } /// - /// Get a template by class name from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// Get a template by class name from the templates warehouse. If not in the warehouse, a new TypeTemplate is created and added to the warehouse. /// /// Class name. /// Resource template. - static AsyncReply getTemplateByClassName(String className) { - for (var t in _templates.values) - if (t.className == className) - return new AsyncReply.ready(t); + static TypeTemplate getTemplateByClassName(String className, [TemplateType templateType = TemplateType.Unspecified]) { - return null; + if (templateType == TemplateType.Unspecified) + { + // look in resources + var template = _templates[TemplateType.Resource].values.firstWhere((x) => x.className == className); + if (template != null) + return template; + + // look in records + template = _templates[TemplateType.Record].values.firstWhere((x) => x.className == className); + if (template != null) + return template; + + // look in wrappers + template = _templates[TemplateType.Wrapper].values.firstWhere((x) => x.className == className); + return template; + } + else + { + return _templates[templateType].values.firstWhere((x) => x.className == className); + } } static bool remove(IResource resource) { @@ -505,8 +619,15 @@ class Warehouse { new KeyList Function(String, dynamic)>(); rt.add( "iip", - (String name, attributes) => Warehouse.New( - DistributedConnection(), name, null, null, null, attributes)); + (String name, attributes) => + Warehouse.newResource( + name, null, null, null, attributes)); + return rt; + } + + static KeyList _getBuiltInTypes() { + var rt = KeyList(); + rt.add(DistributedConnection, () => DistributedConnection()); return rt; } } diff --git a/lib/src/Security/Permissions/ActionType.dart b/lib/src/Security/Permissions/ActionType.dart index 6b27c40..c3c26f7 100644 --- a/lib/src/Security/Permissions/ActionType.dart +++ b/lib/src/Security/Permissions/ActionType.dart @@ -36,5 +36,6 @@ enum ActionType AddChild, RemoveChild, Rename, - ReceiveEvent + ReceiveEvent, + ViewTemplate } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index d79c016..5ce78d0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,16 +7,16 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "22.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.39.4" + version: "1.7.1" args: - dependency: transitive + dependency: "direct main" description: name: args url: "https://pub.dartlang.org" @@ -28,77 +28,84 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.7.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" + version: "1.3.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.15.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "3.0.0" coverage: dependency: transitive description: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "0.13.9" + version: "0.15.2" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" - csslib: + version: "3.0.1" + dart_style: dependency: transitive description: - name: csslib + name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "2.0.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" - html: - dependency: transitive - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.0+3" - http: - dependency: transitive - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.0+4" + version: "2.0.1" http_multi_server: dependency: transitive description: @@ -126,28 +133,28 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+1" + version: "0.6.3" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "0.11.4" + version: "1.0.1" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0" mime: dependency: transitive description: @@ -155,27 +162,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.9.6+3" - multi_server_socket: - dependency: transitive - description: - name: multi_server_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1+2" node_preamble: dependency: transitive description: @@ -189,35 +175,35 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "2.0.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" + version: "1.8.0" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.11.1" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "1.4.4" + version: "2.0.0" shelf: dependency: transitive description: @@ -238,7 +224,7 @@ packages: name: shelf_static url: "https://pub.dartlang.org" source: hosted - version: "0.2.8" + version: "0.2.9+2" shelf_web_socket: dependency: transitive description: @@ -246,83 +232,90 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.3" + source_gen: + dependency: "direct main" + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.9" + version: "0.10.10" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" test: dependency: "direct dev" description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.14.2" + version: "1.16.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.15" + version: "0.2.19" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.3" + version: "0.3.15" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0" vm_service: dependency: transitive description: @@ -336,27 +329,27 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "0.9.7+14" + version: "1.0.0" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "0.5.0+1" + version: "1.0.0" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "3.1.0" sdks: - dart: ">=2.7.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c7f0fc9..37028b5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,17 @@ name: esiur description: Distributed Object Framework. -version: 1.2.6 -# author: Ahmed Zamil +version: 1.3.0 +# author: Ahmed Zamil homepage: https://github.com/esiur/esiur-dart environment: sdk: ">=2.1.0 <3.0.0" - + +dependencies: + source_gen: ^1.0.2 + args: # + dev_dependencies: test: ^1.14.2 diff --git a/test/main.dart b/test/main.dart index b45b75e..5297603 100644 --- a/test/main.dart +++ b/test/main.dart @@ -1,12 +1,22 @@ +import 'package:esiur/src/Proxy/TemplateGenerator.dart'; import "package:test/test.dart"; import 'package:esiur/esiur.dart'; import 'dart:io'; +import '../lib/localhost/Esiur.Generated.dart'; +import 'TestResource.dart'; main() async { try { - var x = await Warehouse.get("iip://localhost:5070/sys/cp", - {"username": "admin", "password": "1234", "domain": "example.com"}); - print(x); + testMe(); + + var c = EsiurGenerated; + print(c); + print(Warehouse.protocols.length); + + await TemplateGenerator.getTemplate("iip://localhost/sys/cp"); + // var x = await Warehouse.get("iip://localhost/sys/cp", + // {"username": "guest", "password": "123456", "domain": "example.com"}); + // print(x); } catch (ex) { print("Error occured"); print(ex);