2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 19:42:58 +00:00
This commit is contained in:
Ahmed Zamil 2019-11-10 12:41:31 +03:00
parent 8d06fd05ad
commit 5e87ea5247
41 changed files with 2076 additions and 431 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.5</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<Company>Esiur</Company> <Company>Esiur</Company>
<Product>Esiur MongoDB Store</Product> <Product>Esiur MongoDB Store</Product>
@ -11,12 +11,12 @@
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.2.5</Version> <Version>1.2.8</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MongoDB.Bson" Version="2.4.4" /> <PackageReference Include="MongoDB.Bson" Version="2.9.1" />
<PackageReference Include="MongoDB.Driver" Version="2.4.4" /> <PackageReference Include="MongoDB.Driver" Version="2.9.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -23,15 +23,22 @@ namespace Esiur.Stores.MongoDB
MongoClient client; MongoClient client;
IMongoDatabase database; IMongoDatabase database;
IMongoCollection<BsonDocument> resourcesCollection; IMongoCollection<BsonDocument> resourcesCollection;
//List<IResource> storeParents = new List<IResource>();
//List<IResource> storeChildren = new List<IResource>();
//string collectionName; //string collectionName;
//string dbName; //string dbName;
Dictionary<string, IResource> resources = new Dictionary<string, IResource>(); Dictionary<string, WeakReference> resources = new Dictionary<string, WeakReference>();
public int Count public long Count
{ {
get { return resources.Count; } get
{
return resourcesCollection.CountDocuments(x => true);
}// resources.Count; }
} }
public void Destroy() public void Destroy()
@ -77,21 +84,35 @@ namespace Esiur.Stores.MongoDB
return true; return true;
} }
AsyncReply<IResource> Fetch(string id) AsyncReply<T> Fetch<T>(string id) where T : IResource
{ {
if (resources.ContainsKey(id) && resources[id].IsAlive)
{
if (resources[id].Target is T)
return new AsyncReply<T>((T)resources[id].Target);
else
return new AsyncReply<T>(default(T)); ;
}
var filter = Builders<BsonDocument>.Filter.Eq("_id", new BsonObjectId(new ObjectId(id))); var filter = Builders<BsonDocument>.Filter.Eq("_id", new BsonObjectId(new ObjectId(id)));
var list = resourcesCollection.Find(filter).ToList(); var list = resourcesCollection.Find(filter).ToList();
if (list.Count == 0) if (list.Count == 0)
return new AsyncReply<IResource>(null); return new AsyncReply<T>(default(T));
var document = list[0]; var document = list[0];
var type = Type.GetType(document["classname"].AsString); var type = Type.GetType(document["classname"].AsString);
if (type == null) if (type == null)
return new AsyncReply<IResource>(null); return new AsyncReply<T>(default(T));
IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type)); IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type));
resources.Add(document["_id"].AsObjectId.ToString(), resource);
//var iid = document["_id"].AsObjectId.ToString();
if (resources.ContainsKey(id))
resources[id] = new WeakReference(resource);
else
resources.Add(id, new WeakReference(resource));
Warehouse.Put(resource, document["name"].AsString, this); Warehouse.Put(resource, document["name"].AsString, this);
@ -100,12 +121,14 @@ namespace Esiur.Stores.MongoDB
var children = document["children"].AsBsonArray; var children = document["children"].AsBsonArray;
//var managers = document["managers"].AsBsonArray; //var managers = document["managers"].AsBsonArray;
var attributes = Parse(document["attributes"]).Then(x=> { var attributes = Parse(document["attributes"]).Then(x =>
{
resource.Instance.SetAttributes(x as Structure); resource.Instance.SetAttributes(x as Structure);
}); });
var bag = new AsyncBag<object>(); var bag = new AsyncBag<object>();
/*
foreach (var p in parents) foreach (var p in parents)
{ {
var ap = Warehouse.Get(p.AsString); var ap = Warehouse.Get(p.AsString);
@ -128,6 +151,10 @@ namespace Esiur.Stores.MongoDB
resource.Instance.Children.Add(x); resource.Instance.Children.Add(x);
}); });
} }
*/
resource.Instance.Attributes.Add("children", children.Select(x => x.AsString).ToArray());
resource.Instance.Attributes.Add("parents", parents.Select(x => x.AsString).ToArray());
// Apply store managers // Apply store managers
foreach (var m in this.Instance.Managers) foreach (var m in this.Instance.Managers)
@ -154,27 +181,34 @@ namespace Esiur.Stores.MongoDB
foreach (var v in values) foreach (var v in values)
{ {
var valueInfo = v.Value as BsonDocument; var valueInfo = v.Value as BsonDocument;
var av = Parse(valueInfo["value"]); var av = Parse(valueInfo["value"]);
bag.Add(av);
av.Then((x) => av.Then((x) =>
{ {
resource.Instance.LoadProperty(v.Name, (ulong)valueInfo["age"].AsInt64, valueInfo["modification"].ToUniversalTime(), x); resource.Instance.LoadProperty(v.Name,
(ulong)valueInfo["age"].AsInt64,
valueInfo["modification"].ToUniversalTime(),
x);
}); });
bag.Add(av);
} }
bag.Seal(); var rt = new AsyncReply<T>();
var rt = new AsyncReply<IResource>();
bag.Then((x) => bag.Then((x) =>
{ {
rt.Trigger(resource); if (resource is T)
rt.Trigger(resource);
else
rt.Trigger(null);
}); });
bag.Seal();
return rt; return rt;
} }
@ -242,16 +276,22 @@ namespace Esiur.Stores.MongoDB
if (p[0] == "id") if (p[0] == "id")
{ {
// load from Id // load from Id
return Fetch<IResource>(p[1]);
/*
if (resources.ContainsKey(p[1])) if (resources.ContainsKey(p[1]))
return new AsyncReply<IResource>(resources[p[1]]); return new AsyncReply<IResource>(resources[p[1]]);
else else
return Fetch(p[1]); return Fetch(p[1]);
*/
} }
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
public string Link(IResource resource) public string Link(IResource resource)
{ {
return this.Instance.Name + "/id/" + (string)resource.Instance.Attributes["objectId"]; return this.Instance.Name + "/id/" + (string)resource.Instance.Attributes["objectId"];
@ -259,11 +299,17 @@ namespace Esiur.Stores.MongoDB
public bool Put(IResource resource) public bool Put(IResource resource)
{ {
PutResource(resource).Wait();
return true;
}
private async Task<bool> PutResource(IResource resource)
{
var attrs = resource.Instance.GetAttributes(); var attrs = resource.Instance.GetAttributes();
foreach (var kv in resources) foreach (var kv in resources)
if (kv.Value == resource) if (kv.Value.Target == resource)
{ {
resource.Instance.Attributes.Add("objectId", kv.Key); resource.Instance.Attributes.Add("objectId", kv.Key);
return true; return true;
@ -290,18 +336,41 @@ namespace Esiur.Stores.MongoDB
var template = resource.Instance.Template; var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children) // setup attributes
children.Add(c.Instance.Link); resource.Instance.Attributes["children"] = new string[0];
resource.Instance.Attributes["parents"] = new string[] { this.Instance.Link };
foreach (IResource p in resource.Instance.Parents) // copy old children (in case we are moving a resource from a store to another.
parents.Add(p.Instance.Link); if (resource.Instance.Store != this)
{
var resourceChildren = await resource.Instance.Children<IResource>();
if (resourceChildren != null)
foreach (IResource c in resourceChildren)
children.Add(c.Instance.Link);
var resourceParents = await resource.Instance.Parents<IResource>();
if (resourceParents == null)
{
parents.Add(this.Instance.Link);
}
else
{
foreach (IResource p in resourceParents)
parents.Add(p.Instance.Link);
}
}
else
{
// just add self
parents.Add(this.Instance.Link);
}
var attrsDoc = ComposeStructure(attrs); var attrsDoc = ComposeStructure(attrs);
var values = new BsonDocument(); var values = new BsonDocument();
foreach (var pt in template.Properties) foreach (var pt in template.Properties)
@ -314,10 +383,11 @@ namespace Esiur.Stores.MongoDB
{ "value", Compose(rt) } }); { "value", Compose(rt) } });
} }
// var filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
// var update = Builders<BsonDocument>.Update // var filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
// .Set("values", values); // var update = Builders<BsonDocument>.Update
// col.UpdateOne(filter, update); // .Set("values", values);
// col.UpdateOne(filter, update);
/* /*
@ -340,6 +410,7 @@ namespace Esiur.Stores.MongoDB
//resource.Instance.Attributes["objectId"] = document["_id"].ToString(); //resource.Instance.Attributes["objectId"] = document["_id"].ToString();
return true; return true;
} }
@ -454,8 +525,10 @@ namespace Esiur.Stores.MongoDB
resourcesCollection = this.database.GetCollection<BsonDocument>(collectionName); resourcesCollection = this.database.GetCollection<BsonDocument>(collectionName);
// return new AsyncReply<bool>(true); // return new AsyncReply<bool>(true);
/*
var filter = new BsonDocument(); var filter = new BsonDocument();
var list = resourcesCollection.Find(filter).ToList(); var list = resourcesCollection.Find(filter).ToList();
@ -476,15 +549,24 @@ namespace Esiur.Stores.MongoDB
var rt = new AsyncReply<bool>(); var rt = new AsyncReply<bool>();
bag.Then((x) => { rt.Trigger(true); }); bag.Then((x) => {
// storeChildren.AddRange(x);
rt.Trigger(true);
});
return rt; return rt;
*/
return new AsyncReply<bool>(true);
} }
else if (trigger == ResourceTrigger.Terminate) else if (trigger == ResourceTrigger.Terminate)
{ {
// save all resources // save all resources
foreach (var resource in resources.Values) foreach (var resource in resources.Values)
SaveResource(resource); if (resource.IsAlive)
SaveResource(resource.Target as IResource);
return new AsyncReply<bool>(true); return new AsyncReply<bool>(true);
} }
@ -501,11 +583,13 @@ namespace Esiur.Stores.MongoDB
var children = new BsonArray(); var children = new BsonArray();
var template = resource.Instance.Template; var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children) //foreach (IResource c in resource.Instance.Children)
children.Add(c.Instance.Link); // children.Add(c.Instance.Link);
foreach (IResource p in resource.Instance.Parents) var plist = resource.Instance.Attributes["parents"] as string[];
parents.Add(p.Instance.Link);
foreach (var link in plist)// Parents)
parents.Add(link);
var values = new BsonDocument(); var values = new BsonDocument();
@ -536,7 +620,7 @@ namespace Esiur.Stores.MongoDB
{ {
{ "parents", parents }, { "parents", parents },
{ "children", children }, { "children", children },
{"attributes", attrsDoc }, { "attributes", attrsDoc },
{ "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name }, { "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name },
{ "name", resource.Instance.Name }, { "name", resource.Instance.Name },
{ "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) }, { "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) },
@ -576,7 +660,7 @@ namespace Esiur.Stores.MongoDB
var bag = new AsyncBag<object>(); var bag = new AsyncBag<object>();
foreach(var v in values) foreach (var v in values)
bag.Add(Parse(v["value"])); bag.Add(Parse(v["value"]));
bag.Seal(); bag.Seal();
@ -584,7 +668,7 @@ namespace Esiur.Stores.MongoDB
bag.Then((results) => bag.Then((results) =>
{ {
var list = new List<PropertyValue>(); var list = new List<PropertyValue>();
for(var i = 0; i < results.Length; i++) for (var i = 0; i < results.Length; i++)
list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime()));
reply.Trigger(list.ToArray()); reply.Trigger(list.ToArray());
@ -701,5 +785,130 @@ namespace Esiur.Stores.MongoDB
} }
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
if (resource == this)
{
IFindFluent<BsonDocument, BsonDocument> match;
if (name == null)
match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name));
else
match = resourcesCollection.Find(x => (x["parents"] as BsonArray).Contains(this.Instance.Name) && x["name"] == name);
var st = match.ToList().Select(x => x["_id"].ToString()).ToArray();
var bag = new AsyncBag<T>();
foreach (var s in st)
{
var r = Fetch<T>(s);
if (r.Ready && r.Result == null)
continue;
bag.Add(r);
}
bag.Seal();
return bag;
}
else
{
var children = (string[])resource.Instance.Attributes["children"];
if (children == null)
{
return new AsyncBag<T>(null);
}
var rt = new AsyncBag<T>();
foreach (var child in children)
{
var r = Warehouse.Get(child);
if (r is IAsyncReply<T>)
rt.Add((IAsyncReply<T>)r);
}
rt.Seal();
return rt;
}
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
Console.WriteLine("Parents start");
if (resource == this)
{
return new AsyncBag<T>(null);
}
else
{
Console.WriteLine("Parents 1");
var parents = (string[])resource.Instance.Attributes["parents"];
if (parents == null)
{
return new AsyncBag<T>(null);
}
var rt = new AsyncBag<T>();
Console.WriteLine("Parents 2");
foreach (var parent in parents)
{
var r = Warehouse.Get(parent);
if (r is IAsyncReply<T>)
rt.Add((IAsyncReply<T>)r);
}
Console.WriteLine($"Parents 3 {parents.Length}");
rt.Seal();
Console.WriteLine("Parents end");
return rt;
}
}
public AsyncReply<bool> AddChild(IResource resource, IResource child)
{
var list = (string[])resource.Instance.Attributes["children"];
resource.Instance.Attributes["children"] = list.Concat(new string[] { child.Instance.Link }).ToArray();
SaveResource(resource);
return new AsyncReply<bool>(true);
}
public AsyncReply<bool> RemoveChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource resource, IResource parent)
{
var list = (string[])resource.Instance.Attributes["parents"];
resource.Instance.Attributes["parents"] = list.Concat(new string[] { parent.Instance.Link }).ToArray();
SaveResource(resource);
return new AsyncReply<bool>(true);
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
} }
} }

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.17" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Esiur\Esiur.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,718 @@
using Esiur.Resource;
using System;
using Esiur.Core;
using Esiur.Data;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Esiur.Resource.Template;
using System.Linq;
using Esiur.Security.Permissions;
using Esiur.Proxy;
using MySql.Data.MySqlClient;
namespace Esiur.Stores.MySql
{
public class MySqlStore : IStore
{
public Instance Instance { get; set; }
public event DestroyedEvent OnDestroy;
string connectionString;
Dictionary<string, IResource> resources = new Dictionary<string, IResource>();
public int Count
{
get { return resources.Count; }
}
public void Destroy()
{
}
public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
//var bsonObjectId = new BsonObjectId(new ObjectId(objectId));
var record = this.database.GetCollection<BsonDocument>("record_" + objectId);
record.InsertOne(new BsonDocument()
{
{"property", propertyName}, {"age", BsonValue.Create(age) }, {"date", date}, {"value", Compose(value) }
});
//var col = this.database.GetCollection<BsonDocument>(collectionName);
var filter = Builders<BsonDocument>.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId)));
var update = Builders<BsonDocument>.Update
.Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) },
{ "modification", date },
{ "value", Compose(value) } });
resourcesCollection.UpdateOne(filter, update);
return true;
}
public bool Remove(IResource resource)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
var filter = Builders<BsonDocument>.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId)));
this.database.DropCollection("record_" + objectId);
resourcesCollection.DeleteOne(filter);
return true;
}
AsyncReply<IResource> Fetch(string id)
{
MySqlHelper.
var filter = Builders<BsonDocument>.Filter.Eq("_id", new BsonObjectId(new ObjectId(id)));
var list = resourcesCollection.Find(filter).ToList();
if (list.Count == 0)
return new AsyncReply<IResource>(null);
var document = list[0];
var type = Type.GetType(document["classname"].AsString);
if (type == null)
return new AsyncReply<IResource>(null);
IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type));
resources.Add(document["_id"].AsObjectId.ToString(), resource);
Warehouse.Put(resource, document["name"].AsString, this);
var parents = document["parents"].AsBsonArray;
var children = document["children"].AsBsonArray;
//var managers = document["managers"].AsBsonArray;
var attributes = Parse(document["attributes"]).Then(x => {
resource.Instance.SetAttributes(x as Structure);
});
var bag = new AsyncBag<object>();
foreach (var p in parents)
{
var ap = Warehouse.Get(p.AsString);
bag.Add(ap);
ap.Then((x) =>
{
if (!resource.Instance.Parents.Contains(x))
resource.Instance.Parents.Add(x);
});
}
foreach (var c in children)
{
var ac = Warehouse.Get(c.AsString);
bag.Add(ac);
ac.Then((x) =>
{
if (!resource.Instance.Children.Contains(x))
resource.Instance.Children.Add(x);
});
}
// Apply store managers
foreach (var m in this.Instance.Managers)
resource.Instance.Managers.Add(m);
/*
// load managers
foreach(var m in managers)
{
IPermissionsManager pm = (IPermissionsManager)Activator.CreateInstance(Type.GetType(m["classname"].AsString));
var sr = Parse(m["settings"]);
bag.Add(sr);
sr.Then((x) =>
{
pm.Initialize((Structure)x, resource);
resource.Instance.Managers.Add(pm);
});
}
*/
// Load values
var values = document["values"].AsBsonDocument;
foreach (var v in values)
{
var valueInfo = v.Value as BsonDocument;
var av = Parse(valueInfo["value"]);
bag.Add(av);
av.Then((x) =>
{
resource.Instance.LoadProperty(v.Name, (ulong)valueInfo["age"].AsInt64, valueInfo["modification"].ToUniversalTime(), x);
});
}
bag.Seal();
var rt = new AsyncReply<IResource>();
bag.Then((x) =>
{
rt.Trigger(resource);
});
return rt;
}
IAsyncReply<object> Parse(BsonValue value)
{
if (value.BsonType == BsonType.Document)
{
var doc = value.AsBsonDocument;
if (doc["type"] == 0)
{
return Warehouse.Get(doc["link"].AsString);
} // structure
else if (doc["type"] == 1)
{
var bag = new AsyncBag<object>();
var rt = new AsyncReply<Structure>();
var bs = (BsonDocument)doc["values"].AsBsonDocument;
var s = new Structure();
foreach (var v in bs)
bag.Add(Parse(v.Value));
bag.Seal();
bag.Then((x) =>
{
for (var i = 0; i < x.Length; i++)
s[bs.GetElement(i).Name] = x[i];
rt.Trigger(s);
});
return rt;
}
else
return new AsyncReply<object>(null);
}
else if (value.BsonType == BsonType.Array)
{
var array = value.AsBsonArray;
var bag = new AsyncBag<object>();
foreach (var v in array)
bag.Add(Parse(v));
bag.Seal();
return bag;
}
else if (value.BsonType == BsonType.DateTime)
{
return new AsyncReply<object>(value.ToUniversalTime());
}
else
{
return new AsyncReply<object>(value.RawValue);
}
}
public AsyncReply<IResource> Get(string path)
{
var p = path.Split('/');
if (p.Length == 2)
if (p[0] == "id")
{
// load from Id
if (resources.ContainsKey(p[1]))
return new AsyncReply<IResource>(resources[p[1]]);
else
return Fetch(p[1]);
}
return new AsyncReply<IResource>(null);
}
public string Link(IResource resource)
{
return this.Instance.Name + "/id/" + (string)resource.Instance.Attributes["objectId"];
}
string MakeTable(Type type)
{
var props = type.GetTypeInfo().GetProperties();
foreach(var p in props)
{
var rp = p.GetCustomAttribute<ResourceProperty>();
if (rp == null)
continue;
}
}
public bool Put(IResource resource)
{
var attrs = resource.Instance.GetAttributes();
foreach (var kv in resources)
if (kv.Value == resource)
{
resource.Instance.Attributes.Add("objectId", kv.Key);
return true;
}
var type = ResourceProxy.GetBaseType(resource);
// insert the document
var document = new BsonDocument
{
{ "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name },
{ "name", resource.Instance.Name },
};
resourcesCollection.InsertOne(document);
resource.Instance.Attributes["objectId"] = document["_id"].ToString();
// now update the document
// * insert first to get the object id, update values, attributes, children and parents after in case the same resource has a property references self
var parents = new BsonArray();
var children = new BsonArray();
var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children)
children.Add(c.Instance.Link);
foreach (IResource p in resource.Instance.Parents)
parents.Add(p.Instance.Link);
var attrsDoc = ComposeStructure(attrs);
var values = new BsonDocument();
foreach (var pt in template.Properties)
{
var rt = pt.Info.GetValue(resource, null);
values.Add(pt.Name,
new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) },
{ "modification", resource.Instance.GetModificationDate(pt.Index) },
{ "value", Compose(rt) } });
}
// var filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
// var update = Builders<BsonDocument>.Update
// .Set("values", values);
// col.UpdateOne(filter, update);
/*
var document = new BsonDocument
{
{ "parents", parents },
{ "children", children },
{ "attributes", attrsDoc },
{ "classname", resource.GetType().FullName + "," + resource.GetType().GetTypeInfo().Assembly.GetName().Name },
{ "name", resource.Instance.Name },
{ "values", values }
};
*/
var filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
var update = Builders<BsonDocument>.Update
.Set("values", values).Set("parents", parents).Set("children", children).Set("attributes", attrsDoc);
resourcesCollection.UpdateOne(filter, update);
//resource.Instance.Attributes["objectId"] = document["_id"].ToString();
return true;
}
public BsonDocument ComposeStructure(Structure value)
{
var rt = new BsonDocument { { "type", 1 } };
var values = new BsonDocument();
foreach (var i in value)
values.Add(i.Key, Compose(i.Value));
rt.Add("values", values);
return rt;
}
public BsonArray ComposeVarArray(object[] array)
{
var rt = new BsonArray();
for (var i = 0; i < array.Length; i++)
rt.Add(Compose(array[i]));
return rt;
}
BsonArray ComposeStructureArray(Structure[] structures)
{
var rt = new BsonArray();
if (structures == null || structures?.Length == 0)
return rt;
foreach (var s in structures)
rt.Add(ComposeStructure(s));
return rt;
}
BsonArray ComposeResourceArray(IResource[] array)
{
var rt = new BsonArray();
foreach (var r in array)
{
rt.Add(new BsonDocument { { "type", 0 }, { "link", r.Instance.Link } });
//if (r.Instance.Attributes.ContainsKey("objectId"))
//rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Attributes["objectId"])));
}
return rt;
}
private BsonValue Compose(object value)
{
var type = Codec.GetDataType(value, null);
switch (type)
{
case DataType.Void:
// nothing to do;
return BsonNull.Value;
case DataType.String:
return new BsonString((string)value);
case DataType.Resource:
case DataType.DistributedResource:
return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } };
//return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Attributes["objectId"]));
case DataType.Structure:
return ComposeStructure((Structure)value);
case DataType.VarArray:
return ComposeVarArray((object[])value);
case DataType.ResourceArray:
if (value is IResource[])
return ComposeResourceArray((IResource[])value);
else
return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[])));
case DataType.StructureArray:
return ComposeStructureArray((Structure[])value);
default:
return BsonValue.Create(value);
}
}
public AsyncReply<IResource> Retrieve(uint iid)
{
throw new NotImplementedException();
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
var collectionName = Instance.Attributes["Collection"] as string ?? "resources";
var dbName = Instance.Attributes["Database"] as string ?? "esiur";
client = new MongoClient(Instance.Attributes["Connection"] as string ?? "mongodb://localhost");
database = client.GetDatabase(dbName);
resourcesCollection = this.database.GetCollection<BsonDocument>(collectionName);
// return new AsyncReply<bool>(true);
var filter = new BsonDocument();
var list = resourcesCollection.Find(filter).ToList();
// if (list.Count == 0)
// return new AsyncBag<IResource>(new IResource[0]);
var bag = new AsyncBag<IResource>();
for (var i = 0; i < list.Count; i++)
{
//Console.WriteLine("Loading {0}/{1}", i, list.Count);
bag.Add(Get("id/" + list[i]["_id"].AsObjectId.ToString()));
}
bag.Seal();
var rt = new AsyncReply<bool>();
bag.Then((x) => { rt.Trigger(true); });
return rt;
}
else if (trigger == ResourceTrigger.Terminate)
{
// save all resources
foreach (var resource in resources.Values)
SaveResource(resource);
return new AsyncReply<bool>(true);
}
else
return new AsyncReply<bool>(true);
}
public void SaveResource(IResource resource)
{
var attrs = resource.Instance.GetAttributes();
var parents = new BsonArray();
var children = new BsonArray();
var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children)
children.Add(c.Instance.Link);
foreach (IResource p in resource.Instance.Parents)
parents.Add(p.Instance.Link);
var values = new BsonDocument();
foreach (var pt in template.Properties)
{
/*
#if NETSTANDARD1_5
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
*/
var rt = pt.Info.GetValue(resource, null);
values.Add(pt.Name,
new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) },
{ "modification", resource.Instance.GetModificationDate(pt.Index) },
{ "value", Compose(rt) } });
}
var attrsDoc = ComposeStructure(attrs);
var type = ResourceProxy.GetBaseType(resource);
var document = new BsonDocument
{
{ "parents", parents },
{ "children", children },
{"attributes", attrsDoc },
{ "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name },
{ "name", resource.Instance.Name },
{ "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) },
{"values", values }
};
var filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
/*
var update = Builders<BsonDocument>.Update
.Set("values", values);
var update = Builders<BsonDocument>.Update.Set("values", values).Set("parents", parents;
col.UpdateOne(filter, update);
*/
resourcesCollection.ReplaceOne(filter, document);
}
public AsyncReply<PropertyValue[]> GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
var record = this.database.GetCollection<BsonDocument>("record_" + objectId);
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Gte("age", fromAge) & builder.Lte("age", toAge) & builder.Eq("property", propertyName);
var reply = new AsyncReply<PropertyValue[]>();
record.FindAsync(filter).ContinueWith((x) =>
{
var values = ((Task<IAsyncCursor<BsonDocument>>)x).Result.ToList();
var bag = new AsyncBag<object>();
foreach (var v in values)
bag.Add(Parse(v["value"]));
bag.Seal();
bag.Then((results) =>
{
var list = new List<PropertyValue>();
for (var i = 0; i < results.Length; i++)
list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime()));
reply.Trigger(list.ToArray());
});
});
return reply;
}
public AsyncReply<PropertyValue[]> GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
var record = this.database.GetCollection<BsonDocument>("record_" + objectId);
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Gte("date", fromDate) & builder.Lte("date", toDate) & builder.Eq("property", propertyName);
var reply = new AsyncReply<PropertyValue[]>();
record.FindAsync(filter).ContinueWith((x) =>
{
var values = ((Task<IAsyncCursor<BsonDocument>>)x).Result.ToList();
var bag = new AsyncBag<object>();
foreach (var v in values)
bag.Add(Parse(v["value"]));
bag.Seal();
bag.Then((results) =>
{
var list = new List<PropertyValue>();
for (var i = 0; i < results.Length; i++)
list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime()));
reply.Trigger(list.ToArray());
});
});
return reply;
}
AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecordByAge(IResource resource, ulong fromAge, ulong toAge)
{
var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList();
var reply = new AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>>();
AsyncBag<PropertyValue[]> bag = new AsyncBag<PropertyValue[]>();
foreach (var p in properties)
bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge));
bag.Seal();
bag.Then(x =>
{
var list = new KeyList<PropertyTemplate, PropertyValue[]>();
for (var i = 0; i < x.Length; i++)
list.Add(properties[i], x[i]);
reply.Trigger(list);
});
return reply;
}
public AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate)
{
var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList();
var reply = new AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>>();
AsyncBag<PropertyValue[]> bag = new AsyncBag<PropertyValue[]>();
foreach (var p in properties)
bag.Add(GetPropertyRecordByDate(resource, p.Name, fromDate, toDate));
bag.Seal();
bag.Then(x =>
{
var list = new KeyList<PropertyTemplate, PropertyValue[]>();
for (var i = 0; i < x.Length; i++)
list.Add(properties[i], x[i]);
reply.Trigger(list);
});
return reply;
}
public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
{
var sql = $"UPDATE `{resource.Instance.Template.ClassName}` SET `{propertyName}` = @value, `{propertyName}_age` = @age, `{propertyName}_date` = @date WHERE `_id` = @id";
MySqlHelper.ExecuteNonQuery(connectionString, sql,
new MySqlParameter("@value", value),
new MySqlParameter("@age", age),
new MySqlParameter("@date", dateTime),
new MySqlParameter("@id", resource.Instance.Attributes["objectId"]));
return true;
}
}
}

View File

@ -1,13 +1,12 @@

Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
VisualStudioVersion = 15.0.26228.9 VisualStudioVersion = 16.0.29324.140
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur", "Esiur\Esiur.csproj", "{DEBF78DB-E3B3-47F4-994C-5C970E98C686}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur", "Esiur\Esiur.csproj", "{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{08AC2E1C-24F0-4309-B35E-73D36A427D2D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.MongoDB", "Esiur.Stores.MongoDB\Esiur.Stores.MongoDB.csproj", "{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Esiur.Stores.MongoDB", "Esiur.Stores.MongoDB\Esiur.Stores.MongoDB.csproj", "{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.MySql", "Esiur.Stores.MySql\Esiur.Stores.MySql.csproj", "{7BD6148A-3335-411C-9189-3803B1824264}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -15,20 +14,23 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Release|Any CPU.Build.0 = Release|Any CPU {4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Release|Any CPU.Build.0 = Release|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Release|Any CPU.Build.0 = Release|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.Build.0 = Release|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Release|Any CPU.Build.0 = Release|Any CPU {7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C584421D-5EC0-4821-B7D8-2633D8D405F2}
EndGlobalSection
EndGlobal EndGlobal

View File

@ -2,39 +2,51 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core namespace Esiur.Core
{ {
public class AsyncAwaiter<T> : INotifyCompletion public class AsyncAwaiter<T> : INotifyCompletion
{ {
public Action callback = null; Action callback = null;
public T result;
private bool completed; AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> reply) public AsyncAwaiter(AsyncReply<T> reply)
{ {
reply.Then(x => reply.Then(x =>
{ {
this.completed = true; this.IsCompleted = true;
this.result = x; this.result = x;
this.callback?.Invoke(); this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
}); });
} }
public T GetResult() public T GetResult()
{ {
if (exception != null)
throw exception;
return result; return result;
} }
public bool IsCompleted => completed; public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation) public void OnCompleted(Action continuation)
{ {
// Continue.... if (IsCompleted)
callback = continuation; continuation?.Invoke();
else
// Continue....
callback = continuation;
} }
} }
} }

View File

@ -95,5 +95,11 @@ namespace Esiur.Core
} }
public AsyncBag(T[] results)
{
resultReady = true;
base.result = results;
}
} }
} }

View File

@ -34,9 +34,12 @@ using System.Runtime.CompilerServices;
namespace Esiur.Core namespace Esiur.Core
{ {
public class AsyncReply<T>: IAsyncReply<T> [AsyncMethodBuilder(typeof(AsyncReply<>))]
public class AsyncReply<T> : IAsyncReply<T>
{ {
public bool Debug = false;
protected List<Action<T>> callbacks = new List<Action<T>>(); protected List<Action<T>> callbacks = new List<Action<T>>();
protected T result; protected T result;
@ -48,11 +51,12 @@ namespace Esiur.Core
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>(); //List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
object callbacksLock = new object(); // object callbacksLock = new object();
protected bool resultReady = false; protected bool resultReady = false;
AsyncException exception; AsyncException exception;
AutoResetEvent mutex = new AutoResetEvent(false);
public bool Ready public bool Ready
{ {
@ -60,6 +64,23 @@ namespace Esiur.Core
} }
public T Wait()
{
if (resultReady)
return result;
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Wait");
//mutex = new AutoResetEvent(false);
mutex.WaitOne();
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Wait ended");
return result;
}
public object Result public object Result
@ -69,53 +90,91 @@ namespace Esiur.Core
public IAsyncReply<T> Then(Action<T> callback) public IAsyncReply<T> Then(Action<T> callback)
{ {
callbacks.Add(callback); //lock (callbacksLock)
//{
if (resultReady) if (resultReady)
{
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Then ready");
callback(result); callback(result);
return this;
}
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Then pending");
callbacks.Add(callback);
return this; return this;
//}
} }
public IAsyncReply<T> Error(Action<AsyncException> callback) public IAsyncReply<T> Error(Action<AsyncException> callback)
{ {
// lock (callbacksLock)
// {
errorCallbacks.Add(callback); errorCallbacks.Add(callback);
if (exception != null) if (exception != null)
callback(exception); callback(exception);
return this; return this;
//}
} }
public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback) public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{ {
//lock (callbacksLock)
//{
progressCallbacks.Add(callback); progressCallbacks.Add(callback);
return this; return this;
//}
} }
public IAsyncReply<T> Chunk(Action<T> callback) public IAsyncReply<T> Chunk(Action<T> callback)
{ {
// lock (callbacksLock)
// {
chunkCallbacks.Add(callback); chunkCallbacks.Add(callback);
return this; return this;
// }
} }
public void Trigger(object result) public void Trigger(object result)
{ {
lock (callbacksLock) if (Debug)
{ Console.WriteLine($"AsyncReply: {GetHashCode()} Trigger");
if (resultReady)
return;
this.result = (T)result;
resultReady = true;
foreach (var cb in callbacks)
cb((T)result);
} //lock (callbacksLock)
//{
if (resultReady)
return;
this.result = (T)result;
resultReady = true;
//if (mutex != null)
mutex.Set();
foreach (var cb in callbacks)
cb((T)result);
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Trigger ended");
//}
} }
@ -130,11 +189,13 @@ namespace Esiur.Core
this.exception = new AsyncException(ErrorType.Management, 0, exception.Message); this.exception = new AsyncException(ErrorType.Management, 0, exception.Message);
lock (callbacksLock) // lock (callbacksLock)
{ // {
foreach (var cb in errorCallbacks) foreach (var cb in errorCallbacks)
cb(this.exception); cb(this.exception);
} // }
mutex?.Set();
} }
@ -143,12 +204,12 @@ namespace Esiur.Core
if (resultReady) if (resultReady)
return; return;
lock (callbacksLock) //lock (callbacksLock)
{ //{
foreach (var cb in progressCallbacks) foreach (var cb in progressCallbacks)
cb(type, value, max); cb(type, value, max);
} //}
} }
@ -157,12 +218,12 @@ namespace Esiur.Core
if (resultReady) if (resultReady)
return; return;
lock (callbacksLock) //lock (callbacksLock)
{ //{
foreach (var cb in chunkCallbacks) foreach (var cb in chunkCallbacks)
cb((T)value); cb((T)value);
} //}
} }
public AsyncAwaiter<T> GetAwaiter() public AsyncAwaiter<T> GetAwaiter()
@ -172,15 +233,14 @@ namespace Esiur.Core
public AsyncReply() public AsyncReply()
{ {
//this.Debug = true;
} }
public AsyncReply(T result) public AsyncReply(T result)
{ {
//this.Debug = true;
resultReady = true; resultReady = true;
this.result = result; this.result = result;
} }
@ -218,7 +278,7 @@ namespace Esiur.Core
return base.Task.ContinueWith<T>((t) => return base.Task.ContinueWith<T>((t) =>
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else #else
return (T)t.GetType().GetProperty("Result").GetValue(t); return (T)t.GetType().GetProperty("Result").GetValue(t);

View File

@ -16,6 +16,6 @@ namespace Esiur.Core
void TriggerProgress(ProgressType type, int value, int max); void TriggerProgress(ProgressType type, int value, int max);
void TriggerChunk(object value); void TriggerChunk(object value);
T Wait();
} }
} }

View File

@ -96,7 +96,7 @@ namespace Esiur.Data
public AutoList(ST state) public AutoList(ST state)
{ {
this.state = state; this.state = state;
#if NETSTANDARD1_5 #if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
@ -111,7 +111,7 @@ namespace Esiur.Data
public AutoList(ST state, T[] values) public AutoList(ST state, T[] values)
{ {
this.state = state; this.state = state;
#if NETSTANDARD1_5 #if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));

View File

@ -62,7 +62,7 @@ namespace Esiur.Data
list.Add((byte)i); list.Add((byte)i);
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else #else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });
@ -100,7 +100,7 @@ namespace Esiur.Data
list.Add((byte)i); list.Add((byte)i);
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else #else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });
@ -138,7 +138,7 @@ namespace Esiur.Data
} }
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else #else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() }); MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });

View File

@ -34,6 +34,7 @@ using Esiur.Resource;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Esiur.Resource.Template; using Esiur.Resource.Template;
using System.Runtime.CompilerServices;
namespace Esiur.Data namespace Esiur.Data
{ {
@ -171,7 +172,7 @@ namespace Esiur.Data
var result = (StructureComparisonResult)data[offset++]; var result = (StructureComparisonResult)data[offset++];
IAsyncReply<Structure> previous = null; AsyncReply<Structure> previous = null;
// string[] previousKeys = null; // string[] previousKeys = null;
// DataType[] previousTypes = null; // DataType[] previousTypes = null;
@ -1064,6 +1065,16 @@ namespace Esiur.Data
return rt.ToArray(); return rt.ToArray();
} }
public static bool IsAnonymous(Type type)
{
// Detect anonymous types
var info = type.GetTypeInfo();
var hasCompilerGeneratedAttribute = info.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0;
var nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
return hasCompilerGeneratedAttribute && nameContainsAnonymousType;
}
/// <summary> /// <summary>
/// Check if a type implements an interface /// Check if a type implements an interface
/// </summary> /// </summary>
@ -1086,7 +1097,7 @@ namespace Esiur.Data
if (type == iface) if (type == iface)
return true; return true;
#if NETSTANDARD1_5 #if NETSTANDARD
if (type.GetTypeInfo().GetInterfaces().Contains(iface))// (x=>x.GetTypeInfo().IsGenericType (iface)) if (type.GetTypeInfo().GetInterfaces().Contains(iface))// (x=>x.GetTypeInfo().IsGenericType (iface))
return true; return true;
@ -1109,7 +1120,7 @@ namespace Esiur.Data
if (type == iface) if (type == iface)
return true; return true;
#if NETSTANDARD1_5 #if NETSTANDARD
if (type.GetTypeInfo().GetInterfaces().Contains(iface)) if (type.GetTypeInfo().GetInterfaces().Contains(iface))
return true; return true;
@ -1137,7 +1148,7 @@ namespace Esiur.Data
{ {
if (childType == parentType) if (childType == parentType)
return true; return true;
#if NETSTANDARD1_5 #if NETSTANDARD
childType = childType.GetTypeInfo().BaseType; childType = childType.GetTypeInfo().BaseType;
#else #else
childType = childType.BaseType; childType = childType.BaseType;

View File

@ -67,7 +67,7 @@ namespace Esiur.Data
{ {
try try
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
if (destinationType.GetTypeInfo().IsInstanceOfType(v.GetValue(i))) if (destinationType.GetTypeInfo().IsInstanceOfType(v.GetValue(i)))
#else #else
if (destinationType.IsInstanceOfType(v.GetValue(i))) if (destinationType.IsInstanceOfType(v.GetValue(i)))
@ -97,7 +97,7 @@ namespace Esiur.Data
destinationType = underType; destinationType = underType;
} }
#if NETSTANDARD1_5 #if NETSTANDARD
if (destinationType.GetTypeInfo().IsInstanceOfType(value)) if (destinationType.GetTypeInfo().IsInstanceOfType(value))
#else #else
if (destinationType.IsInstanceOfType(value)) if (destinationType.IsInstanceOfType(value))
@ -589,7 +589,7 @@ namespace Esiur.Data
{ {
try try
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var tryParse = typeof(T).GetTypeInfo().GetDeclaredMethod("TryParse"); var tryParse = typeof(T).GetTypeInfo().GetDeclaredMethod("TryParse");
if ((bool)tryParse.Invoke(null, new object[] { Input, null })) if ((bool)tryParse.Invoke(null, new object[] { Input, null }))
{ {

View File

@ -220,7 +220,7 @@ namespace Esiur.Data
public KeyList(object owner = null) public KeyList(object owner = null)
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else #else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));

View File

@ -31,6 +31,7 @@ using System.Threading.Tasks;
using Esiur.Data; using Esiur.Data;
using Esiur.Misc; using Esiur.Misc;
using Esiur.Core; using Esiur.Core;
using System.Reflection;
namespace Esiur.Data namespace Esiur.Data
{ {
@ -61,6 +62,26 @@ namespace Esiur.Data
return rt.TrimEnd('\r', '\n'); return rt.TrimEnd('\r', '\n');
} }
public static Structure FromObject(object obj)
{
var type = obj.GetType();
if (obj is Structure)
return obj as Structure;
else if (Codec.IsAnonymous(type))
{
var st = new Structure();
var pi = type.GetTypeInfo().GetProperties();
foreach (var p in pi)
st[p.Name] = p.GetValue(obj);
return st;
}
else
return null;
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{ {
return dic.GetEnumerator(); return dic.GetEnumerator();

View File

@ -1,23 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.5</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Description>Distributed Resources Platform</Description> <Description>Distributed Resources Platform</Description>
<Copyright>Ahmed Kh. Zamil</Copyright> <Copyright>Ahmed Kh. Zamil</Copyright>
<PackageLicenseUrl>https://github.com/esiur/esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/esiur/esiur-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.2.7</Version> <Version>1.4.0</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.2.7.0</AssemblyVersion> <AssemblyVersion>1.3.1.0</AssemblyVersion>
<Company>Esiur Foundation</Company> <Company>Esiur Foundation</Company>
<FileVersion>1.2.7.0</FileVersion> <FileVersion>1.3.1.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<DefineConstants>TRACE;DEBUG;NETSTANDARD1_5</DefineConstants> <DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@ -46,6 +46,7 @@
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" /> <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.1" /> <PackageReference Include="System.Net.Security" Version="4.3.1" />
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" /> <PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -72,20 +72,20 @@ namespace Esiur.Net.DataLink
{ {
if (trigger == ResourceTrigger.Initialize) if (trigger == ResourceTrigger.Initialize)
{ {
/*
foreach (Instance instance in Instance.Children) foreach (var resource in Instance.Children<IResource>())
{ {
if (instance.Resource is PacketFilter) if (resource is PacketFilter)
{ {
filters.Add(instance.Resource as PacketFilter); filters.Add(resource as PacketFilter);
} }
else if (instance.Resource is PacketSource) else if (resource is PacketSource)
{ {
sources.Add(instance.Resource as PacketSource); sources.Add(resource as PacketSource);
} }
} }
*/
foreach (var src in sources) foreach (var src in sources)
{ {
src.OnNewPacket += PacketReceived; src.OnNewPacket += PacketReceived;

View File

@ -44,6 +44,7 @@ namespace Esiur.Net.HTTP
public class HTTPServer : NetworkServer<HTTPConnection>, IResource public class HTTPServer : NetworkServer<HTTPConnection>, IResource
{ {
Dictionary<string, HTTPSession> sessions= new Dictionary<string, HTTPSession>(); Dictionary<string, HTTPSession> sessions= new Dictionary<string, HTTPSession>();
HTTPFilter[] filters = null;
public Instance Instance public Instance Instance
{ {
@ -183,13 +184,8 @@ namespace Esiur.Net.HTTP
{ {
//Console.WriteLine("OUT: " + this.Connections.Count); //Console.WriteLine("OUT: " + this.Connections.Count);
foreach (IResource resource in Instance.Children) foreach (var filter in filters)
{ filter.ClientDisconnected(sender);
if (resource is HTTPFilter)
{
(resource as HTTPFilter).ClientDisconnected(sender);
}
}
} }
@ -268,16 +264,11 @@ namespace Esiur.Net.HTTP
try try
{ {
foreach (IResource resource in Instance.Children) foreach (var resource in filters)
{ resource.Execute(sender);
if (resource is HTTPFilter)
{
if ((resource as HTTPFilter).Execute(sender))
return;
}
}
sender.Send("Bad Request");
sender.Send("Bad Request");
sender.Close(); sender.Close();
} }
catch (Exception ex) catch (Exception ex)
@ -289,21 +280,19 @@ namespace Esiur.Net.HTTP
//Console.WriteLine(ex.ToString()); //Console.WriteLine(ex.ToString());
//EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error); //EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error);
sender.Send(Return500(ex.Message)); sender.Send(Error500(ex.Message));
} }
} }
} }
private string Return500(string sMessage) private string Error500(string msg)
{ {
string sTMP = null; return "<html><head><title>500 Internal Server Error</title></head><br>\r\n"
sTMP = "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE></HEAD><br>\r\n"; + "<body><br>\r\n"
sTMP = sTMP + "<BODY BGCOLOR=" + (char)(34) + "#FFFFFF" + (char)(34) + " Text=" + (char)(34) + "#000000" + (char)(34) + " LINK=" + (char)(34) + "#0000FF" + (char)(34) + " VLINK=" + (char)(34) + "#000080" + (char)(34) + " ALINK=" + (char)(34) + "#008000" + (char)(34) + "><br>\r\n"; + "<b>500</b> Internal Server Error<br>" + msg + "\r\n"
sTMP = sTMP + "<b>500</b> Sorry - Internal Server Error<br>" + sMessage + "\r\n"; + "</body><br>\r\n"
sTMP = sTMP + "</BODY><br>\r\n"; + "</html><br>\r\n";
sTMP = sTMP + "</HTML><br>\r\n";
return sTMP;
} }
@ -382,6 +371,10 @@ namespace Esiur.Net.HTTP
Trigger(ResourceTrigger.Terminate); Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize); Trigger(ResourceTrigger.Initialize);
} }
else if (trigger == ResourceTrigger.SystemInitialized)
{
Instance.Children<HTTPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(true); return new AsyncReply<bool>(true);
@ -395,12 +388,9 @@ namespace Esiur.Net.HTTP
//Console.WriteLine("IN: " + this.Connections.Count); //Console.WriteLine("IN: " + this.Connections.Count);
foreach (var resource in Instance.Children) foreach (var resource in filters)
{ {
if (resource is HTTPFilter) resource.ClientConnected(sender);
{
(resource as HTTPFilter).ClientConnected(sender);
}
} }
} }

View File

@ -46,25 +46,31 @@ namespace Esiur.Net.HTTP
public override bool Execute(HTTPConnection sender) public override bool Execute(HTTPConnection sender)
{ {
if (DistributedServer == null) if (sender.IsWebsocketRequest())
return false; {
if (DistributedServer == null)
return false;
var tcpSocket = sender.Unassign(); var tcpSocket = sender.Unassign();
if (tcpSocket == null) if (tcpSocket == null)
return false; return false;
var httpServer = sender.Parent; var httpServer = sender.Parent;
var wsSocket = new WSSocket(tcpSocket); var wsSocket = new WSSocket(tcpSocket);
httpServer.RemoveConnection(sender); httpServer.RemoveConnection(sender);
var iipConnection = new DistributedConnection(); var iipConnection = new DistributedConnection();
DistributedServer.AddConnection(iipConnection); DistributedServer.AddConnection(iipConnection);
iipConnection.Assign(wsSocket); iipConnection.Assign(wsSocket);
wsSocket.Begin(); wsSocket.Begin();
return true;
}
return false;
return true;
/* /*
if (sender.Request.Filename.StartsWith("/iip/")) if (sender.Request.Filename.StartsWith("/iip/"))
{ {

View File

@ -326,16 +326,22 @@ namespace Esiur.Net.IIP
//packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString()); //packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString());
//if (packs.Count > 1) //if (packs.Count > 1)
// Console.WriteLine("P2"); // Console.WriteLine("P2");
//Console.WriteLine("");
if (rt <= 0) if (rt <= 0)
{ {
//Console.WriteLine("Hold");
var size = ends - offset; var size = ends - offset;
data.HoldFor(msg, offset, size, size + (uint)(-rt)); data.HoldFor(msg, offset, size, size + (uint)(-rt));
return ends; return ends;
} }
else else
{ {
//Console.WriteLine($"CMD {packet.Command} {offset} {ends}");
offset += (uint)rt; offset += (uint)rt;
if (packet.Command == IIPPacket.IIPPacketCommand.Event) if (packet.Command == IIPPacket.IIPPacketCommand.Event)
@ -807,7 +813,9 @@ namespace Esiur.Net.IIP
sock.Connect(domain, port).Then((x)=> { sock.Connect(domain, port).Then((x)=> {
Assign(sock); Assign(sock);
//rt.trigger(true); //rt.trigger(true);
}).Error((x) => openReply.TriggerError(x)); }).Error((x) =>
openReply.TriggerError(x)
);
return openReply; return openReply;
} }
@ -841,5 +849,64 @@ namespace Esiur.Net.IIP
return true; return true;
} }
AsyncReply<bool> IStore.AddChild(IResource parent, IResource child)
{
// not implemented
throw new NotImplementedException();
}
AsyncReply<bool> IStore.RemoveChild(IResource parent, IResource child)
{
// not implemeneted
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
throw new Exception("SS");
//if (Codec.IsLocalResource(resource, this))
// return new AsyncBag<T>((resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x));
return null;
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
throw new Exception("SS");
//if (Codec.IsLocalResource(resource, this))
// return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
return null;
}
/*
public AsyncBag<T> Children<T>(IResource resource)
{
if (Codec.IsLocalResource(resource, this))
return (resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
return null;
}
public AsyncBag<T> Parents<T>(IResource resource)
{
if (Codec.IsLocalResource(resource, this))
return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x);
return null;
}
*/
} }
} }

View File

@ -387,7 +387,10 @@ namespace Esiur.Net.IIP
{ {
Fetch(childId).Then(child => Fetch(childId).Then(child =>
{ {
parent.Instance.Children.Add(child); parent.children.Add(child);
child.parents.Add(parent);
//parent.Instance.Children.Add(child);
}); });
}); });
} }
@ -398,7 +401,10 @@ namespace Esiur.Net.IIP
{ {
Fetch(childId).Then(child => Fetch(childId).Then(child =>
{ {
parent.Instance.Children.Remove(child); parent.children.Remove(child);
child.parents.Remove(parent);
// parent.Instance.Children.Remove(child);
}); });
}); });
} }
@ -443,16 +449,16 @@ namespace Esiur.Net.IIP
r.Instance.ResourceEventOccurred -= Instance_EventOccurred; r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
r.Instance.ResourceModified -= Instance_PropertyModified; r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
r.Instance.Children.OnAdd -= Children_OnAdd; // r.Instance.Children.OnAdd -= Children_OnAdd;
r.Instance.Children.OnRemoved -= Children_OnRemoved; // r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified; r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe // subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred; r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified; r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
r.Instance.Children.OnAdd += Children_OnAdd; //r.Instance.Children.OnAdd += Children_OnAdd;
r.Instance.Children.OnRemoved += Children_OnRemoved; //r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified; r.Instance.Attributes.OnModified += Attributes_OnModified;
var link = DC.ToBytes(r.Instance.Link); var link = DC.ToBytes(r.Instance.Link);
@ -520,6 +526,28 @@ namespace Esiur.Net.IIP
.Done(); .Done();
} }
public bool RemoveChild(IResource parent, IResource child)
{
SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved)
.AddUInt32((parent as DistributedResource).Id)
.AddUInt32((child as DistributedResource).Id)
.Done();
return true;
}
public bool AddChild(IResource parent, IResource child)
{
SendEvent(IIPPacket.IIPPacketEvent.ChildAdded)
.AddUInt32((parent as DistributedResource).Id)
.AddUInt32((child as DistributedResource).Id)
.Done();
return true;
}
void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge) void IIPRequestReattachResource(uint callback, uint resourceId, ulong resourceAge)
{ {
Warehouse.Get(resourceId).Then((res) => Warehouse.Get(resourceId).Then((res) =>
@ -531,16 +559,16 @@ namespace Esiur.Net.IIP
r.Instance.ResourceEventOccurred -= Instance_EventOccurred; r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
r.Instance.ResourceModified -= Instance_PropertyModified; r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
r.Instance.Children.OnAdd -= Children_OnAdd; //r.Instance.Children.OnAdd -= Children_OnAdd;
r.Instance.Children.OnRemoved -= Children_OnRemoved; //r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified; r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe // subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred; r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified; r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
r.Instance.Children.OnAdd += Children_OnAdd; //r.Instance.Children.OnAdd += Children_OnAdd;
r.Instance.Children.OnRemoved += Children_OnRemoved; //r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified; r.Instance.Attributes.OnModified += Attributes_OnModified;
// reply ok // reply ok
@ -646,7 +674,7 @@ namespace Esiur.Net.IIP
Codec.ParseStructure(content, offset, cl, this).Then(values => Codec.ParseStructure(content, offset, cl, this).Then(values =>
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var constructors = Type.GetType(className).GetTypeInfo().GetConstructors(); var constructors = Type.GetType(className).GetTypeInfo().GetConstructors();
#else #else
var constructors = Type.GetType(className).GetConstructors(); var constructors = Type.GetType(className).GetConstructors();
@ -791,7 +819,7 @@ namespace Esiur.Net.IIP
return; return;
} }
parent.Instance.Children.Add(child); parent.Instance.Store.AddChild(parent, child);
SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done(); SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done();
//child.Instance.Parents //child.Instance.Parents
@ -830,7 +858,7 @@ namespace Esiur.Net.IIP
return; return;
} }
parent.Instance.Children.Remove(child); parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child);
SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done();
//child.Instance.Parents //child.Instance.Parents
@ -871,9 +899,14 @@ namespace Esiur.Net.IIP
return; return;
} }
SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback) resource.Instance.Children<IResource>().Then(children =>
.AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Children.ToArray(), this, true)) {
.Done(); SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback)
.AddUInt8Array(Codec.ComposeResourceArray(children, this, true))
.Done();
});
}); });
} }
@ -888,9 +921,14 @@ namespace Esiur.Net.IIP
return; return;
} }
SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback) resource.Instance.Parents<IResource>().Then(parents =>
.AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Parents.ToArray(), this, true)) {
.Done(); SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback)
.AddUInt8Array(Codec.ComposeResourceArray(parents, this, true))
.Done();
});
}); });
} }
@ -1010,7 +1048,8 @@ namespace Esiur.Net.IIP
void IIPRequestQueryResources(uint callback, string resourceLink) void IIPRequestQueryResources(uint callback, string resourceLink)
{ {
Warehouse.Query(resourceLink).Then((r) =>
Action<IResource[]> queryCallback = (r) =>
{ {
//if (r != null) //if (r != null)
//{ //{
@ -1022,12 +1061,12 @@ namespace Esiur.Net.IIP
SendReply(IIPPacket.IIPPacketAction.QueryLink, callback) SendReply(IIPPacket.IIPPacketAction.QueryLink, callback)
.AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) .AddUInt8Array(Codec.ComposeResourceArray(list, this, true))
.Done(); .Done();
//} };
//else
//{ if (Server?.EntryPoint != null)
// reply failed Server.EntryPoint.Query(resourceLink, this).Then(queryCallback);
//} else
}); Warehouse.Query(resourceLink).ContinueWith(x => queryCallback(x.Result));
} }
void IIPRequestResourceAttribute(uint callback, uint resourceId) void IIPRequestResourceAttribute(uint callback, uint resourceId)
@ -1068,7 +1107,7 @@ namespace Esiur.Net.IIP
} }
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else #else
var fi = r.GetType().GetMethod(ft.Name); var fi = r.GetType().GetMethod(ft.Name);
@ -1134,7 +1173,7 @@ namespace Esiur.Net.IIP
{ {
(rt as Task).ContinueWith(t => (rt as Task).ContinueWith(t =>
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else #else
var res = t.GetType().GetProperty("Result").GetValue(t); var res = t.GetType().GetProperty("Result").GetValue(t);
@ -1225,7 +1264,7 @@ namespace Esiur.Net.IIP
} }
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name); var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else #else
var fi = r.GetType().GetMethod(ft.Name); var fi = r.GetType().GetMethod(ft.Name);
@ -1285,7 +1324,7 @@ namespace Esiur.Net.IIP
{ {
(rt as Task).ContinueWith(t => (rt as Task).ContinueWith(t =>
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t); var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else #else
var res = t.GetType().GetProperty("Result").GetValue(t); var res = t.GetType().GetProperty("Result").GetValue(t);
@ -1358,7 +1397,7 @@ namespace Esiur.Net.IIP
} }
else else
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else #else
var pi = r.GetType().GetProperty(pt.Name); var pi = r.GetType().GetProperty(pt.Name);
@ -1435,7 +1474,7 @@ namespace Esiur.Net.IIP
{ {
if (r.Instance.GetAge(index) > age) if (r.Instance.GetAge(index) > age)
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else #else
var pi = r.GetType().GetProperty(pt.Name); var pi = r.GetType().GetProperty(pt.Name);
@ -1498,7 +1537,7 @@ namespace Esiur.Net.IIP
{ {
/* /*
#if NETSTANDARD1_5 #if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name); var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else #else
var pi = r.GetType().GetProperty(pt.Name); var pi = r.GetType().GetProperty(pt.Name);
@ -1748,12 +1787,18 @@ namespace Esiur.Net.IIP
Query(path).Then(ar => Query(path).Then(ar =>
{ {
//if (filter != null)
// ar = ar?.Where(filter).ToArray();
// MISSING: should dispatch the unused resources.
if (ar?.Length > 0) if (ar?.Length > 0)
rt.Trigger(ar[0]); rt.Trigger(ar[0]);
else else
rt.Trigger(null); rt.Trigger(null);
}).Error(ex => rt.TriggerError(ex)); }).Error(ex => rt.TriggerError(ex));
return rt; return rt;
/* /*

View File

@ -53,7 +53,7 @@ namespace Esiur.Net.IIP
/// Raised when the distributed resource is destroyed. /// Raised when the distributed resource is destroyed.
/// </summary> /// </summary>
public event DestroyedEvent OnDestroy; public event DestroyedEvent OnDestroy;
public event Instance.ResourceModifiedEvent OnModified;
uint instanceId; uint instanceId;
DistributedConnection connection; DistributedConnection connection;
@ -68,6 +68,9 @@ namespace Esiur.Net.IIP
//ulong age; //ulong age;
//ulong[] ages; //ulong[] ages;
object[] properties; object[] properties;
internal List<DistributedResource> parents = new List<DistributedResource>();
internal List<DistributedResource> children = new List<DistributedResource>();
DistributedResourceEvent[] events; DistributedResourceEvent[] events;
//ResourceTemplate template; //ResourceTemplate template;
@ -171,10 +174,12 @@ namespace Esiur.Net.IIP
this.link = link; this.link = link;
this.connection = connection; this.connection = connection;
this.instanceId = instanceId; this.instanceId = instanceId;
//this.Instance.Template = template; //this.Instance.Template = template;
//this.Instance.Age = age; //this.Instance.Age = age;
//this.template = template; //this.template = template;
//this.age = age; //this.age = age;
} }
internal void _Ready() internal void _Ready()
@ -270,16 +275,12 @@ namespace Esiur.Net.IIP
if (args.Length == 1) if (args.Length == 1)
{ {
// Detect anonymous types // Detect anonymous types
var type = args[0].GetType().GetTypeInfo(); var type = args[0].GetType();
var hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0; if (Codec.IsAnonymous(type))
var nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
var isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
if (isAnonymousType)
{ {
var namedArgs = new Structure(); var namedArgs = new Structure();
var pi = type.GetProperties(); var pi = type.GetTypeInfo().GetProperties();
foreach (var p in pi) foreach (var p in pi)
namedArgs[p.Name] = p.GetValue(args[0]); namedArgs[p.Name] = p.GetValue(args[0]);
result = _InvokeByNamedArguments(ft.Index, namedArgs); result = _InvokeByNamedArguments(ft.Index, namedArgs);
@ -453,6 +454,7 @@ namespace Esiur.Net.IIP
public DistributedResource() public DistributedResource()
{ {
//stack = new DistributedResourceStack(this); //stack = new DistributedResourceStack(this);
//this.Instance.ResourceModified += this.OnModified;
} }
@ -463,6 +465,10 @@ namespace Esiur.Net.IIP
/// <returns></returns> /// <returns></returns>
public AsyncReply<bool> Trigger(ResourceTrigger trigger) public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{ {
if (trigger == ResourceTrigger.Initialize)
this.Instance.ResourceModified += this.OnModified;
// do nothing. // do nothing.
return new AsyncReply<bool>(true); return new AsyncReply<bool>(true);
} }

View File

@ -56,6 +56,12 @@ namespace Esiur.Net.IIP
set; set;
} }
public EntryPoint EntryPoint
{
get;
set;
}
//[Storable] //[Storable]
//[ResourceProperty] //[ResourceProperty]
public ushort port public ushort port
@ -128,8 +134,7 @@ namespace Esiur.Net.IIP
protected override void ClientConnected(DistributedConnection sender) protected override void ClientConnected(DistributedConnection sender)
{ {
Console.WriteLine("DistributedConnection Client Connected"); //Console.WriteLine("DistributedConnection Client Connected");
} }
private void Sender_OnReady(DistributedConnection sender) private void Sender_OnReady(DistributedConnection sender)

View File

@ -0,0 +1,40 @@
/*
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.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Esiur.Core;
using Esiur.Data;
using Esiur.Resource;
using Esiur.Resource.Template;
namespace Esiur.Net.IIP
{
public abstract class EntryPoint : Esiur.Resource.Resource
{
public abstract AsyncReply<IResource[]> Query(string path, DistributedConnection sender);
public abstract override bool Create();
}
}

View File

@ -209,8 +209,8 @@ namespace Esiur.Net.Packets
{ {
if (offset + needed > ends) if (offset + needed > ends)
{ {
//dataLengthNeeded = needed - (ends - offset); dataLengthNeeded = needed - (ends - offset);
dataLengthNeeded = needed - (ends - originalOffset); //dataLengthNeeded = needed - (ends - originalOffset);
return true; return true;
} }

View File

@ -53,6 +53,7 @@ namespace Esiur.Net.Sockets
bool asyncSending; bool asyncSending;
bool began = false; bool began = false;
SocketState state = SocketState.Initial; SocketState state = SocketState.Initial;
public event ISocketReceiveEvent OnReceive; public event ISocketReceiveEvent OnReceive;
@ -313,23 +314,23 @@ namespace Esiur.Net.Sockets
public void Close() public void Close()
{ {
if (state != SocketState.Closed && state != SocketState.Terminated) if (state != SocketState.Closed && state != SocketState.Terminated)
{
state = SocketState.Closed; state = SocketState.Closed;
if (sock.Connected) if (sock.Connected)
{
try
{ {
sock.Shutdown(SocketShutdown.Both); try
} {
catch sock.Shutdown(SocketShutdown.Both);
{ }
state = SocketState.Terminated; catch
{
state = SocketState.Terminated;
}
} }
sock.Shutdown(SocketShutdown.Both);// Close();
OnClose?.Invoke(); OnClose?.Invoke();
} }
} }
public void Send(byte[] message) public void Send(byte[] message)

View File

@ -65,18 +65,24 @@ namespace Esiur.Net.TCP
} }
public Instance Instance { get; set; } public Instance Instance { get; set; }
TCPFilter[] filters = null;
public AsyncReply<bool> Trigger(ResourceTrigger trigger) public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{ {
if (trigger == ResourceTrigger.Initialize) if (trigger == ResourceTrigger.Initialize)
{ {
TCPSocket listener; TCPSocket listener;
if (ip != null) if (ip != null)
listener =new TCPSocket(new IPEndPoint(IPAddress.Parse(ip), port)); listener =new TCPSocket(new IPEndPoint(IPAddress.Parse(ip), port));
else else
listener = new TCPSocket(new IPEndPoint(IPAddress.Any, port)); listener = new TCPSocket(new IPEndPoint(IPAddress.Any, port));
Start(listener, timeout, clock); Start(listener, timeout, clock);
} }
else if (trigger == ResourceTrigger.Terminate) else if (trigger == ResourceTrigger.Terminate)
{ {
@ -87,6 +93,10 @@ namespace Esiur.Net.TCP
Trigger(ResourceTrigger.Terminate); Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize); Trigger(ResourceTrigger.Initialize);
} }
else if (trigger == ResourceTrigger.SystemInitialized)
{
Instance.Children<TCPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(true); return new AsyncReply<bool>(true);
} }
@ -97,14 +107,10 @@ namespace Esiur.Net.TCP
{ {
var msg = data.Read(); var msg = data.Read();
foreach (var resource in Instance.Children) foreach (var filter in filters)
{ {
if (resource is TCPFilter) if (filter.Execute(msg, data, sender))
{
var f = resource as TCPFilter;
if (f.Execute(msg, data, sender))
return; return;
}
} }
} }
@ -115,25 +121,17 @@ namespace Esiur.Net.TCP
protected override void ClientConnected(TCPConnection sender) protected override void ClientConnected(TCPConnection sender)
{ {
foreach (var resource in Instance.Children) foreach (var filter in filters)
{ {
if (resource is TCPFilter) filter.Connected(sender);
{
var f = resource as TCPFilter;
f.Connected(sender);
}
} }
} }
protected override void ClientDisconnected(TCPConnection sender) protected override void ClientDisconnected(TCPConnection sender)
{ {
foreach (var resource in Instance.Children) foreach (var filter in filters)
{ {
if (resource is TCPFilter) filter.Disconnected(sender);
{
var f = resource as TCPFilter;
f.Disconnected(sender);
}
} }
} }

View File

@ -5,8 +5,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration> <Configuration>Debug</Configuration>
<TargetFramework>netstandard1.5</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<PublishDir>M:\opt\esiur</PublishDir> <PublishDir>M:\opt\esiur</PublishDir>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
</PropertyGroup> </PropertyGroup>

View File

@ -12,7 +12,7 @@ namespace Esiur.Proxy
{ {
static Dictionary<Type, Type> cache = new Dictionary<Type, Type>(); static Dictionary<Type, Type> cache = new Dictionary<Type, Type>();
#if NETSTANDARD1_5 #if NETSTANDARD
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified"); static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod(); static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
#else #else
@ -44,7 +44,7 @@ namespace Esiur.Proxy
if (cache.ContainsKey(type)) if (cache.ContainsKey(type))
return cache[type]; return cache[type];
#if NETSTANDARD1_5 #if NETSTANDARD
var typeInfo = type.GetTypeInfo(); var typeInfo = type.GetTypeInfo();
if (typeInfo.IsSealed) if (typeInfo.IsSealed)
@ -78,7 +78,7 @@ namespace Esiur.Proxy
#if NETSTANDARD1_5 #if NETSTANDARD
var t = typeBuilder.CreateTypeInfo().AsType(); var t = typeBuilder.CreateTypeInfo().AsType();
cache.Add(type, t); cache.Add(type, t);
return t; return t;

View File

@ -35,13 +35,27 @@ namespace Esiur.Resource
{ {
public interface IStore:IResource public interface IStore:IResource
{ {
AsyncReply<IResource> Get(string path); AsyncReply<IResource> Get(string path);//, Func<IResource, bool> filter = null);
AsyncReply<IResource> Retrieve(uint iid); //AsyncReply<IResource> Retrieve(uint iid);
bool Put(IResource resource); bool Put(IResource resource);
string Link(IResource resource); string Link(IResource resource);
bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
bool Remove(IResource resource); bool Remove(IResource resource);
AsyncReply<bool> AddChild(IResource parent, IResource child);
AsyncReply<bool> RemoveChild(IResource parent, IResource child);
AsyncReply<bool> AddParent(IResource child, IResource parent);
AsyncReply<bool> RemoveParent(IResource child, IResource parent);
AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource;
AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource;
//AsyncReply<PropertyValue[]> GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge); //AsyncReply<PropertyValue[]> GetPropertyRecord(IResource resource, string propertyName, ulong fromAge, ulong toAge);
//AsyncReply<PropertyValue[]> GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate); //AsyncReply<PropertyValue[]> GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate);

View File

@ -12,6 +12,7 @@ using Esiur.Security.Permissions;
using Esiur.Resource.Template; using Esiur.Resource.Template;
using Esiur.Security.Authority; using Esiur.Security.Authority;
using Esiur.Proxy; using Esiur.Proxy;
using Esiur.Core;
namespace Esiur.Resource namespace Esiur.Resource
{ {
@ -19,10 +20,11 @@ namespace Esiur.Resource
{ {
string name; string name;
AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>(); //IQueryable<IResource> children;//
IResource resource; //AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
WeakReference<IResource> resource;
IStore store; IStore store;
AutoList<IResource, Instance> parents;// = new AutoList<IResource>(); //AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
//bool inherit; //bool inherit;
ResourceTemplate template; ResourceTemplate template;
@ -40,6 +42,8 @@ namespace Esiur.Resource
public event ResourceEventOccurredEvent ResourceEventOccurred; public event ResourceEventOccurredEvent ResourceEventOccurred;
public event ResourceDestroyedEvent ResourceDestroyed; public event ResourceDestroyedEvent ResourceDestroyed;
bool loading = false;
KeyList<string, object> attributes; KeyList<string, object> attributes;
List<ulong> ages = new List<ulong>(); List<ulong> ages = new List<ulong>();
@ -90,7 +94,7 @@ namespace Esiur.Resource
attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers"); attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers");
} }
foreach(var attr in attributes) foreach (var attr in attributes)
{ {
if (attr == "name") if (attr == "name")
st["name"] = this.name; st["name"] = this.name;
@ -109,15 +113,15 @@ namespace Esiur.Resource
} }
else if (attr == "parents") else if (attr == "parents")
{ {
st["parents"] = parents.ToArray(); //st["parents"] = parents.ToArray();
} }
else if (attr == "children") else if (attr == "children")
{ {
st["children"] = children.ToArray(); //st["children"] = children.ToArray();
} }
else if (attr == "childrenCount") else if (attr == "childrenCount")
{ {
st["childrenCount"] = children.Count; //st["childrenCount"] = children.Count;
} }
else if (attr == "type") else if (attr == "type")
{ {
@ -155,8 +159,13 @@ namespace Esiur.Resource
{ {
var settings = m["settings"] as Structure; var settings = m["settings"] as Structure;
var manager = Activator.CreateInstance(type) as IPermissionsManager; var manager = Activator.CreateInstance(type) as IPermissionsManager;
manager.Initialize(settings, this.resource);
this.managers.Add(manager); IResource res;
if (this.resource.TryGetTarget(out res))
{
manager.Initialize(settings, res);
this.managers.Add(manager);
}
} }
else else
return false; return false;
@ -266,13 +275,19 @@ namespace Esiur.Resource
/// <returns></returns> /// <returns></returns>
public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value) public bool LoadProperty(string name, ulong age, DateTime modificationDate, object value)
{ {
IResource res;
if (!resource.TryGetTarget(out res))
return false;
var pt = template.GetPropertyTemplateByName(name); var pt = template.GetPropertyTemplateByName(name);
if (pt == null) if (pt == null)
return false; return false;
/* /*
#if NETSTANDARD1_5 #if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() }); var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() });
#else #else
var pi = resource.GetType().GetProperty(pt.Name); var pi = resource.GetType().GetProperty(pt.Name);
@ -283,17 +298,24 @@ namespace Esiur.Resource
return false; return false;
try if (pt.Info.CanWrite)
{ {
if (pt.Info.CanWrite) try
pt.Info.SetValue(resource, DC.CastConvert(value, pt.Info.PropertyType)); {
} loading = true;
catch(Exception ex)
{ pt.Info.SetValue(res, DC.CastConvert(value, pt.Info.PropertyType));
//Console.WriteLine(resource.ToString() + " " + name); }
Global.Log(ex); catch (Exception ex)
{
//Console.WriteLine(resource.ToString() + " " + name);
Global.Log(ex);
}
loading = false;
} }
SetAge(pt.Index, age); SetAge(pt.Index, age);
SetModificationDate(pt.Index, modificationDate); SetModificationDate(pt.Index, modificationDate);
@ -359,16 +381,19 @@ namespace Esiur.Resource
foreach (var pt in template.Properties) foreach (var pt in template.Properties)
{ {
/* /*
#if NETSTANDARD1_5 #if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name); var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else #else
var pi = resource.GetType().GetProperty(pt.Name); var pi = resource.GetType().GetProperty(pt.Name);
#endif #endif
*/ */
IResource res;
var rt = pt.Info.GetValue(resource, null); if (resource.TryGetTarget(out res))
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index])); {
var rt = pt.Info.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
} }
return props.ToArray(); return props.ToArray();
@ -446,7 +471,7 @@ namespace Esiur.Resource
/// <returns></returns> /// <returns></returns>
public bool IsStorable() public bool IsStorable()
{ {
#if NETSTANDARD1_5 #if NETSTANDARD
var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray(); var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray();
#else #else
var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true); var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true);
@ -458,22 +483,27 @@ namespace Esiur.Resource
internal void EmitModification(PropertyTemplate pt, object value) internal void EmitModification(PropertyTemplate pt, object value)
{ {
instanceAge++;
var now = DateTime.UtcNow;
ages[pt.Index] = instanceAge; IResource res;
modificationDates[pt.Index] = now; if (this.resource.TryGetTarget(out res))
if (pt.Storage == StorageMode.NonVolatile)
{ {
store.Modify(resource, pt.Name, value, ages[pt.Index], now); instanceAge++;
} var now = DateTime.UtcNow;
else if (pt.Storage == StorageMode.Recordable)
{
store.Record(resource, pt.Name, value, ages[pt.Index], now);
}
ResourceModified?.Invoke(resource, pt.Name, value); ages[pt.Index] = instanceAge;
modificationDates[pt.Index] = now;
if (pt.Storage == StorageMode.NonVolatile)
{
store.Modify(res, pt.Name, value, ages[pt.Index], now);
}
else if (pt.Storage == StorageMode.Recordable)
{
store.Record(res, pt.Name, value, ages[pt.Index], now);
}
ResourceModified?.Invoke(res, pt.Name, value);
}
} }
/// <summary> /// <summary>
@ -484,6 +514,9 @@ namespace Esiur.Resource
/// <param name="oldValue"></param> /// <param name="oldValue"></param>
public void Modified([CallerMemberName] string propertyName = "") public void Modified([CallerMemberName] string propertyName = "")
{ {
if (loading)
return;
object value; object value;
if (GetPropertyValue(propertyName, out value)) if (GetPropertyValue(propertyName, out value))
{ {
@ -496,7 +529,12 @@ namespace Esiur.Resource
internal void EmitResourceEvent(object issuer, Session[] receivers, string name, object[] args) internal void EmitResourceEvent(object issuer, Session[] receivers, string name, object[] args)
{ {
ResourceEventOccurred?.Invoke(resource, issuer, receivers, name, args); IResource res;
if (this.resource.TryGetTarget(out res))
{
ResourceEventOccurred?.Invoke(res, issuer, receivers, name, args);
}
} }
/// <summary> /// <summary>
@ -508,7 +546,7 @@ namespace Esiur.Resource
public bool GetPropertyValue(string name, out object value) public bool GetPropertyValue(string name, out object value)
{ {
/* /*
#if NETSTANDARD1_5 #if NETSTANDARD
PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else #else
@ -521,7 +559,7 @@ namespace Esiur.Resource
if (pt != null && pt.Info != null) if (pt != null && pt.Info != null)
{ {
/* /*
#if NETSTANDARD1_5 #if NETSTANDARD
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray(); object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
#else #else
@ -537,7 +575,15 @@ namespace Esiur.Resource
} }
*/ */
value = pt.Info.GetValue(resource, null); IResource res;
if (resource.TryGetTarget(out res))
value = pt.Info.GetValue(res, null);
else
{
value = null;
return false;
}
return true; return true;
} }
@ -556,10 +602,7 @@ namespace Esiur.Resource
/// <summary> /// <summary>
/// List of parents. /// List of parents.
/// </summary> /// </summary>
public AutoList<IResource, Instance> Parents //public AutoList<IResource, Instance> Parents => parents;
{
get { return parents; }
}
/// <summary> /// <summary>
/// Store responsible for creating and keeping the resource. /// Store responsible for creating and keeping the resource.
@ -572,15 +615,54 @@ namespace Esiur.Resource
/// <summary> /// <summary>
/// List of children. /// List of children.
/// </summary> /// </summary>
public AutoList<IResource, Instance> Children // public AutoList<IResource, Instance> Children => children;
{
get { return children; }
}
/// <summary> /// <summary>
/// The unique and permanent link to the resource. /// The unique and permanent link to the resource.
/// </summary> /// </summary>
public string Link public string Link
{
get
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
if (res == res.Instance.store)
return name; // root store
else
return store.Link(res);
}
else
return null;
}
}
public AsyncBag<T> Children<T>(string name = null) where T : IResource
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
//if (!(store is null))
return store.Children<T>(res, name);
//else
// return (res as IStore).Children<T>(res, name);
}
else
return new AsyncBag<T>(null);
}
public AsyncBag<T> Parents<T>(string name = null) where T : IResource
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
return store.Parents<T>(res, name);
}
else
return new AsyncBag<T>(null);
}
/*
{ {
get get
{ {
@ -607,6 +689,8 @@ namespace Esiur.Resource
} }
} }
} }
*
*/
/// <summary> /// <summary>
/// Instance name. /// Instance name.
@ -623,7 +707,16 @@ namespace Esiur.Resource
/// </summary> /// </summary>
public IResource Resource public IResource Resource
{ {
get { return resource; } get
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
return res;
}
else
return null;
}
} }
/// <summary> /// <summary>
@ -658,11 +751,15 @@ namespace Esiur.Resource
/// <returns>Ruling.</returns> /// <returns>Ruling.</returns>
public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null) public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null)
{ {
foreach (IPermissionsManager manager in managers) IResource res;
if (this.resource.TryGetTarget(out res))
{ {
var r = manager.Applicable(this.resource, session, action, member, inquirer); foreach (IPermissionsManager manager in managers)
if (r != Ruling.DontCare) {
return r; var r = manager.Applicable(res, session, action, member, inquirer);
if (r != Ruling.DontCare)
return r;
}
} }
return Ruling.DontCare; return Ruling.DontCare;
@ -684,19 +781,19 @@ namespace Esiur.Resource
public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0) public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0)
{ {
this.store = store; this.store = store;
this.resource = resource; this.resource = new WeakReference<IResource>(resource);
this.id = id; this.id = id;
this.name = name; this.name = name;
this.instanceAge = age; this.instanceAge = age;
this.attributes = new KeyList<string, object>(this); this.attributes = new KeyList<string, object>(this);
children = new AutoList<IResource, Instance>(this); //children = new AutoList<IResource, Instance>(this);
parents = new AutoList<IResource, Instance>(this); //parents = new AutoList<IResource, Instance>(this);
managers = new AutoList<IPermissionsManager, Instance>(this); managers = new AutoList<IPermissionsManager, Instance>(this);
children.OnAdd += Children_OnAdd; //children.OnAdd += Children_OnAdd;
children.OnRemoved += Children_OnRemoved; //children.OnRemoved += Children_OnRemoved;
parents.OnAdd += Parents_OnAdd; //parents.OnAdd += Parents_OnAdd;
parents.OnRemoved += Parents_OnRemoved; //parents.OnRemoved += Parents_OnRemoved;
resource.OnDestroy += Resource_OnDestroy; resource.OnDestroy += Resource_OnDestroy;
@ -715,7 +812,7 @@ namespace Esiur.Resource
// connect events // connect events
Type t = ResourceProxy.GetBaseType(resource); Type t = ResourceProxy.GetBaseType(resource);
#if NETSTANDARD1_5 #if NETSTANDARD
var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else #else
@ -783,7 +880,12 @@ namespace Esiur.Resource
} }
} }
private void Children_OnRemoved(Instance parent, IResource value)
//IQueryable<IResource> Children => store.GetChildren(this);
/*
* private void Children_OnRemoved(Instance parent, IResource value)
{ {
value.Instance.parents.Remove(resource); value.Instance.parents.Remove(resource);
} }
@ -804,7 +906,7 @@ namespace Esiur.Resource
if (!value.Instance.children.Contains(resource)) if (!value.Instance.children.Contains(resource))
value.Instance.children.Add(resource); value.Instance.children.Add(resource);
} }
*/
private void Resource_OnDestroy(object sender) private void Resource_OnDestroy(object sender)
{ {

View File

@ -36,7 +36,7 @@ namespace Esiur.Resource
public virtual void Destroy() public virtual void Destroy()
{ {
OnDestroy?.Invoke(this);
} }
public virtual AsyncReply<bool> Trigger(ResourceTrigger trigger) public virtual AsyncReply<bool> Trigger(ResourceTrigger trigger)
@ -51,5 +51,10 @@ namespace Esiur.Resource
{ {
return true; return true;
} }
~Resource()
{
Destroy();
}
} }
} }

View File

@ -0,0 +1,28 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Esiur.Resource
{
public class ResourceQuery : IQueryable<IResource>
{
public Type ElementType => throw new NotImplementedException();
public Expression Expression => throw new NotImplementedException();
public IQueryProvider Provider => throw new NotImplementedException();
public IEnumerator<IResource> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}

View File

@ -139,7 +139,7 @@ namespace Esiur.Resource.Template
className = type.FullName; className = type.FullName;
#if NETSTANDARD1_5 #if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(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); MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

View File

@ -32,6 +32,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Esiur.Net.IIP;
using System.Text.RegularExpressions;
namespace Esiur.Resource namespace Esiur.Resource
{ {
@ -40,13 +42,13 @@ namespace Esiur.Resource
{ {
//static byte prefixCounter; //static byte prefixCounter;
static AutoList<IResource, Instance> stores = new AutoList<IResource, Instance>(null); static AutoList<IStore, Instance> stores = new AutoList<IStore, Instance>(null);
static Dictionary<uint, IResource> resources = new Dictionary<uint, IResource>(); static Dictionary<uint, WeakReference<IResource>> resources = new Dictionary<uint, WeakReference<IResource>>();
static uint resourceCounter = 0; static uint resourceCounter = 0;
static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>(); static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>();
static bool storeIsOpen = false; static bool warehouseIsOpen = false;
public delegate void StoreConnectedEvent(IStore store, string name); public delegate void StoreConnectedEvent(IStore store, string name);
public delegate void StoreDisconnectedEvent(IStore store); public delegate void StoreDisconnectedEvent(IStore store);
@ -54,7 +56,15 @@ namespace Esiur.Resource
public static event StoreConnectedEvent StoreConnected; public static event StoreConnectedEvent StoreConnected;
public static event StoreDisconnectedEvent StoreDisconnected; public static event StoreDisconnectedEvent StoreDisconnected;
public static KeyList<string, Func<IStore>> Protocols { get; } = new KeyList<string, Func<IStore>>(); public static KeyList<string, Func<IStore>> Protocols { get; } = getSupportedProtocols();
static KeyList<string, Func<IStore>> getSupportedProtocols()
{
var rt = new KeyList<string, Func<IStore>>();
rt.Add("iip", () => new DistributedConnection());
return rt;
}
/// <summary> /// <summary>
/// Get a store by its name. /// Get a store by its name.
@ -77,7 +87,13 @@ namespace Esiur.Resource
public static AsyncReply<IResource> Get(uint id) public static AsyncReply<IResource> Get(uint id)
{ {
if (resources.ContainsKey(id)) if (resources.ContainsKey(id))
return new AsyncReply<IResource>(resources[id]); {
IResource r;
if (resources[id].TryGetTarget(out r))
return new AsyncReply<IResource>(r);
else
return new AsyncReply<IResource>(null);
}
else else
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
@ -109,7 +125,11 @@ namespace Esiur.Resource
var rBag = new AsyncBag<bool>(); var rBag = new AsyncBag<bool>();
foreach (var rk in resources) foreach (var rk in resources)
rBag.Add(rk.Value.Trigger(ResourceTrigger.SystemInitialized)); {
IResource r;
if (rk.Value.TryGetTarget(out r))
rBag.Add(r.Trigger(ResourceTrigger.SystemInitialized));
}
rBag.Seal(); rBag.Seal();
@ -123,7 +143,7 @@ namespace Esiur.Resource
} }
rt.Trigger(true); rt.Trigger(true);
storeIsOpen = true; warehouseIsOpen = true;
}); });
}); });
@ -142,15 +162,30 @@ namespace Esiur.Resource
var bag = new AsyncBag<bool>(); var bag = new AsyncBag<bool>();
foreach (var resource in resources.Values) foreach (var resource in resources.Values)
if (!(resource is IStore)) {
bag.Add(resource.Trigger(ResourceTrigger.Terminate)); IResource r;
if (resource.TryGetTarget(out r))
{
if (!(r is IStore))
bag.Add(r.Trigger(ResourceTrigger.Terminate));
}
}
foreach (var store in stores) foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.Terminate)); bag.Add(store.Trigger(ResourceTrigger.Terminate));
foreach (var resource in resources.Values) foreach (var resource in resources.Values)
if (!(resource is IStore)) {
bag.Add(resource.Trigger(ResourceTrigger.SystemTerminated)); IResource r;
if (resource.TryGetTarget(out r))
{
if (!(r is IStore))
bag.Add(r.Trigger(ResourceTrigger.SystemTerminated));
}
}
foreach (var store in stores) foreach (var store in stores)
bag.Add(store.Trigger(ResourceTrigger.SystemTerminated)); bag.Add(store.Trigger(ResourceTrigger.SystemTerminated));
@ -174,7 +209,8 @@ namespace Esiur.Resource
} }
private static IResource[] QureyIn(string[] path, int index, AutoList<IResource, Instance> resources) /*
private static IResource[] QureyIn(string[] path, int index, IEnumerable<IResource> resources)// AutoList<IResource, Instance> resources)
{ {
var rt = new List<IResource>(); var rt = new List<IResource>();
@ -191,18 +227,16 @@ namespace Esiur.Resource
else else
foreach (IResource child in resources) foreach (IResource child in resources)
if (child.Instance.Name == path[index]) if (child.Instance.Name == path[index])
rt.AddRange(QureyIn(path, index+1, child.Instance.Children)); rt.AddRange(QureyIn(path, index+1, child.Instance.Children<IResource>()));
return rt.ToArray(); return rt.ToArray();
} }
public static AsyncReply<IResource[]> Query(string path) public static AsyncReply<IResource[]> Query(string path)
{ {
if (path == null || path == "") if (path == null || path == "")
{ {
var roots = stores.Where(s => s.Instance.Parents.Count == 0).ToArray(); var roots = stores.Where(s => s.Instance.Parents<IResource>().Count() == 0).ToArray();
return new AsyncReply<IResource[]>(roots); return new AsyncReply<IResource[]>(roots);
} }
else else
@ -229,6 +263,51 @@ namespace Esiur.Resource
} }
} }
*/
public static async Task<IResource[]> Query(string path)
{
var rt = new AsyncReply<IResource[]>();
var p = path.Trim().Split('/');
IResource resource;
foreach (var store in stores)
if (p[0] == store.Instance.Name)
{
if (p.Length == 1)
return new IResource[] { store };
var res = await store.Get(String.Join("/", p.Skip(1).ToArray()));
if (res != null)
return new IResource[] { res };
resource = store;
for (var i = 1; i < p.Length; i++)
{
var children = await resource.Instance.Children<IResource>(p[i]);
if (children.Length > 0)
{
if (i == p.Length - 1)
return children;
else
resource = children[0];
}
else
break;
}
return null;
}
return null;
}
/// <summary> /// <summary>
/// Get a resource by its path. /// Get a resource by its path.
@ -236,38 +315,15 @@ namespace Esiur.Resource
/// </summary> /// </summary>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns>Resource instance.</returns> /// <returns>Resource instance.</returns>
public static AsyncReply<IResource> Get(string path, Structure attributes = null, IResource parent = null, IPermissionsManager manager = null) public static AsyncReply<IResource> Get(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
{ {
var p = path.Split('/');
IResource res;
foreach(IStore d in stores)
if (p[0] == d.Instance.Name)
{
var i = 1;
res = d;
while(p.Length > i)
{
var si = i;
foreach (IResource r in res.Instance.Children) var rt = new AsyncReply<IResource>();
if (r.Instance.Name == p[i])
{
i++;
res = r;
break;
}
if (si == i)
// not found, ask the store
return d.Get(path.Substring(p[0].Length + 1));
}
return new AsyncReply<IResource>(res);
}
// Should we create a new store ? // Should we create a new store ?
if (path.Contains("://")) if (path.Contains("://"))
{ {
var url = path.Split(new string[] { "://" }, 2, StringSplitOptions.None); var url = path.Split(new string[] { "://" }, 2, StringSplitOptions.None);
@ -275,17 +331,18 @@ namespace Esiur.Resource
var pathname = string.Join("/", url[1].Split(new char[] { '/' }).Skip(1)); var pathname = string.Join("/", url[1].Split(new char[] { '/' }).Skip(1));
var rt = new AsyncReply<IResource>();
if (Protocols.ContainsKey(url[0])) if (Protocols.ContainsKey(url[0]))
{ {
var handler = Protocols[url[0]]; var handler = Protocols[url[0]];
var store = handler();// Activator.CreateInstance(handler.GetType()) as IStore; var store = handler();
Put(store, url[0] + "://" + hostname, null, parent, null, 0, manager, attributes); Put(store, hostname, null, parent, null, 0, manager, attributes);
store.Trigger(ResourceTrigger.Open).Then(x => { store.Trigger(ResourceTrigger.Open).Then(x => {
warehouseIsOpen = true;
if (pathname.Length > 0 && pathname != "") if (pathname.Length > 0 && pathname != "")
store.Get(pathname).Then(r => { store.Get(pathname).Then(r => {
rt.Trigger(r); rt.Trigger(r);
@ -296,13 +353,24 @@ namespace Esiur.Resource
rt.TriggerError(e); rt.TriggerError(e);
Warehouse.Remove(store); Warehouse.Remove(store);
}); });
}
return rt; return rt;
}
} }
return new AsyncReply<IResource>(null); Query(path).ContinueWith(rs =>
{
// rt.TriggerError(new Exception());
if (rs.Result != null && rs.Result.Length > 0)
rt.Trigger(rs.Result[0]);
else
rt.Trigger(null);
});
return rt;
} }
/// <summary> /// <summary>
@ -312,12 +380,31 @@ namespace Esiur.Resource
/// <param name="name">Resource name.</param> /// <param name="name">Resource name.</param>
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param> /// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param> /// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public static void Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, Structure attributes = null) public static void Put(IResource resource, string name, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null)
{ {
if (store == null)
{
// assign parent as a store
if (parent is IStore)
store = (IStore)parent;
// assign parent's store as a store
else if (parent != null)
store = parent.Instance.Store;
// assign self as a store (root store)
else if (resource is IStore)
{
store = (IStore)resource;
stores.Add(resource as IStore);
}
else
throw new Exception("Can't find a store for the resource.");
}
resource.Instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age); resource.Instance = new Instance(resourceCounter++, name, resource, store, customTemplate, age);
if (attributes != null) if (attributes != null)
resource.Instance.SetAttributes(attributes); resource.Instance.SetAttributes(Structure.FromObject(attributes));
if (manager != null) if (manager != null)
resource.Instance.Managers.Add(manager); resource.Instance.Managers.Add(manager);
@ -325,6 +412,8 @@ namespace Esiur.Resource
if (store == parent) if (store == parent)
parent = null; parent = null;
/*
if (parent == null) if (parent == null)
{ {
if (!(resource is IStore)) if (!(resource is IStore))
@ -332,20 +421,26 @@ namespace Esiur.Resource
} }
else else
parent.Instance.Children.Add(resource); parent.Instance.Children.Add(resource);
*/
if (resource is IStore) if (resource is IStore)
{
stores.Add(resource as IStore);
StoreConnected?.Invoke(resource as IStore, name); StoreConnected?.Invoke(resource as IStore, name);
}
else else
store.Put(resource); store.Put(resource);
resources.Add(resource.Instance.Id, resource);
if (storeIsOpen) if (parent != null)
{
parent.Instance.Store.AddChild(parent, resource);
store.AddParent(resource, parent);
//store.AddChild(parent, resource);
}
resources.Add(resource.Instance.Id, new WeakReference<IResource>(resource));
if (warehouseIsOpen)
resource.Trigger(ResourceTrigger.Initialize); resource.Trigger(ResourceTrigger.Initialize);
} }
@ -430,9 +525,17 @@ namespace Esiur.Resource
stores.Remove(resource as IStore); stores.Remove(resource as IStore);
// remove all objects associated with the store // remove all objects associated with the store
var toBeRemoved = resources.Values.Where(x => x.Instance.Store == resource); var toBeRemoved = resources.Values.Where(x => {
IResource r;
return x.TryGetTarget(out r) && r.Instance.Store == resource;
});
foreach (var o in toBeRemoved) foreach (var o in toBeRemoved)
Remove(o); {
IResource r;
if (o.TryGetTarget(out r))
Remove(r);
}
StoreDisconnected?.Invoke(resource as IStore); StoreDisconnected?.Invoke(resource as IStore);
} }

View File

@ -33,7 +33,7 @@ using Esiur.Security.Authority;
namespace Esiur.Security.Permissions namespace Esiur.Security.Permissions
{ {
public class ParentalPermissionsManager : IPermissionsManager public class StorePermissionsManager : IPermissionsManager
{ {
Structure settings; Structure settings;
@ -41,20 +41,12 @@ namespace Esiur.Security.Permissions
public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null) public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null)
{ {
return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer);
foreach (IResource parent in resource.Instance.Parents)
{
var ruling = parent.Instance.Applicable(session, action, member, inquirer);
if (ruling != Ruling.DontCare)
return ruling;
}
return Ruling.DontCare;
} }
public bool Initialize(Structure settings, IResource resource) public bool Initialize(Structure settings, IResource resource)
{ {
throw new NotImplementedException(); return true;
} }
} }
} }

View File

@ -33,19 +33,31 @@ namespace Esiur.Stores
public AsyncReply<IResource> Get(string path) public AsyncReply<IResource> Get(string path)
{ {
foreach (var r in resources)
if (r.Value.Instance.Name == path)
return new AsyncReply<IResource>(r.Value);
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
public bool Put(IResource resource) public bool Put(IResource resource)
{ {
resources.Add(resource.Instance.Id, resource); resources.Add(resource.Instance.Id, resource);// new WeakReference<IResource>(resource));
resource.Instance.Attributes["children"] = new AutoList<IResource, Instance>(resource.Instance);
resource.Instance.Attributes["parents"] = new AutoList<IResource, Instance>(resource.Instance);
return true; return true;
} }
public AsyncReply<IResource> Retrieve(uint iid) public AsyncReply<IResource> Retrieve(uint iid)
{ {
if (resources.ContainsKey(iid)) if (resources.ContainsKey(iid))
return new AsyncReply<IResource>(resources[iid]); {
if (resources.ContainsKey(iid))// .TryGetTarget(out r))
return new AsyncReply<IResource>(resources[iid]);
else
return new AsyncReply<IResource>(null);
}
else else
return new AsyncReply<IResource>(null); return new AsyncReply<IResource>(null);
} }
@ -76,5 +88,58 @@ namespace Esiur.Stores
return true; return true;
} }
public AsyncReply<bool> AddChild(IResource parent, IResource child)
{
if (parent.Instance.Store == this)
{
(parent.Instance.Attributes["children"] as AutoList<IResource, Instance>).Add(child);
return new AsyncReply<bool>(true);
}
else
return new AsyncReply<bool>(false);
}
public AsyncReply<bool> RemoveChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource resource, IResource parent)
{
if (resource.Instance.Store == this)
{
(resource.Instance.Attributes["parents"] as AutoList<IResource, Instance>).Add(parent);
return new AsyncReply<bool>(true);
}
else
return new AsyncReply<bool>(false);
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
var children = (resource.Instance.Attributes["children"] as AutoList<IResource, Instance>);
if (name == null)
return new AsyncBag<T>(children.Where(x=>x is T).Select(x=>(T)x).ToArray());
else
return new AsyncBag<T>(children.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray());
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
var parents = (resource.Instance.Attributes["parents"] as AutoList<IResource, Instance>);
if (name == null)
return new AsyncBag<T>(parents.Where(x => x is T).Select(x => (T)x).ToArray());
else
return new AsyncBag<T>(parents.Where(x => x is T && x.Instance.Name == name).Select(x => (T)x).ToArray());
}
} }
} }

View File

@ -0,0 +1,118 @@
using Esiur.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Core;
using Esiur.Data;
using Esiur.Resource.Template;
namespace Esiur.Stores
{
public class TemporaryStore : IStore
{
public Instance Instance { get; set; }
public event DestroyedEvent OnDestroy;
Dictionary<uint, WeakReference> resources = new Dictionary<uint, WeakReference>();
public void Destroy()
{
}
public string Link(IResource resource)
{
if (resource.Instance.Store == this)
return this.Instance.Name + "/" + resource.Instance.Id;
return null;
}
public AsyncReply<IResource> Get(string path)
{
foreach (var r in resources)
if (r.Value.IsAlive && (r.Value.Target as IResource).Instance.Name == path)
return new AsyncReply<IResource>(r.Value.Target as IResource);
return new AsyncReply<IResource>(null);
}
public bool Put(IResource resource)
{
resources.Add(resource.Instance.Id, new WeakReference( resource));// new WeakReference<IResource>(resource));
return true;
}
public AsyncReply<IResource> Retrieve(uint iid)
{
if (resources.ContainsKey(iid))
{
if (resources.ContainsKey(iid) && resources[iid].IsAlive)// .TryGetTarget(out r))
return new AsyncReply<IResource>(resources[iid].Target as IResource);
else
return new AsyncReply<IResource>(null);
}
else
return new AsyncReply<IResource>(null);
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
{
throw new NotImplementedException();
}
public AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate)
{
throw new NotImplementedException();
}
public bool Remove(IResource resource)
{
resources.Remove(resource.Instance.Id);
return true;
}
public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
{
return true;
}
public AsyncReply<bool> AddChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveChild(IResource parent, IResource child)
{
throw new NotImplementedException();
}
public AsyncReply<bool> AddParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncReply<bool> RemoveParent(IResource child, IResource parent)
{
throw new NotImplementedException();
}
public AsyncBag<T> Children<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
public AsyncBag<T> Parents<T>(IResource resource, string name) where T : IResource
{
throw new NotImplementedException();
}
}
}

BIN
Esiurd.sln Normal file

Binary file not shown.

View File

@ -9,7 +9,7 @@ using System.Threading;
namespace Test namespace Test
{ {
public class MyObject : Resource public class MyObject : EntryPoint
{ {
[ResourceEvent] [ResourceEvent]
@ -90,6 +90,16 @@ namespace Test
return reply; return reply;
} }
public override AsyncReply<IResource[]> Query(string path, DistributedConnection sender)
{
return new AsyncReply<IResource[]>(new IResource[] { this });
}
public override bool Create()
{
return true;
}
[ResourceProperty] [ResourceProperty]
public Structure Info public Structure Info
{ {

View File

@ -51,8 +51,6 @@ namespace Test
{ {
Warehouse.Protocols.Add("iip", () => new DistributedConnection());
// Create stores to keep objects. // Create stores to keep objects.
var system = Warehouse.New<MemoryStore>("system"); var system = Warehouse.New<MemoryStore>("system");
var remote = Warehouse.New<MemoryStore>("remote"); var remote = Warehouse.New<MemoryStore>("remote");
@ -64,12 +62,12 @@ namespace Test
// Set membership which handles authentication. // Set membership which handles authentication.
iip.Membership = Warehouse.New<MyMembership>("ms", system); iip.Membership = Warehouse.New<MyMembership>("ms", system);
// Start the server on port 5000. // Start the server on port 5000.
iip.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5000)), 600000, 60000); iip.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 500)), 600000, 60000);
// Create http server to handle IIP over Websockets // Create http server to handle IIP over Websockets
var http = Warehouse.New<HTTPServer>("http", system); var http = Warehouse.New<HTTPServer>("http", system);
http.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5001)), 600000, 60000); http.Start(new TCPSocket(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 501)), 600000, 60000);
// Create IIP over Websocket HTTP module and give it to HTTP server. // Create IIP over Websocket HTTP module and give it to HTTP server.
var wsOverHttp = Warehouse.New<IIPoWS>("IIPoWS", system, http); var wsOverHttp = Warehouse.New<IIPoWS>("IIPoWS", system, http);
@ -106,13 +104,10 @@ namespace Test
} }
})); }));
else else
localObject = (MyObject)(await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; }); localObject = (MyObject)(await Warehouse.Get("db/my"));
//var obj = ProxyObject.<MyObject>(); iip.EntryPoint = localObject;
//Warehouse.Put(obj, "dd", system);
//obj.Level2= 33;
Warehouse.StoreConnected += (store, name) => Warehouse.StoreConnected += (store, name) =>
{ {
@ -160,7 +155,7 @@ namespace Test
private static async void TestClient() private static async void TestClient()
{ {
remoteObject = await Warehouse.Get("iip://localhost:5000/db/my", new Structure() { ["username"] = "demo", ["password"] = "1234" }); remoteObject = await Warehouse.Get("iip://localhost:500/db/my", new { username= "demo", password = 1234 });
dynamic x = remoteObject; dynamic x = remoteObject;