diff --git a/.pubignore b/.pubignore new file mode 100644 index 0000000..b59f7e3 --- /dev/null +++ b/.pubignore @@ -0,0 +1 @@ +test/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a687720..0f7f2e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.4.3] - Hotfix +Bugfix + +## [1.4.2] - Release +Added get-template command + ## [1.2.3] - Release Improved property updating diff --git a/LICENSE b/LICENSE index e69e7c9..f0cf5a6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019-2021 Esiur Foundation, Ahmed Kh. Zamil +Copyright (c) 2019-2022 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/lib/builder.dart b/lib/builder.dart index 3c75719..1521b4c 100644 --- a/lib/builder.dart +++ b/lib/builder.dart @@ -1,47 +1,47 @@ -import 'package:source_gen/source_gen.dart'; -import 'package:build/build.dart'; -import 'package:yaml/yaml.dart'; +// import 'package:source_gen/source_gen.dart'; +// import 'package:build/build.dart'; +// import 'package:yaml/yaml.dart'; -//Builder iipService(BuilderOptions options) { - //return LibraryBuilder(TemplateBuilder(), generatedExtension: '.info.dart'); -//} +// //Builder iipService(BuilderOptions options) { +// //return LibraryBuilder(TemplateBuilder(), generatedExtension: '.info.dart'); +// //} -class TemplateBuilder implements Builder { - //BuilderOptions options; - String _fileName; - TemplateBuilder([BuilderOptions? options]) : _fileName = _get_dest(options); +// 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 TemplateBuilder extends Generator { // @override -// String generate(LibraryReader library, BuildStep buildStep) { -// return ''' -// // Source library: ${library.element.source.uri} -// const Testinggggg = 3; -// '''; +// 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 TemplateBuilder extends Generator { +// // @override +// // String generate(LibraryReader library, BuildStep buildStep) { +// // return ''' +// // // Source library: ${library.element.source.uri} +// // const Testinggggg = 3; +// // '''; +// // } +// // } diff --git a/lib/src/Core/AsyncBag.dart b/lib/src/Core/AsyncBag.dart index 1aedf65..553fb7e 100644 --- a/lib/src/Core/AsyncBag.dart +++ b/lib/src/Core/AsyncBag.dart @@ -23,7 +23,14 @@ class AsyncBag extends AsyncReply> { if (_sealedBag) return; _sealedBag = true; - if (_replies.length == 0) trigger([]); + if (_replies.length == 0) { + if (arrayType != null) { + var ar = Warehouse.createArray(arrayType as Type); + trigger(ar as List); + } else { + trigger([]); + } + } var results = List.filled(_replies.length, null); @@ -31,21 +38,23 @@ class AsyncBag extends AsyncReply> { var k = _replies[i]; var index = i; - k..then((r) { - results[index] = r; - _count++; - if (_count == _replies.length) { - if (arrayType != null) { - var ar = Warehouse.createArray(arrayType as Type); - results.forEach(ar.add); - trigger(ar as List); - } else { - trigger(results.cast()); + k + ..then((r) { + results[index] = r; + _count++; + if (_count == _replies.length) { + if (arrayType != null) { + var ar = Warehouse.createArray(arrayType as Type); + results.forEach(ar.add); + trigger(ar as List); + } else { + trigger(results.cast()); + } } - } - })..error((ex) { - triggerError(ex); - }); + }) + ..error((ex) { + triggerError(ex); + }); } } diff --git a/lib/src/Core/IEventHandler.dart b/lib/src/Core/IEventHandler.dart index 7f17a0f..35d6434 100644 --- a/lib/src/Core/IEventHandler.dart +++ b/lib/src/Core/IEventHandler.dart @@ -1,4 +1,8 @@ +import 'dart:async'; + class IEventHandler { + final _propertyModifiedController = StreamController(); + Map> _events = {}; register(String event) { @@ -7,6 +11,12 @@ class IEventHandler { IEventHandler() {} + Stream get properyModified => _propertyModifiedController.stream; + + emitProperty(String name) { + _propertyModifiedController.add(name); + } + emitArgs(String event, List arguments) { //event = event.toLowerCase(); @@ -21,13 +31,13 @@ class IEventHandler { on(String event, Function callback) { event = event.toLowerCase(); - if (_events.containsKey(event)) register(event); + if (!_events.containsKey(event)) register(event); _events[event]?.add(callback); return this; } - off(event, callback) { - event = event.toString(); + off(String event, callback) { + event = event.toLowerCase(); if (_events.containsKey(event)) { if (callback != null) _events[event]?.remove(callback); diff --git a/lib/src/Data/Codec.dart b/lib/src/Data/Codec.dart index 02b1dd1..05e84b9 100644 --- a/lib/src/Data/Codec.dart +++ b/lib/src/Data/Codec.dart @@ -170,9 +170,12 @@ class Codec { AsyncReply? previous = null; - if (result == RecordComparisonResult.Null) + if (result == RecordComparisonResult.Empty) { + reply.seal(); + return reply; + } else if (result == RecordComparisonResult.Null) { previous = AsyncReply.ready(null); - else if (result == RecordComparisonResult.Record || + } else if (result == RecordComparisonResult.Record || result == RecordComparisonResult.RecordSameType) { var cs = data.getUint32(offset); var recordLength = cs; @@ -203,8 +206,10 @@ class Codec { } else { AsyncReply? previous = null; Guid? classId = null; - - if (result == RecordComparisonResult.Null) + if (result == RecordComparisonResult.Empty) { + reply.seal(); + return reply; + } else if (result == RecordComparisonResult.Null) previous = new AsyncReply.ready(null); else if (result == RecordComparisonResult.Record) { var cs = data.getUint32(offset); @@ -392,11 +397,13 @@ class Codec { static DC composeRecordArray( List? records, DistributedConnection connection, [bool prependLength = false]) { - if (records == null || records.length == 0) + if (records == null) // || records.length == 0) return prependLength ? new DC(4) : new DC(0); var rt = new BinaryList(); - var comparsion = compareRecords(null, records[0]); + var comparsion = records.length == 0 + ? RecordComparisonResult.Empty + : compareRecords(null, records[0]); //var type = records.getType().GetElementType(); var isTyped = T == IRecord; // != typeof(IRecord); @@ -960,11 +967,14 @@ class Codec { static DC composeResourceArray( List? resources, DistributedConnection connection, [bool prependLength = false]) { - if (resources == null || resources.length == 0) + 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); + //var comparsion = compareResources(null, resources[0], connection); + var comparsion = resources.length == 0 + ? ResourceComparisonResult.Empty + : compareResources(null, resources[0], connection); if (T != IResource) { // get template @@ -1048,7 +1058,10 @@ class Codec { AsyncReply? previous = null; - if (result == ResourceComparisonResult.Null) + if (result == ResourceComparisonResult.Empty) { + reply.seal(); + return reply; + } else if (result == ResourceComparisonResult.Null) previous = new AsyncReply.ready(null); else if (result == ResourceComparisonResult.Local) { previous = Warehouse.getById(data.getUint32(offset)); @@ -1065,7 +1078,10 @@ class Codec { AsyncReply? current = null; - if (result == ResourceComparisonResult.Null) { + if (result == ResourceComparisonResult.Empty) { + reply.seal(); + return reply; + } else if (result == ResourceComparisonResult.Null) { current = new AsyncReply.ready(null); } else if (result == ResourceComparisonResult.Same) { current = previous; diff --git a/lib/src/Data/RecordComparisonResult.dart b/lib/src/Data/RecordComparisonResult.dart index a1b6f4f..a158bd0 100644 --- a/lib/src/Data/RecordComparisonResult.dart +++ b/lib/src/Data/RecordComparisonResult.dart @@ -3,4 +3,6 @@ class RecordComparisonResult { static const Record = 1; static const RecordSameType = 2; static const Same = 3; + static const Empty = 4; + } diff --git a/lib/src/Data/ResourceComparisonResult.dart b/lib/src/Data/ResourceComparisonResult.dart index e0864b3..51c1c32 100644 --- a/lib/src/Data/ResourceComparisonResult.dart +++ b/lib/src/Data/ResourceComparisonResult.dart @@ -1,7 +1,7 @@ -class ResourceComparisonResult -{ - static const Null = 0; - static const Distributed = 1; - static const Local = 2; - static const Same = 3; -} \ No newline at end of file +class ResourceComparisonResult { + static const Null = 0; + static const Distributed = 1; + static const Local = 2; + static const Same = 3; + static const Empty = 4; +} diff --git a/lib/src/Net/IIP/DistributedConnection.dart b/lib/src/Net/IIP/DistributedConnection.dart index 1bdab86..b15005f 100644 --- a/lib/src/Net/IIP/DistributedConnection.dart +++ b/lib/src/Net/IIP/DistributedConnection.dart @@ -22,6 +22,8 @@ SOFTWARE. */ +import '../Sockets/WSocket.dart'; + import '../../Resource/Template/TemplateDescriber.dart'; import '../../Resource/Template/TemplateType.dart'; import '../../Security/Authority/AuthenticationMethod.dart'; @@ -161,7 +163,7 @@ class DistributedConnection extends NetworkConnection with IStore { /// Send data to the other end as parameters /// /// Values will be converted to bytes then sent. - SendList sendParams([AsyncReply>? reply = null]) { + SendList sendParams([AsyncReply?>? reply = null]) { return new SendList(this, reply); } @@ -188,6 +190,11 @@ class DistributedConnection extends NetworkConnection with IStore { var domain = instance?.attributes["domain"] ?? address; + var ws = instance?.attributes.containsKey("ws") == true || + instance?.attributes.containsKey("wss") == true; + var secure = instance?.attributes.containsKey("secure") == true || + instance?.attributes.containsKey("wss") == true; + if (instance?.attributes.containsKey("username") == true && instance?.attributes.containsKey("password") == true) { var username = instance?.attributes["username"] as String; @@ -200,7 +207,9 @@ class DistributedConnection extends NetworkConnection with IStore { hostname: address, port: port, passwordOrToken: password, - username: username); + username: username, + useWebsocket: ws, + secureWebSocket: secure); } else if (instance?.attributes.containsKey("token") == true) { var token = DC.stringToBytes(instance?.attributes["token"] ?? ""); var tokenIndex = instance?.attributes["tokenIndex"] ?? 0; @@ -210,13 +219,17 @@ class DistributedConnection extends NetworkConnection with IStore { hostname: address, port: port, passwordOrToken: token, - tokenIndex: tokenIndex); + tokenIndex: tokenIndex, + useWebsocket: ws, + secureWebSocket: secure); } else { return connect( method: AuthenticationMethod.None, hostname: address, port: port, - domain: domain); + domain: domain, + useWebsocket: ws, + secureWebSocket: secure); } } @@ -231,7 +244,9 @@ class DistributedConnection extends NetworkConnection with IStore { String? username, int? tokenIndex, DC? passwordOrToken, - String? domain}) { + String? domain, + bool useWebsocket = false, + bool secureWebSocket = false}) { if (_openReply != null) throw AsyncException(ErrorType.Exception, 0, "Connection in progress"); @@ -251,19 +266,26 @@ class DistributedConnection extends NetworkConnection with IStore { if (_session == null) throw AsyncException(ErrorType.Exception, 0, "Session not initialized"); - if (socket == null) socket = new TCPSocket(); + if (socket == null) { + if (useWebsocket) { + socket = new WSocket()..secure = secureWebSocket; + } else + socket = new TCPSocket(); + } _port = port ?? _port; _hostname = hostname ?? _hostname; if (_hostname == null) throw Exception("Host not specified."); - socket.connect(_hostname as String, _port).then((x) { - assign(socket as ISocket); - }).error((x) { - _openReply?.triggerError(x); - _openReply = null; - }); + if (socket != null) { + socket.connect(_hostname as String, _port).then((x) { + assign(socket as ISocket); + }).error((x) { + _openReply?.triggerError(x); + _openReply = null; + }); + } return _openReply as AsyncReply; } @@ -961,7 +983,7 @@ class DistributedConnection extends NetworkConnection with IStore { /// Arguments to send. /// SendList sendRequest(int action) { - var reply = new AsyncReply>(); + var reply = new AsyncReply?>(); var c = _callbackCounter++; // avoid thread racing _requests.add(c, reply); @@ -2248,10 +2270,14 @@ class DistributedConnection extends NetworkConnection with IStore { (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]); + if (rt != null) { + _templateRequests.remove(classId); + _templates[(rt[0] as TypeTemplate).classId] = rt[0] as TypeTemplate; + Warehouse.putTemplate(rt[0] as TypeTemplate); + reply.trigger(rt[0]); + } else { + reply.triggerError(Exception("Null response")); + } }) ..error((ex) { reply.triggerError(ex); @@ -2301,24 +2327,28 @@ class DistributedConnection extends NetworkConnection with IStore { ..addUint16(l.length) ..addDC(l)) .done() - ..then((rt) { - List templates = []; - // parse templates + ..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; - } + if (rt != null) { + 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; + } + } else { + reply.triggerError(Exception("Null response")); + } - reply.trigger(templates); - }) - ..error((ex) { - reply.triggerError(ex); - }); + reply.trigger(templates); + }) + ..error((ex) { + reply.triggerError(ex); + }); return reply; } @@ -2347,55 +2377,59 @@ class DistributedConnection extends NetworkConnection with IStore { (sendRequest(IIPPacketAction.AttachResource)..addUint32(id)).done() ..then((rt) { - // @TODO: Generator code - DistributedResource dr; + if (rt != null) { + // @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 as Type); - dr.internal_init(this, id, rt[1], rt[2]); - } else { - dr = new DistributedResource(); - dr.internal_init(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.internal_attach(ar); - _resourceRequests.remove(id); - reply.trigger(dr); - }); - }) - ..error((ex) => reply.triggerError(ex)); + if (resource == null) { + var template = + Warehouse.getTemplateByClassId(rt[0], TemplateType.Wrapper); + if (template?.definedType != null) { + dr = Warehouse.createInstance(template?.definedType as Type); + dr.internal_init(this, id, rt[1], rt[2]); } else { - Codec.parsePropertyValueArray(d, 0, d.length, this).then((ar) { - //print("attached"); - if (ar != null) dr.internal_attach(ar); - _resourceRequests.remove(id); - reply.trigger(dr); - }); + dr = new DistributedResource(); + dr.internal_init(this, id, rt[1], rt[2]); } - }) - ..error((ex) { - reply.triggerError(ex); - }); + } 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.internal_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"); + if (ar != null) dr.internal_attach(ar); + _resourceRequests.remove(id); + reply.trigger(dr); + }); + } + }) + ..error((ex) { + reply.triggerError(ex); + }); + } else { + reply.triggerError(Exception("Null response")); + } }) ..error((ex) { reply.triggerError(ex); @@ -2410,10 +2444,14 @@ class DistributedConnection extends NetworkConnection with IStore { sendRequest(IIPPacketAction.ResourceChildren) ..addUint32(resource.instance?.id as int) ..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)); + if (ar != null) { + var d = ar[0] as DC; + Codec.parseResourceArray(d, 0, d.length, this).then((resources) { + rt.trigger(resources); + }).error((ex) => rt.triggerError(ex)); + } else { + rt.triggerError(Exception("Null response")); + } }); return rt; @@ -2425,11 +2463,15 @@ class DistributedConnection extends NetworkConnection with IStore { sendRequest(IIPPacketAction.ResourceParents) ..addUint32((resource.instance as 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)); + if (ar != null) { + var d = ar[0] as DC; + Codec.parseResourceArray(d, 0, d.length, this) + .then((resources) { + rt.trigger(resources); + }).error((ex) => rt.triggerError(ex)); + } else { + rt.triggerError(Exception("Null response")); + } }); return rt; @@ -2443,8 +2485,8 @@ class DistributedConnection extends NetworkConnection with IStore { (sendRequest(IIPPacketAction.ClearAllAttributes) ..addUint32(resource.instance?.id as int)) .done() - ..then((ar) => rt.trigger(true)) - ..error((ex) => rt.triggerError(ex)); + ..then((ar) => rt.trigger(true)) + ..error((ex) => rt.triggerError(ex)); else { var attrs = DC.stringArrayToBytes(attributes); (sendRequest(IIPPacketAction.ClearAttributes) @@ -2452,8 +2494,8 @@ class DistributedConnection extends NetworkConnection with IStore { ..addInt32(attrs.length) ..addDC(attrs)) .done() - ..then((ar) => rt.trigger(true)) - ..error((ex) => rt.triggerError(ex)); + ..then((ar) => rt.trigger(true)) + ..error((ex) => rt.triggerError(ex)); } return rt; @@ -2483,15 +2525,19 @@ class DistributedConnection extends NetworkConnection with IStore { (sendRequest(IIPPacketAction.GetAllAttributes) ..addUint32(resource.instance?.id as int)) .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)); - }); + ..then((ar) { + if (ar != null) { + 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 { + rt.triggerError(Exception("Null response")); + } + }); } else { var attrs = DC.stringArrayToBytes(attributes); (sendRequest(IIPPacketAction.GetAttributes) @@ -2499,16 +2545,20 @@ class DistributedConnection extends NetworkConnection with IStore { ..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); + ..then((ar) { + if (ar != null) { + 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)); - }); + rt.trigger(st); + }) + ..error((ex) => rt.triggerError(ex)); + } else { + rt.triggerError(Exception("Null response")); + } + }); } return rt; @@ -2538,10 +2588,14 @@ class DistributedConnection extends NetworkConnection with IStore { ..addDateTime(fromDate) ..addDateTime(toDate) ..done().then((rt) { - var content = rt[0] as DC; + if (rt != null) { + var content = rt[0] as DC; - Codec.parseHistory(content, 0, content.length, resource, this) - .then((history) => reply.trigger(history)); + Codec.parseHistory(content, 0, content.length, resource, this) + .then((history) => reply.trigger(history)); + } else { + reply.triggerError(Exception("Null response")); + } }).error((ex) => reply.triggerError(ex)); return reply; @@ -2563,10 +2617,14 @@ class DistributedConnection extends NetworkConnection with IStore { ..addUint16(str.length) ..addDC(str) ..done().then((args) { - var content = args[0] as DC; + if (args != null) { + var content = args[0] as DC; - Codec.parseResourceArray(content, 0, content.length, this) - .then((resources) => reply.trigger(resources)); + Codec.parseResourceArray(content, 0, content.length, this) + .then((resources) => reply.trigger(resources)); + } else { + reply.triggerError(Exception("Null response")); + } }).error((ex) => reply.triggerError(ex)); return reply; @@ -2602,11 +2660,15 @@ class DistributedConnection extends NetworkConnection with IStore { (sendRequest(IIPPacketAction.CreateResource)..addDC(pkt.toDC())).done() ..then((args) { - var rid = args[0]; + if (args != null) { + var rid = args[0]; - fetch(rid).then((r) { - reply.trigger(r); - }); + fetch(rid).then((r) { + reply.trigger(r); + }); + } else { + reply.triggerError(Exception("Null response")); + } }); return reply; diff --git a/lib/src/Net/IIP/DistributedResource.dart b/lib/src/Net/IIP/DistributedResource.dart index f312ee5..8180b65 100644 --- a/lib/src/Net/IIP/DistributedResource.dart +++ b/lib/src/Net/IIP/DistributedResource.dart @@ -22,6 +22,7 @@ SOFTWARE. */ +import 'dart:async'; import '../../Resource/Instance.dart'; @@ -371,12 +372,12 @@ class DistributedResource extends IResource { ..addUint8(index) ..addDC(parameters)) .done() - ..then((res) { - // not really needed, server will always send property modified, - // this only happens if the programmer forgot to emit in property setter - _properties[index] = value; - reply.trigger(null); - }); + ..then((res) { + // not really needed, server will always send property modified, + // this only happens if the programmer forgot to emit in property setter + _properties[index] = value; + reply.trigger(null); + }); return reply; } diff --git a/lib/src/Net/SendList.dart b/lib/src/Net/SendList.dart index e94bf49..48001be 100644 --- a/lib/src/Net/SendList.dart +++ b/lib/src/Net/SendList.dart @@ -4,12 +4,12 @@ import 'NetworkConnection.dart'; class SendList extends BinaryList { NetworkConnection connection; - AsyncReply>? reply; + AsyncReply?>? reply; SendList(this.connection, this.reply) {} @override - AsyncReply> done() { + AsyncReply?> done() { connection.send(super.toDC()); return reply ?? AsyncReply.ready([]); diff --git a/lib/src/Net/Sockets/WSocket.dart b/lib/src/Net/Sockets/WSocket.dart new file mode 100644 index 0000000..509abc8 --- /dev/null +++ b/lib/src/Net/Sockets/WSocket.dart @@ -0,0 +1,164 @@ +/* + +Copyright (c) 2019 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 'dart:io'; + +//import 'package:web_socket_channel/io.dart' as WS; +import 'package:web_socket_channel/io.dart'; + +import '../../Core/ErrorType.dart'; +import '../../Core/ExceptionCode.dart'; + +import '../../Core/AsyncException.dart'; + +import 'ISocket.dart'; +import '../../Data/DC.dart'; +import '../NetworkBuffer.dart'; +import 'SocketState.dart'; +import 'IPEndPoint.dart'; +import '../../Core/AsyncReply.dart'; + +class WSocket extends ISocket { + WebSocket? _sock; + IOWebSocketChannel? _channel; + + NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); + + bool began = false; + + bool secure = false; + + SocketState _state = SocketState.Initial; + + IPEndPoint? _localEP, _remoteEP; + + bool begin() { + if (began) return false; + + began = true; + + if (_sock != null) { + var s = _sock as Socket; + _localEP = IPEndPoint(s.address.rawAddress, s.port); + _remoteEP = IPEndPoint(s.remoteAddress.rawAddress, s.remotePort); + } + return true; + } + + void dataHandler(List data) { + 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); + } 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; + + WebSocket.connect("${secure ? 'wss' : 'ws'}://${hostname}:${port}'") + .then((s) { + _sock = s; + _state = SocketState.Established; + _channel = IOWebSocketChannel(s); + begin(); + receiver?.networkConnect(this); + 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() { + // 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) { + if (offset != null && size == null) { + _channel?.sink + .add(message.clip(offset, message.length - offset).toList()); + } else if (offset != null && size != null) { + _channel?.sink.add(message.clip(offset, size).toList()); + } else { + _channel?.sink.add(message.toList()); + } + } + } + + void destroy() { + close(); + emitArgs("destroy", [this]); + } + + AsyncReply accept() { + var reply = new AsyncReply(); + return reply; + } +} diff --git a/lib/src/Net/Sockets/Websocket.dart b/lib/src/Net/Sockets/Websocket.dart deleted file mode 100644 index 4a3f58a..0000000 --- a/lib/src/Net/Sockets/Websocket.dart +++ /dev/null @@ -1,192 +0,0 @@ -/* - -Copyright (c) 2019 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 'dart:io'; -import 'ISocket.dart'; -import '../../Data/DC.dart'; -import '../NetworkBuffer.dart'; -import 'SocketState.dart'; -import 'IPEndPoint.dart'; -import '../../Core/AsyncReply.dart'; - -import 'package:web_socket_channel/io.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; -import 'package:web_socket_channel/status.dart' as status; - -class WSSocket extends ISocket -{ - WebSocketChannel sock; - - NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); - - bool began = false; - - SocketState _state = SocketState.Initial; - - - IPEndPoint _localEP, _remoteEP; - - bool begin() - { - if (began) - return false; - - began = 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()); - - - try - { - if (_state == SocketState.Closed || _state == SocketState.Terminated) - return; - - - 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(){ - sock.destroy(); - } - - - AsyncReply connect(String hostname, int port) - { - var rt = new AsyncReply(); - - try - { - _state = SocketState.Connecting; - - WebSocket() - prefix0.WebSocket(url) - IOWebSocketChannel. - 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(ex); - }); - - - } - catch(ex) - { - rt.triggerError(ex); - } - - 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() - { - close(); - emitArgs("destroy", [this]); - } - - AsyncReply accept() - { - - - var reply = new AsyncReply(); - return reply; - } -} -*/ \ No newline at end of file diff --git a/lib/src/Proxy/TemplateGenerator.dart b/lib/src/Proxy/TemplateGenerator.dart index d2893b7..cd5a89a 100644 --- a/lib/src/Proxy/TemplateGenerator.dart +++ b/lib/src/Proxy/TemplateGenerator.dart @@ -219,7 +219,7 @@ class TemplateGenerator { var con = await Warehouse.get( (path[1] as String) + "://" + (path[2] as String), !isNullOrEmpty(username) && !isNullOrEmpty(password) - ? {username: username, password: password} + ? {"username": username, "password": password} : null); if (con == null) throw Exception("Can't connect to server"); diff --git a/lib/src/Resource/IResource.dart b/lib/src/Resource/IResource.dart index d13cd71..c48c4bf 100644 --- a/lib/src/Resource/IResource.dart +++ b/lib/src/Resource/IResource.dart @@ -40,4 +40,5 @@ abstract class IResource extends IDestructible { getProperty(String name); TemplateDescriber get template; + } diff --git a/lib/src/Resource/Instance.dart b/lib/src/Resource/Instance.dart index dd76754..b48fb95 100644 --- a/lib/src/Resource/Instance.dart +++ b/lib/src/Resource/Instance.dart @@ -386,6 +386,8 @@ class Instance extends IEventHandler { emitArgs("resourceModified", [_resource, pt.name, value]); //_resource.emitArgs("modified", [pt.name, value]); _resource.emitArgs(":${pt.name}", [value]); + + _resource.emitProperty(pt.name); } /// diff --git a/lib/src/Resource/Warehouse.dart b/lib/src/Resource/Warehouse.dart index aad1540..2af6529 100644 --- a/lib/src/Resource/Warehouse.dart +++ b/lib/src/Resource/Warehouse.dart @@ -65,7 +65,8 @@ class Warehouse { static KeyList _factory = _getBuiltInTypes(); - static KeyList Function(String, dynamic)> + static KeyList Function(String, Map?)> protocols = _getSupportedProtocols(); static bool _warehouseIsOpen = false; @@ -222,7 +223,7 @@ class Warehouse { /// /// Resource instance. static AsyncReply get(String path, - [attributes = null, + [Map? attributes = null, IResource? parent = null, IPermissionsManager? manager = null]) { var rt = AsyncReply(); @@ -232,8 +233,8 @@ class Warehouse { var url = _urlRegex.allMatches(path).first; if (protocols.containsKey(url[1])) { - var handler = - protocols[url[1]] as AsyncReply Function(String, dynamic); + var handler = protocols[url[1]] as AsyncReply Function( + String, Map?); var getFromStore = () { handler(url[2] as String, attributes) @@ -360,7 +361,7 @@ class Warehouse { TypeTemplate? customTemplate = null, int age = 0, IPermissionsManager? manager = null, - attributes = null]) { + Map? attributes = null]) { var rt = AsyncReply(); if (resource.instance != null) { @@ -493,7 +494,7 @@ class Warehouse { [IStore? store = null, IResource? parent = null, IPermissionsManager? manager = null, - attributes = null, + Map? attributes = null, properties = null]) { if (_factory[T] == null) throw Exception("No Instance Creator was found for type ${T}"); @@ -640,15 +641,30 @@ class Warehouse { return true; } - static KeyList Function(String, dynamic)> + static KeyList Function(String, Map?)> _getSupportedProtocols() { - var rt = - new KeyList Function(String, dynamic)>(); - rt.add( - "iip", - (String name, attributes) => - Warehouse.newResource( - name, null, null, null, attributes)); + var rt = new KeyList Function(String, Map?)>(); + rt + ..add( + "iip", + (String name, Map? attributes) => + Warehouse.newResource( + name, null, null, null, attributes)) + ..add("iipws", (String name, Map? attributes) { + if (attributes == null) attributes = {}; + attributes['ws'] = true; + return Warehouse.newResource( + name, null, null, null, attributes); + }) + ..add("iipwss", (String name, Map? attributes) { + if (attributes == null) attributes = {}; + attributes['wss'] = true; + return Warehouse.newResource( + name, null, null, null, attributes); + }); + return rt; } diff --git a/pubspec.lock b/pubspec.lock index bc60ef9..c0cf628 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,7 +21,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" async: dependency: transitive description: @@ -36,13 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" charcode: dependency: transitive description: @@ -92,13 +85,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" file: dependency: transitive description: @@ -154,7 +140,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" logging: dependency: transitive description: @@ -231,7 +217,7 @@ packages: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.2.0" shelf: dependency: transitive description: @@ -260,13 +246,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" - source_gen: - dependency: "direct main" - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" source_map_stack_trace: dependency: transitive description: @@ -359,7 +338,7 @@ packages: source: hosted version: "1.0.0" web_socket_channel: - dependency: transitive + dependency: "direct main" description: name: web_socket_channel url: "https://pub.dartlang.org" @@ -380,4 +359,4 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=2.14.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c50cde8..4ec1add 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,17 +1,18 @@ name: esiur description: Distributed Object Framework. -version: 1.4.1 +version: 1.4.5 #author: Ahmed Zamil homepage: https://github.com/esiur/esiur-dart environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.14.0 <3.0.0" dependencies: - source_gen: - args: # - pubspec_parse: + # source_gen: ^1.0.5 + args: ^2.3.0 + pubspec_parse: ^1.2.0 + web_socket_channel: ^2.1.0 dev_dependencies: test: