diff --git a/lib/src/Core/AsyncException.dart b/lib/src/Core/AsyncException.dart index ec04af3..f4b0c82 100644 --- a/lib/src/Core/AsyncException.dart +++ b/lib/src/Core/AsyncException.dart @@ -1,32 +1,29 @@ - import 'ExceptionCode.dart'; import 'ErrorType.dart'; -class AsyncException implements Exception -{ - final ErrorType type; - final int code; - final String message; +class AsyncException implements Exception { + final ErrorType type; + final int code; + final String message; - AsyncException(this.type, this.code, this.message) - { + AsyncException(this.type, this.code, this.message) {} - } + static toAsyncException(Exception ex) { + return ex is AsyncException + ? ex + : new AsyncException(ErrorType.Exception, 0, ex.toString()); + } - static toAsyncException(Exception ex) - { - return ex is AsyncException ? ex - : new AsyncException(ErrorType.Exception, 0, ex.toString()); - } + String errMsg() { + if (type == ErrorType.Management) + return ExceptionCode.values.elementAt(code).toString() + + ": " + + (message ?? ""); + else + return code.toString() + ": " + message; + } - String errMsg() { - if (type == ErrorType.Management) - return ExceptionCode.values.elementAt(code).toString() + ": " + (message ?? ""); - else - return code.toString() + ": " + message; - } - - @override + @override String toString() { return errMsg(); } diff --git a/lib/src/Core/AsyncReply.dart b/lib/src/Core/AsyncReply.dart index 1c785de..30e45c8 100644 --- a/lib/src/Core/AsyncReply.dart +++ b/lib/src/Core/AsyncReply.dart @@ -89,6 +89,10 @@ class AsyncReply implements Future { _errorCallbacks.add((ex)=>onError()); } + else if (onError is Function(Object, StackTrace)) + { + _errorCallbacks.add((ex)=>onError(ex, null)); + } } @@ -169,10 +173,17 @@ class AsyncReply implements Future if (_resultReady) return; - _exception = AsyncException.toAsyncException(exception); + if (exception is AsyncException) + _exception = exception; + else + _exception = AsyncException.toAsyncException(exception); ///lock (callbacksLock) //{ + + if (this._errorCallbacks.length == 0) + throw _exception; + else _errorCallbacks.forEach((x) { x(_exception); }); diff --git a/lib/src/Net/IIP/DistributedConnection.dart b/lib/src/Net/IIP/DistributedConnection.dart index a897dea..560a8dc 100644 --- a/lib/src/Net/IIP/DistributedConnection.dart +++ b/lib/src/Net/IIP/DistributedConnection.dart @@ -916,12 +916,12 @@ class DistributedConnection extends NetworkConnection with IStore /// /// Resource. /// - bool put(IResource resource) + AsyncReply put(IResource resource) { if (Codec.isLocalResource(resource, this)) _resources.add((resource as DistributedResource).id, resource); // else .. put it in the server.... - return true; + return AsyncReply.ready(true); } diff --git a/lib/src/Net/IIP/DistributedResource.dart b/lib/src/Net/IIP/DistributedResource.dart index 3acc8bd..4c13047 100644 --- a/lib/src/Net/IIP/DistributedResource.dart +++ b/lib/src/Net/IIP/DistributedResource.dart @@ -33,322 +33,271 @@ import '../../Data/Codec.dart'; import './DistributedConnection.dart'; import '../Packets/IIPPacketAction.dart'; -class DistributedResource extends IResource -{ +class DistributedResource extends IResource { + int _instanceId; + DistributedConnection _connection; - int _instanceId; - DistributedConnection _connection; + bool _attached = false; + //bool _isReady = false; - bool _attached = false; - //bool _isReady = false; + String _link; + List _properties; + bool _destroyed = false; - String _link; - List _properties; - bool _destroyed = false; + List> _queued_updates = + List>(); + /// + /// Connection responsible for the distributed resource. + /// + DistributedConnection get connection => _connection; - List> _queued_updates =List>(); + /// + /// Resource link + /// + String get link => _link; - /// - /// Connection responsible for the distributed resource. - /// - DistributedConnection get connection => _connection; + /// + /// Instance Id given by the other end. + /// + int get id => _instanceId; - /// - /// Resource link - /// - String get link => _link; + //bool get destroyed => _destroyed; - /// - /// Instance Id given by the other end. - /// - int get id => _instanceId; + bool get suspended => _suspended; + bool _suspended = true; - //bool get destroyed => _destroyed; + AsyncReply trigger(ResourceTrigger trigger) => AsyncReply.ready(true); - bool get suspended => _suspended; - bool _suspended = true; + /// + /// IDestructible interface. + /// + void destroy() { + _destroyed = true; + _attached = false; + _connection.sendDetachRequest(_instanceId); + emitArgs("destroy", [this]); + } - /// - /// IDestructible interface. - /// - void destroy() - { - _destroyed = true; - _attached = false; - _connection.sendDetachRequest(_instanceId); - emitArgs("destroy", [this]); + void suspend() { + _suspended = true; + _attached = false; + } + + /// + /// Resource is ready when all its properties are attached. + /// + // bool get isReady => _isReady; + + /// + /// Resource is attached when all its properties are received. + /// + bool get attached => _attached; + + // public DistributedResourceStack Stack + //{ + // get { return stack; } + //} + + /// + /// Create a new distributed resource. + /// + /// Connection responsible for the distributed resource. + /// Resource template. + /// Instance Id given by the other end. + /// Resource age. + DistributedResource( + DistributedConnection connection, int instanceId, int age, String link) { + this._link = link; + this._connection = connection; + this._instanceId = instanceId; + } + + //void _ready() + //{ + // _isReady = true; + // } + + /// + /// Export all properties with ResourceProperty attributed as bytes array. + /// + /// + List serialize() { + var props = new List(_properties.length); + + for (var i = 0; i < _properties.length; i++) + props[i] = new PropertyValue( + _properties[i], instance.getAge(i), instance.getModificationDate(i)); + + return props; + } + + bool attach(List properties) { + if (_attached) + return false; + else { + _suspended = false; + + _properties = new List(properties.length); // object[properties.Length]; + + //_events = new DistributedResourceEvent[Instance.Template.Events.Length]; + + for (var i = 0; i < properties.length; i++) { + instance.setAge(i, properties[i].age); + instance.setModificationDate(i, properties[i].date); + _properties[i] = properties[i].value; + } + + // trigger holded events/property updates. + //foreach (var r in afterAttachmentTriggers) + // r.Key.Trigger(r.Value); + + //afterAttachmentTriggers.Clear(); + + _attached = true; + + if (_queued_updates.length > 0) { + _queued_updates + .forEach((kv) => updatePropertyByIndex(kv.key, kv.value)); + _queued_updates.clear(); + } } - - void suspend() - { - _suspended = true; - _attached = false; - } - - /// - /// Resource is ready when all its properties are attached. - /// - // bool get isReady => _isReady; - - /// - /// Resource is attached when all its properties are received. - /// - bool get attached => _attached; - + return true; + } - // public DistributedResourceStack Stack - //{ - // get { return stack; } - //} + void emitEventByIndex(int index, List args) { + // neglect events when the object is not yet attached + if (!_attached) return; - /// - /// Create a new distributed resource. - /// - /// Connection responsible for the distributed resource. - /// Resource template. - /// Instance Id given by the other end. - /// Resource age. - DistributedResource(DistributedConnection connection, int instanceId, int age, String link) - { - this._link = link; - this._connection = connection; - this._instanceId = instanceId; - } + var et = instance.template.getEventTemplateByIndex(index); + //events[index]?.Invoke(this, args); + emitArgs(et.name, args); - //void _ready() - //{ - // _isReady = true; - // } + instance.emitResourceEvent(null, null, et.name, args); + } - /// - /// Export all properties with ResourceProperty attributed as bytes array. - /// - /// - List serialize() - { + AsyncReply invokeByNamedArguments(int index, Structure namedArgs) { + if (_destroyed) throw new Exception("Trying to access destroyed object"); - var props = new List(_properties.length); + if (_suspended) throw new Exception("Trying to access suspended object"); + if (index >= instance.template.functions.length) + throw new Exception("Function index is incorrect"); - for (var i = 0; i < _properties.length; i++) - props[i] = new PropertyValue(_properties[i], instance.getAge(i), instance.getModificationDate(i)); + return connection.sendInvokeByNamedArguments(_instanceId, index, namedArgs); + } - return props; - } + AsyncReply invokeByArrayArguments(int index, List args) { + if (_destroyed) throw new Exception("Trying to access destroyed object"); - bool attach(List properties) - { - if (_attached) - return false; - else - { - _suspended = false; + if (_suspended) throw new Exception("Trying to access suspended object"); - _properties = new List(properties.length);// object[properties.Length]; + if (index >= instance.template.functions.length) + throw new Exception("Function index is incorrect"); - //_events = new DistributedResourceEvent[Instance.Template.Events.Length]; + return connection.sendInvokeByArrayArguments(_instanceId, index, args); + } - for (var i = 0; i < properties.length; i++) - { - instance.setAge(i, properties[i].age); - instance.setModificationDate(i, properties[i].date); - _properties[i] = properties[i].value; - } + operator [](String index) { + var pt = instance.template.getPropertyTemplateByName(index); + if (pt != null) return get(pt.index); + } - // trigger holded events/property updates. - //foreach (var r in afterAttachmentTriggers) - // r.Key.Trigger(r.Value); + operator []=(String index, value) { + var pt = instance.template.getPropertyTemplateByName(index); + if (pt != null) set(pt.index, value); + } - //afterAttachmentTriggers.Clear(); + String _getMemberName(Symbol symbol) { + var memberName = symbol.toString(); + if (memberName.endsWith("=\")")) + return memberName.substring(8, memberName.length - 3); + else + return memberName.substring(8, memberName.length - 2); + } - _attached = true; + @override //overring noSuchMethod + noSuchMethod(Invocation invocation) { + var memberName = _getMemberName(invocation.memberName); - if (_queued_updates.length > 0) - { - _queued_updates.forEach((kv)=>updatePropertyByIndex(kv.key, kv.value)); - _queued_updates.clear(); - } + if (invocation.isMethod) { + var ft = instance.template.getFunctionTemplateByName(memberName); + if (_attached && ft != null) { + if (invocation.namedArguments.length > 0) { + var namedArgs = new Structure(); + for (var p in invocation.namedArguments.keys) + namedArgs[_getMemberName(p)] = invocation.namedArguments[p]; + + return invokeByNamedArguments(ft.index, namedArgs); + } else { + return invokeByArrayArguments( + ft.index, invocation.positionalArguments); } + } + } else if (invocation.isSetter) { + var pt = instance.template.getPropertyTemplateByName(memberName); + + if (pt != null) { + set(pt.index, invocation.positionalArguments[0]); return true; - } - - void emitEventByIndex(int index, List args) - { - // neglect events when the object is not yet attached - if (!_attached) - return; - - var et = instance.template.getEventTemplateByIndex(index); - //events[index]?.Invoke(this, args); - emitArgs(et.name, args); - - instance.emitResourceEvent(null, null, et.name, args); - } - - AsyncReply invokeByNamedArguments(int index, Structure namedArgs) - { - if (_destroyed) - throw new Exception("Trying to access destroyed object"); - - if (_suspended) - throw new Exception("Trying to access suspended object"); - - if (index >= instance.template.functions.length) - throw new Exception("Function index is incorrect"); - - - return connection.sendInvokeByNamedArguments(_instanceId, index, namedArgs); - } - - - - AsyncReply invokeByArrayArguments(int index, List args) - { - if (_destroyed) - throw new Exception("Trying to access destroyed object"); - - if (_suspended) - throw new Exception("Trying to access suspended object"); - - if (index >= instance.template.functions.length) - throw new Exception("Function index is incorrect"); - - - return connection.sendInvokeByArrayArguments(_instanceId, index, args); - } - - operator [](String index) - { - var pt = instance.template.getPropertyTemplateByName(index); - if (pt != null) - return get(pt.index); } + } else if (invocation.isGetter) { + var pt = instance.template.getPropertyTemplateByName(memberName); - operator []=(String index, value) - { - var pt = instance.template.getPropertyTemplateByName(index); - if (pt != null) - set(pt.index, value); + if (pt != null) { + return get(pt.index); } - - String _getMemberName(Symbol symbol) - { - var memberName = symbol.toString(); - if (memberName.endsWith("=\")")) - return memberName.substring(8, memberName.length - 3); - else - return memberName.substring(8, memberName.length - 2); } - @override //overring noSuchMethod - noSuchMethod(Invocation invocation) - { - var memberName = _getMemberName(invocation.memberName); - - if (invocation.isMethod) - { - var ft = instance.template.getFunctionTemplateByName(memberName); - - if (_attached && ft!=null) - { - if (invocation.namedArguments.length > 0) - { - var namedArgs = new Structure(); - for(var p in invocation.namedArguments.keys) - namedArgs[_getMemberName(p)] = invocation.namedArguments[p]; - - return invokeByNamedArguments(ft.index, namedArgs); - } - else - { - return invokeByArrayArguments(ft.index, invocation.positionalArguments); - } - } - } - else if (invocation.isSetter) - { - var pt = instance.template.getPropertyTemplateByName(memberName); + return null; + } - if (pt != null) - { - set(pt.index, invocation.positionalArguments[0]); - return true; - } - } - else if (invocation.isGetter) - { - - var pt = instance.template.getPropertyTemplateByName(memberName); + /// + /// Get a property value. + /// + /// Zero-based property index. + /// Value + get(int index) { + if (index >= _properties.length) return null; + return _properties[index]; + } - if (pt != null) - { - return get(pt.index); - } - } - - return null; + void updatePropertyByIndex(int index, dynamic value) { + if (!_attached) { + _queued_updates.add(KeyValuePair(index, value)); + } else { + var pt = instance.template.getPropertyTemplateByIndex(index); + _properties[index] = value; + instance.emitModification(pt, value); } + } + /// + /// Set property value. + /// + /// Zero-based property index. + /// Value + /// Indicator when the property is set. + AsyncReply set(int index, dynamic value) { + if (index >= _properties.length) return null; + var reply = new AsyncReply(); - /// - /// Get a property value. - /// - /// Zero-based property index. - /// Value - get(int index) - { - if (index >= _properties.length) - return null; - return _properties[index]; - } + var parameters = Codec.compose(value, connection); + connection + .sendRequest(IIPPacketAction.SetProperty) + .addUint32(_instanceId) + .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); + }); - - void updatePropertyByIndex(int index, dynamic value) - { - if (!_attached) - { - _queued_updates.add(KeyValuePair(index, value)); - } - else - { - var pt = instance.template.getPropertyTemplateByIndex(index); - _properties[index] = value; - instance.emitModification(pt, value); - } - } - - /// - /// Set property value. - /// - /// Zero-based property index. - /// Value - /// Indicator when the property is set. - AsyncReply set(int index, dynamic value) - { - if (index >= _properties.length) - return null; - - var reply = new AsyncReply(); - - var parameters = Codec.compose(value, connection); - connection.sendRequest(IIPPacketAction.SetProperty) - .addUint32(_instanceId) - .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); - }); - - return reply; - } - - -} \ No newline at end of file + return reply; + } +} diff --git a/lib/src/Net/Packets/IIPAuthPacket.dart b/lib/src/Net/Packets/IIPAuthPacket.dart index e1bf2a4..600b34d 100644 --- a/lib/src/Net/Packets/IIPAuthPacket.dart +++ b/lib/src/Net/Packets/IIPAuthPacket.dart @@ -231,8 +231,8 @@ class IIPAuthPacket } else if (command == IIPAuthPacketCommand.Acknowledge) { - remoteMethod = ((data[offset] >> 4) & 0x3); - localMethod = ((data[offset] >> 2) & 0x3); + remoteMethod = AuthenticationMethod.values[ ((data[offset] >> 4) & 0x3)]; + localMethod = AuthenticationMethod.values[ ((data[offset] >> 2) & 0x3)]; var encrypt = ((data[offset++] & 0x2) == 0x2); if (_notEnough(offset, ends, 1)) diff --git a/lib/src/Resource/IStore.dart b/lib/src/Resource/IStore.dart index 06c2dd1..05f43f8 100644 --- a/lib/src/Resource/IStore.dart +++ b/lib/src/Resource/IStore.dart @@ -35,12 +35,11 @@ abstract class IStore implements IResource { AsyncReply get(String path); AsyncReply retrieve(int iid); - bool put(IResource resource); + AsyncReply put(IResource resource); String link(IResource resource); bool record(IResource resource, String propertyName, dynamic value, int age, DateTime dateTime); bool modify(IResource resource, String propertyName, dynamic value, int age, DateTime dateTime); bool remove(IResource resource); - AsyncReply>> getRecord(IResource resource, DateTime fromDate, DateTime toDate); } diff --git a/lib/src/Resource/Warehouse.dart b/lib/src/Resource/Warehouse.dart index cea61af..22e5df1 100644 --- a/lib/src/Resource/Warehouse.dart +++ b/lib/src/Resource/Warehouse.dart @@ -38,258 +38,223 @@ import 'ResourceTrigger.dart'; import '../Net/IIP/DistributedConnection.dart'; // Centeral Resource Issuer -class Warehouse -{ - static AutoList _stores = new AutoList(null); - static Map _resources = new Map(); - static int resourceCounter = 0; +class Warehouse { + static AutoList _stores = + new AutoList(null); + static Map _resources = new Map(); + static int resourceCounter = 0; - static KeyList _templates = new KeyList(); + static KeyList _templates = + new KeyList(); + //public delegate void StoreConnectedEvent(IStore store, string name); + //public delegate void StoreDisconnectedEvent(IStore store); - //public delegate void StoreConnectedEvent(IStore store, string name); - //public delegate void StoreDisconnectedEvent(IStore store); - - //public static event StoreConnectedEvent StoreConnected; - ///public static event StoreDisconnectedEvent StoreDisconnected; + //public static event StoreConnectedEvent StoreConnected; + ///public static event StoreDisconnectedEvent StoreDisconnected; - static bool _warehouseIsOpen = false; + static bool _warehouseIsOpen = false; - static KeyList protocols = _getSupportedProtocols(); + static KeyList Function(String, dynamic)> + protocols = _getSupportedProtocols(); - static final _urlRegex = RegExp(r'^(?:([^\s|:]*):\/\/([^\/]*)\/?(.*))'); + static final _urlRegex = RegExp(r'^(?:([^\s|:]*):\/\/([^\/]*)\/?(.*))'); - /// - /// Get a store by its name. - /// - /// Store instance name - /// - static IStore getStore(String name) - { - for(var s in _stores) - if (s.instance.name == name) - return s; - return null; - } + /// + /// Get a store by its name. + /// + /// Store instance name + /// + static IStore getStore(String name) { + for (var s in _stores) if (s.instance.name == name) return s; + return null; + } - /// - /// Get a resource by instance Id. - /// - /// Instance Id - /// - static AsyncReply getById(int id) - { - if (_resources.containsKey(id)) - return new AsyncReply.ready(_resources[id]); - else - return new AsyncReply.ready(null); - } + /// + /// Get a resource by instance Id. + /// + /// Instance Id + /// + static AsyncReply getById(int id) { + if (_resources.containsKey(id)) + return new AsyncReply.ready(_resources[id]); + else + return new AsyncReply.ready(null); + } - /// - /// Open the warehouse. - /// This function issues the initialize trigger to all stores and resources. - /// - /// True, if no problem occurred. - static AsyncReply open() - { - var bag = new AsyncBag(); + /// + /// Open the warehouse. + /// This function issues the initialize trigger to all stores and resources. + /// + /// True, if no problem occurred. + static AsyncReply open() { + var bag = new AsyncBag(); + for (var s in _stores) bag.add(s.trigger(ResourceTrigger.Initialize)); - for(var s in _stores) - bag.add(s.trigger(ResourceTrigger.Initialize)); - - - - bag.seal(); - - var rt = new AsyncReply(); - bag.then((x) - { - for (var b in x) - if (!b) - { - rt.trigger(false); - return; - } - - var rBag = new AsyncBag(); - for (var rk in _resources.keys) - rBag.add(_resources[rk].trigger(ResourceTrigger.SystemInitialized)); - - rBag.seal(); - - rBag.then((y) - { - for (var b in y) - if (!b) - { - rt.trigger(false); - return; - } - - rt.trigger(true); - _warehouseIsOpen = true; - }); - - }); - - return rt; - } - - /// - /// Close the warehouse. - /// This function issues terminate trigger to all resources and stores. - /// - /// True, if no problem occurred. - static AsyncReply close() - { - - var bag = new AsyncBag(); - - for (var resource in _resources.values) - if (!(resource is IStore)) - bag.add(resource.trigger(ResourceTrigger.Terminate)); - - for (var s in _stores) - bag.add(s.trigger(ResourceTrigger.Terminate)); - - for (var resource in _resources.values) - if (!(resource is IStore)) - bag.add(resource.trigger(ResourceTrigger.SystemTerminated)); - - for (var store in _stores) - bag.add(store.trigger(ResourceTrigger.SystemTerminated)); - - bag.seal(); - - var rt = new AsyncReply(); - bag.then((x) - { - for (var b in x) - if (!b) - { - rt.trigger(false); - return; - } - - rt.trigger(true); - }); - - return rt; - } - - - static List qureyIn(List path, int index, AutoList resources) - { - var rt = new List(); - - if (index == path.length - 1) - { - if (path[index] == "") - for (var child in resources) - rt.add(child); - else - for (var child in resources) - if (child.instance.name == path[index]) - rt.add(child); - } - else - for (var child in resources) - if (child.instance.name == path[index]) - rt.addAll(qureyIn(path, index+1, child.instance.children)); - - return rt; - } - - static AsyncReply> query(String path) - { - - - if (path == null || path == "") - { - var roots = _stores.where((s) => s.instance.parents.length == 0).toList(); - return new AsyncReply>.ready(roots); - } - else - { - var rt = new AsyncReply>(); - get(path).then((x) - { - var p = path.split('/'); - - if (x == null) - { - rt.trigger(qureyIn(p, 0, _stores)); - } - else - { - var ar = qureyIn(p, 0, _stores).where((r) => r != x).toList(); - ar.insert(0, x); - rt.trigger(ar); - } - }); - - return rt; + bag.seal(); + var rt = new AsyncReply(); + bag.then((x) { + for (var b in x) + if (!b) { + rt.trigger(false); + return; } + var rBag = new AsyncBag(); + for (var rk in _resources.keys) + rBag.add(_resources[rk].trigger(ResourceTrigger.SystemInitialized)); + + rBag.seal(); + + rBag.then((y) { + for (var b in y) + if (!b) { + rt.trigger(false); + return; + } + + rt.trigger(true); + _warehouseIsOpen = true; + }); + }); + + return rt; + } + + /// + /// Close the warehouse. + /// This function issues terminate trigger to all resources and stores. + /// + /// True, if no problem occurred. + static AsyncReply close() { + var bag = new AsyncBag(); + + for (var resource in _resources.values) + if (!(resource is IStore)) + bag.add(resource.trigger(ResourceTrigger.Terminate)); + + for (var s in _stores) bag.add(s.trigger(ResourceTrigger.Terminate)); + + for (var resource in _resources.values) + if (!(resource is IStore)) + bag.add(resource.trigger(ResourceTrigger.SystemTerminated)); + + for (var store in _stores) + bag.add(store.trigger(ResourceTrigger.SystemTerminated)); + + bag.seal(); + + var rt = new AsyncReply(); + bag.then((x) { + for (var b in x) + if (!b) { + rt.trigger(false); + return; + } + + rt.trigger(true); + }); + + return rt; + } + + static List qureyIn( + List path, int index, AutoList resources) { + var rt = new List(); + + if (index == path.length - 1) { + if (path[index] == "") + for (var child in resources) rt.add(child); + else + for (var child in resources) + if (child.instance.name == path[index]) rt.add(child); + } else + for (var child in resources) + if (child.instance.name == path[index]) + rt.addAll(qureyIn(path, index + 1, child.instance.children)); + + return rt; + } + + static AsyncReply> query(String path) { + if (path == null || path == "") { + var roots = _stores.where((s) => s.instance.parents.length == 0).toList(); + return new AsyncReply>.ready(roots); + } else { + var rt = new AsyncReply>(); + get(path).then((x) { + var p = path.split('/'); + + if (x == null) { + rt.trigger(qureyIn(p, 0, _stores)); + } else { + var ar = qureyIn(p, 0, _stores).where((r) => r != x).toList(); + ar.insert(0, x); + rt.trigger(ar); + } + }); + + return rt; + } + } + + /// + /// Get a resource by its path. + /// Resource path is sperated by '/' character, e.g. "system/http". + /// + /// + /// Resource instance. + static AsyncReply get(String path, + [attributes = null, + IResource parent = null, + IPermissionsManager manager = null]) { + var rt = AsyncReply(); + + // Should we create a new store ? + if (_urlRegex.hasMatch(path)) { + var url = _urlRegex.allMatches(path).first; + + if (protocols.containsKey(url[1])) { + var handler = protocols[url[1]]; + + var getFromStore = () { + handler(url[2], attributes).then((store) { + if (url[3].length > 0 && url[3] != "") + store.get(url[3]).then((r) { + rt.trigger(r); + }).error((e) => rt.triggerError(e)); + else + rt.trigger(store); + }).error((e) { + rt.triggerError(e); + //Warehouse.remove(store); + }); + }; + + if (!_warehouseIsOpen) + open().then((v) { + if (v) + getFromStore(); + else + rt.trigger(null); + }); + else + getFromStore(); + + return rt; + } } - /// - /// Get a resource by its path. - /// Resource path is sperated by '/' character, e.g. "system/http". - /// - /// - /// Resource instance. - static AsyncReply get(String path, [attributes = null, IResource parent = null, IPermissionsManager manager = null]) - { - var rt = new AsyncReply(); - - // Should we create a new store ? - if (_urlRegex.hasMatch(path)) - { - var url = _urlRegex.allMatches(path).first; - - if (protocols.containsKey(url[1])) - { - var handler = protocols[url[1]]; - - var store = handler(); - put(store, url[2], null, parent, null, 0, manager, attributes); - - store.trigger(ResourceTrigger.Open).then((x) - { - - _warehouseIsOpen = true; - - if (url[3].length > 0 && url[3] != "") - store.get(url[3]).then((r) - { - rt.trigger(r); - }).error((e) => rt.triggerError(e)); - else - rt.trigger(store); - }).error((e) - { - rt.triggerError(e); - Warehouse.remove(store); - }); - - return rt; - } - } - - - query(path).then((rs) - { - if (rs != null && rs.length > 0) - rt.trigger(rs[0]); - else - rt.trigger(null); - }); - - return rt; + query(path).then((rs) { + if (rs != null && rs.length > 0) + rt.trigger(rs[0]); + else + rt.trigger(null); + }); + return rt; /* var p = path.split('/'); @@ -359,154 +324,187 @@ class Warehouse return new AsyncReply.ready(null); */ + } + + /// + /// Put a resource in the warehouse. + /// + /// Resource instance. + /// 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, + [IStore store = null, + IResource parent = null, + ResourceTemplate customTemplate = null, + int age = 0, + IPermissionsManager manager = null, + attributes = null]) { + var rt = AsyncReply(); + + resource.instance = new Instance( + resourceCounter++, name, resource, store, customTemplate, age); + + if (attributes != null) + resource.instance.setAttributes(Structure.fromMap(attributes)); + + if (manager != null) resource.instance.managers.add(manager); + + if (store == parent) parent = null; + + if (parent == null) { + if (!(resource is IStore)) store.instance.children.add(resource); + } else + parent.instance.children.add(resource); + + var initResource = () { + _resources[resource.instance.id] = resource; + + if (_warehouseIsOpen) { + resource.trigger(ResourceTrigger.Initialize).then((value) { + if (resource is IStore) + resource.trigger(ResourceTrigger.Open).then((value) { + rt.trigger(value); + }).error((ex) => rt.triggerError(ex)); + else + rt.trigger(value); + }).error((ex) => rt.triggerError(ex)); + } + }; + + if (resource is IStore) { + _stores.add(resource); + initResource(); + } else { + store.put(resource).then((value) { + if (value) + initResource(); + else + rt.trigger(false); + }).error((ex) => rt.triggerError(ex)); } - /// - /// Put a resource in the warehouse. - /// - /// Resource instance. - /// 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 void put(IResource resource, String name, [IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, int age = 0, IPermissionsManager manager = null, attributes = null]) - { - resource.instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age); + return rt; + } - if (attributes != null) - resource.instance.setAttributes(Structure.fromMap(attributes)); - - if (manager != null) - resource.instance.managers.add(manager); - - if (store == parent) - parent = null; - - if (parent == null) - { - if (!(resource is IStore)) - store.instance.children.add(resource); - } - else - parent.instance.children.add(resource); - - - if (resource is IStore) - { - _stores.add(resource); - //StoreConnected?.Invoke(resource as IStore, name); - } - else - store.put(resource); - - _resources[resource.instance.id] = resource; - - if (_warehouseIsOpen) - resource.trigger(ResourceTrigger.Initialize); + static AsyncReply New(T resource, String name, + [IStore store = null, + IResource parent = null, + IPermissionsManager manager = null, + attributes = null, + properties = null]) { + if (properties != null) { + dynamic d = resource; + for (var i = 0; i < properties.length; i++) + d[properties.keys.elementAt(i)] = properties.at(i); + //setProperty(resource, properties.keys.elementAt(i), properties.at(i)); } - static T New(String name, [IStore store = null, IResource parent = null, IPermissionsManager manager = null, Structure attributes = null]) - { - /* + var rt = AsyncReply(); + + put(resource, name, store, parent, null, 0, manager, attributes) + .then((value) { + if (value) + rt.trigger(resource); + else + rt.trigger(null); + }).error((ex) => rt.triggerError(ex)); + + return rt; + + /* var type = ResourceProxy.GetProxy(); var res = Activator.CreateInstance(type) as IResource; put(res, name, store, parent, null, 0, manager, attributes); return (T)res; */ + } + + /// + /// 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); + } + + /// + /// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. + /// + /// .Net type. + /// Resource template. + static ResourceTemplate getTemplateByType(Type type) { + // loaded ? + for (var t in _templates.values) + if (t.className == type.toString()) return t; + + var template = new ResourceTemplate.fromType(type); + _templates.add(template.classId, template); + + 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. + /// + /// Class Id. + /// Resource template. + static AsyncReply getTemplateByClassId(Guid classId) { + if (_templates.containsKey(classId)) + return new AsyncReply.ready(_templates[classId]); + return null; + } + + /// + /// 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. + /// + /// Class name. + /// Resource template. + static AsyncReply getTemplateByClassName(String className) { + for (var t in _templates.values) + if (t.className == className) + return new AsyncReply.ready(t); + + return null; + } + + static bool remove(IResource resource) { + if (resource.instance == null) return false; + + if (_resources.containsKey(resource.instance.id)) + _resources.remove(resource.instance.id); + else + return false; + + if (resource is IStore) { + _stores.remove(resource); + + // remove all objects associated with the store + var toBeRemoved = + _resources.values.where((x) => x.instance.store == resource); + for (var o in toBeRemoved) remove(o); + + // StoreDisconnected?.Invoke(resource as IStore); } - /// - /// 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); - } + if (resource.instance.store != null) + resource.instance.store.remove(resource); + resource.destroy(); - /// - /// Get a template by type from the templates warehouse. If not in the warehouse, a new ResourceTemplate is created and added to the warehouse. - /// - /// .Net type. - /// Resource template. - static ResourceTemplate getTemplateByType(Type type) - { - // loaded ? - for (var t in _templates.values) - if (t.className == type.toString()) - return t; + return true; + } - var template = new ResourceTemplate.fromType(type); - _templates.add(template.classId, template); - - 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. - /// - /// Class Id. - /// Resource template. - static AsyncReply getTemplateByClassId(Guid classId) - { - if (_templates.containsKey(classId)) - return new AsyncReply.ready(_templates[classId]); - return null; - } - - /// - /// 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. - /// - /// Class name. - /// Resource template. - static AsyncReply getTemplateByClassName(String className) - { - for (var t in _templates.values) - if (t.className == className) - return new AsyncReply.ready(t); - - return null; - } - - static bool remove(IResource resource) - { - - if (resource.instance == null) - return false; - - if (_resources.containsKey(resource.instance.id)) - _resources.remove(resource.instance.id); - else - return false; - - if (resource is IStore) - { - _stores.remove(resource); - - // remove all objects associated with the store - var toBeRemoved = _resources.values.where((x) => x.instance.store == resource); - for (var o in toBeRemoved) - remove(o); - - // StoreDisconnected?.Invoke(resource as IStore); - } - - if (resource.instance.store != null) - resource.instance.store.remove(resource); - - resource.destroy(); - - return true; - } - - - static KeyList _getSupportedProtocols() - { - var rt = new KeyList(); - rt.add("iip", () => new DistributedConnection()); - return rt; - } + static KeyList Function(String, dynamic)> + _getSupportedProtocols() { + var rt = + new KeyList Function(String, dynamic)>(); + rt.add( + "iip", + (String name, attributes) => Warehouse.New( + DistributedConnection(), name, null, null, null, attributes)); + return rt; + } } - diff --git a/pubspec.yaml b/pubspec.yaml index 1b5ad85..c7f0fc9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,13 @@ name: esiur description: Distributed Object Framework. -version: 1.2.4 +version: 1.2.6 # author: Ahmed Zamil homepage: https://github.com/esiur/esiur-dart + environment: sdk: ">=2.1.0 <3.0.0" - + dev_dependencies: test: ^1.14.2 diff --git a/test/main.dart b/test/main.dart index 3c1924f..b45b75e 100644 --- a/test/main.dart +++ b/test/main.dart @@ -3,13 +3,14 @@ import 'package:esiur/esiur.dart'; import 'dart:io'; main() async { - test("Connect to server", () async { - // // // connect to the server - var x = await Warehouse.get("iip://localhost:5000/sys/su", + try { + var x = await Warehouse.get("iip://localhost:5070/sys/cp", {"username": "admin", "password": "1234", "domain": "example.com"}); - print(x); - }); + } catch (ex) { + print("Error occured"); + print(ex); + } } // describe object