2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 03:32:57 +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">
<PropertyGroup>
<TargetFramework>netstandard1.5</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<Authors>Ahmed Kh. Zamil</Authors>
<Company>Esiur</Company>
<Product>Esiur MongoDB Store</Product>
@ -11,12 +11,12 @@
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet/</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.2.5</Version>
<Version>1.2.8</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MongoDB.Bson" Version="2.4.4" />
<PackageReference Include="MongoDB.Driver" Version="2.4.4" />
<PackageReference Include="MongoDB.Bson" Version="2.9.1" />
<PackageReference Include="MongoDB.Driver" Version="2.9.1" />
</ItemGroup>
<ItemGroup>

View File

@ -23,15 +23,22 @@ namespace Esiur.Stores.MongoDB
MongoClient client;
IMongoDatabase database;
IMongoCollection<BsonDocument> resourcesCollection;
//List<IResource> storeParents = new List<IResource>();
//List<IResource> storeChildren = new List<IResource>();
//string collectionName;
//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()
@ -39,7 +46,7 @@ namespace Esiur.Stores.MongoDB
}
public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
@ -77,21 +84,35 @@ namespace Esiur.Stores.MongoDB
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 list = resourcesCollection.Find(filter).ToList();
if (list.Count == 0)
return new AsyncReply<IResource>(null);
return new AsyncReply<T>(default(T));
var document = list[0];
var type = Type.GetType(document["classname"].AsString);
if (type == null)
return new AsyncReply<IResource>(null);
return new AsyncReply<T>(default(T));
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);
@ -100,14 +121,16 @@ namespace Esiur.Stores.MongoDB
var children = document["children"].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);
});
var bag = new AsyncBag<object>();
/*
foreach (var p in parents)
{
{
var ap = Warehouse.Get(p.AsString);
bag.Add(ap);
ap.Then((x) =>
@ -128,6 +151,10 @@ namespace Esiur.Stores.MongoDB
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
foreach (var m in this.Instance.Managers)
@ -154,27 +181,34 @@ namespace Esiur.Stores.MongoDB
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);
resource.Instance.LoadProperty(v.Name,
(ulong)valueInfo["age"].AsInt64,
valueInfo["modification"].ToUniversalTime(),
x);
});
bag.Add(av);
}
bag.Seal();
var rt = new AsyncReply<IResource>();
var rt = new AsyncReply<T>();
bag.Then((x) =>
{
rt.Trigger(resource);
if (resource is T)
rt.Trigger(resource);
else
rt.Trigger(null);
});
bag.Seal();
return rt;
}
@ -230,7 +264,7 @@ namespace Esiur.Stores.MongoDB
}
else
{
return new AsyncReply<object>(value.RawValue);
}
}
@ -242,16 +276,22 @@ namespace Esiur.Stores.MongoDB
if (p[0] == "id")
{
// load from Id
return Fetch<IResource>(p[1]);
/*
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"];
@ -259,11 +299,17 @@ namespace Esiur.Stores.MongoDB
public bool Put(IResource resource)
{
PutResource(resource).Wait();
return true;
}
private async Task<bool> PutResource(IResource resource)
{
var attrs = resource.Instance.GetAttributes();
foreach (var kv in resources)
if (kv.Value == resource)
if (kv.Value.Target == resource)
{
resource.Instance.Attributes.Add("objectId", kv.Key);
return true;
@ -290,34 +336,58 @@ namespace Esiur.Stores.MongoDB
var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children)
children.Add(c.Instance.Link);
// setup attributes
resource.Instance.Attributes["children"] = new string[0];
resource.Instance.Attributes["parents"] = new string[] { this.Instance.Link };
// copy old children (in case we are moving a resource from a store to another.
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);
}
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 filter = Builders<BsonDocument>.Filter.Eq("_id", document["_id"]);
// var update = Builders<BsonDocument>.Update
// .Set("values", values);
// col.UpdateOne(filter, update);
/*
@ -340,6 +410,7 @@ namespace Esiur.Stores.MongoDB
//resource.Instance.Attributes["objectId"] = document["_id"].ToString();
return true;
}
@ -409,7 +480,7 @@ namespace Esiur.Stores.MongoDB
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"]));
@ -454,8 +525,10 @@ namespace Esiur.Stores.MongoDB
resourcesCollection = this.database.GetCollection<BsonDocument>(collectionName);
// return new AsyncReply<bool>(true);
// return new AsyncReply<bool>(true);
/*
var filter = new BsonDocument();
var list = resourcesCollection.Find(filter).ToList();
@ -476,15 +549,24 @@ namespace Esiur.Stores.MongoDB
var rt = new AsyncReply<bool>();
bag.Then((x) => { rt.Trigger(true); });
bag.Then((x) => {
// storeChildren.AddRange(x);
rt.Trigger(true);
});
return rt;
*/
return new AsyncReply<bool>(true);
}
else if (trigger == ResourceTrigger.Terminate)
{
// save all resources
foreach (var resource in resources.Values)
SaveResource(resource);
if (resource.IsAlive)
SaveResource(resource.Target as IResource);
return new AsyncReply<bool>(true);
}
@ -501,12 +583,14 @@ namespace Esiur.Stores.MongoDB
var children = new BsonArray();
var template = resource.Instance.Template;
foreach (IResource c in resource.Instance.Children)
children.Add(c.Instance.Link);
//foreach (IResource c in resource.Instance.Children)
// children.Add(c.Instance.Link);
var plist = resource.Instance.Attributes["parents"] as string[];
foreach (var link in plist)// Parents)
parents.Add(link);
foreach (IResource p in resource.Instance.Parents)
parents.Add(p.Instance.Link);
var values = new BsonDocument();
@ -536,7 +620,7 @@ namespace Esiur.Stores.MongoDB
{
{ "parents", parents },
{ "children", children },
{"attributes", attrsDoc },
{ "attributes", attrsDoc },
{ "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name },
{ "name", resource.Instance.Name },
{ "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) },
@ -576,15 +660,15 @@ namespace Esiur.Stores.MongoDB
var bag = new AsyncBag<object>();
foreach(var v in values)
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++)
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());
@ -653,7 +737,7 @@ namespace Esiur.Stores.MongoDB
reply.Trigger(list);
});
return reply;
}
@ -685,7 +769,7 @@ namespace Esiur.Stores.MongoDB
public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime)
{
var objectId = resource.Instance.Attributes["objectId"].ToString();
@ -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
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
# Visual Studio Version 16
VisualStudioVersion = 16.0.29324.140
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
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
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -15,20 +14,23 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEBF78DB-E3B3-47F4-994C-5C970E98C686}.Release|Any CPU.Build.0 = Release|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08AC2E1C-24F0-4309-B35E-73D36A427D2D}.Release|Any CPU.Build.0 = Release|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7FB2243-12AB-46A6-9DA4-FF8DABC77D8F}.Release|Any CPU.Build.0 = Release|Any CPU
{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F74A8C1-D38F-4CC0-ACD1-24459BA0EAFC}.Release|Any CPU.Build.0 = Release|Any CPU
{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.Build.0 = Release|Any CPU
{7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C584421D-5EC0-4821-B7D8-2633D8D405F2}
EndGlobalSection
EndGlobal

View File

@ -2,39 +2,51 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncAwaiter<T> : INotifyCompletion
{
public Action callback = null;
public T result;
private bool completed;
Action callback = null;
AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> reply)
{
reply.Then(x =>
{
this.completed = true;
this.IsCompleted = true;
this.result = x;
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public T GetResult()
{
if (exception != null)
throw exception;
return result;
}
public bool IsCompleted => completed;
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
// Continue....
callback = continuation;
if (IsCompleted)
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,25 +34,29 @@ using System.Runtime.CompilerServices;
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 T result;
protected List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected List<Action<T>> chunkCallbacks = new List<Action<T>>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
object callbacksLock = new object();
// object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
AutoResetEvent mutex = new AutoResetEvent(false);
public bool Ready
{
@ -60,7 +64,24 @@ 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
{
@ -69,53 +90,91 @@ namespace Esiur.Core
public IAsyncReply<T> Then(Action<T> callback)
{
callbacks.Add(callback);
//lock (callbacksLock)
//{
if (resultReady)
{
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Then ready");
callback(result);
return this;
}
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Then pending");
callbacks.Add(callback);
return this;
//}
}
public IAsyncReply<T> Error(Action<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public IAsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public IAsyncReply<T> Chunk(Action<T> callback)
{
// lock (callbacksLock)
// {
chunkCallbacks.Add(callback);
return this;
// }
}
public void Trigger(object result)
{
lock (callbacksLock)
{
if (resultReady)
return;
this.result = (T)result;
resultReady = true;
foreach (var cb in callbacks)
cb((T)result);
if (Debug)
Console.WriteLine($"AsyncReply: {GetHashCode()} Trigger");
}
//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");
//}
}
@ -128,13 +187,15 @@ namespace Esiur.Core
this.exception = exception as AsyncException;
else
this.exception = new AsyncException(ErrorType.Management, 0, exception.Message);
lock (callbacksLock)
{
foreach (var cb in errorCallbacks)
cb(this.exception);
}
// lock (callbacksLock)
// {
foreach (var cb in errorCallbacks)
cb(this.exception);
// }
mutex?.Set();
}
@ -143,26 +204,26 @@ namespace Esiur.Core
if (resultReady)
return;
lock (callbacksLock)
{
foreach (var cb in progressCallbacks)
cb(type, value, max);
//lock (callbacksLock)
//{
foreach (var cb in progressCallbacks)
cb(type, value, max);
}
//}
}
public void TriggerChunk(object value)
{
if (resultReady)
return;
lock (callbacksLock)
{
foreach (var cb in chunkCallbacks)
cb((T)value);
//lock (callbacksLock)
//{
foreach (var cb in chunkCallbacks)
cb((T)value);
}
//}
}
public AsyncAwaiter<T> GetAwaiter()
@ -170,21 +231,20 @@ namespace Esiur.Core
return new AsyncAwaiter<T>(this);
}
public AsyncReply()
{
//this.Debug = true;
}
public AsyncReply(T result)
{
//this.Debug = true;
resultReady = true;
this.result = result;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{
@ -218,7 +278,7 @@ namespace Esiur.Core
return base.Task.ContinueWith<T>((t) =>
{
#if NETSTANDARD1_5
#if NETSTANDARD
return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
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 TriggerChunk(object value);
T Wait();
}
}

View File

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

View File

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

View File

@ -34,6 +34,7 @@ using Esiur.Resource;
using System.Linq;
using System.Reflection;
using Esiur.Resource.Template;
using System.Runtime.CompilerServices;
namespace Esiur.Data
{
@ -171,7 +172,7 @@ namespace Esiur.Data
var result = (StructureComparisonResult)data[offset++];
IAsyncReply<Structure> previous = null;
AsyncReply<Structure> previous = null;
// string[] previousKeys = null;
// DataType[] previousTypes = null;
@ -1064,6 +1065,16 @@ namespace Esiur.Data
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>
/// Check if a type implements an interface
/// </summary>
@ -1086,7 +1097,7 @@ namespace Esiur.Data
if (type == iface)
return true;
#if NETSTANDARD1_5
#if NETSTANDARD
if (type.GetTypeInfo().GetInterfaces().Contains(iface))// (x=>x.GetTypeInfo().IsGenericType (iface))
return true;
@ -1109,7 +1120,7 @@ namespace Esiur.Data
if (type == iface)
return true;
#if NETSTANDARD1_5
#if NETSTANDARD
if (type.GetTypeInfo().GetInterfaces().Contains(iface))
return true;
@ -1137,7 +1148,7 @@ namespace Esiur.Data
{
if (childType == parentType)
return true;
#if NETSTANDARD1_5
#if NETSTANDARD
childType = childType.GetTypeInfo().BaseType;
#else
childType = childType.BaseType;

View File

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

View File

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

View File

@ -31,6 +31,7 @@ using System.Threading.Tasks;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
{
@ -61,6 +62,26 @@ namespace Esiur.Data
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()
{
return dic.GetEnumerator();

View File

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

View File

@ -72,20 +72,20 @@ namespace Esiur.Net.DataLink
{
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)
{
src.OnNewPacket += PacketReceived;

View File

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

View File

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

View File

@ -312,7 +312,7 @@ namespace Esiur.Net.IIP
{
var rt = packet.Parse(msg, offset, ends);
//Console.WriteLine("Rec: " + chunkId + " " + packet.ToString());
/*
if (packet.Command == IIPPacketCommand.Event)
Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString());
@ -321,21 +321,27 @@ namespace Esiur.Net.IIP
else
Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends);
*/
//packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString());
//if (packs.Count > 1)
// Console.WriteLine("P2");
// Console.WriteLine("P2");
//Console.WriteLine("");
if (rt <= 0)
{
//Console.WriteLine("Hold");
var size = ends - offset;
data.HoldFor(msg, offset, size, size + (uint)(-rt));
return ends;
}
else
{
//Console.WriteLine($"CMD {packet.Command} {offset} {ends}");
offset += (uint)rt;
if (packet.Command == IIPPacket.IIPPacketCommand.Event)
@ -807,7 +813,9 @@ namespace Esiur.Net.IIP
sock.Connect(domain, port).Then((x)=> {
Assign(sock);
//rt.trigger(true);
}).Error((x) => openReply.TriggerError(x));
}).Error((x) =>
openReply.TriggerError(x)
);
return openReply;
}
@ -840,6 +848,65 @@ namespace Esiur.Net.IIP
// nothing to do
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 =>
{
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 =>
{
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.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
r.Instance.Children.OnAdd -= Children_OnAdd;
r.Instance.Children.OnRemoved -= Children_OnRemoved;
// r.Instance.Children.OnAdd -= Children_OnAdd;
// r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
r.Instance.Children.OnAdd += Children_OnAdd;
r.Instance.Children.OnRemoved += Children_OnRemoved;
//r.Instance.Children.OnAdd += Children_OnAdd;
//r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified;
var link = DC.ToBytes(r.Instance.Link);
@ -520,6 +526,28 @@ namespace Esiur.Net.IIP
.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)
{
Warehouse.Get(resourceId).Then((res) =>
@ -531,16 +559,16 @@ namespace Esiur.Net.IIP
r.Instance.ResourceEventOccurred -= Instance_EventOccurred;
r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
r.Instance.Children.OnAdd -= Children_OnAdd;
r.Instance.Children.OnRemoved -= Children_OnRemoved;
//r.Instance.Children.OnAdd -= Children_OnAdd;
//r.Instance.Children.OnRemoved -= Children_OnRemoved;
r.Instance.Attributes.OnModified -= Attributes_OnModified;
// subscribe
r.Instance.ResourceEventOccurred += Instance_EventOccurred;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
r.Instance.Children.OnAdd += Children_OnAdd;
r.Instance.Children.OnRemoved += Children_OnRemoved;
//r.Instance.Children.OnAdd += Children_OnAdd;
//r.Instance.Children.OnRemoved += Children_OnRemoved;
r.Instance.Attributes.OnModified += Attributes_OnModified;
// reply ok
@ -646,7 +674,7 @@ namespace Esiur.Net.IIP
Codec.ParseStructure(content, offset, cl, this).Then(values =>
{
#if NETSTANDARD1_5
#if NETSTANDARD
var constructors = Type.GetType(className).GetTypeInfo().GetConstructors();
#else
var constructors = Type.GetType(className).GetConstructors();
@ -791,7 +819,7 @@ namespace Esiur.Net.IIP
return;
}
parent.Instance.Children.Add(child);
parent.Instance.Store.AddChild(parent, child);
SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done();
//child.Instance.Parents
@ -830,7 +858,7 @@ namespace Esiur.Net.IIP
return;
}
parent.Instance.Children.Remove(child);
parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child);
SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done();
//child.Instance.Parents
@ -871,9 +899,14 @@ namespace Esiur.Net.IIP
return;
}
SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback)
.AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Children.ToArray(), this, true))
.Done();
resource.Instance.Children<IResource>().Then(children =>
{
SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback)
.AddUInt8Array(Codec.ComposeResourceArray(children, this, true))
.Done();
});
});
}
@ -888,9 +921,14 @@ namespace Esiur.Net.IIP
return;
}
SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback)
.AddUInt8Array(Codec.ComposeResourceArray(resource.Instance.Parents.ToArray(), this, true))
.Done();
resource.Instance.Parents<IResource>().Then(parents =>
{
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)
{
Warehouse.Query(resourceLink).Then((r) =>
Action<IResource[]> queryCallback = (r) =>
{
//if (r != null)
//{
@ -1022,12 +1061,12 @@ namespace Esiur.Net.IIP
SendReply(IIPPacket.IIPPacketAction.QueryLink, callback)
.AddUInt8Array(Codec.ComposeResourceArray(list, this, true))
.Done();
//}
//else
//{
// reply failed
//}
});
};
if (Server?.EntryPoint != null)
Server.EntryPoint.Query(resourceLink, this).Then(queryCallback);
else
Warehouse.Query(resourceLink).ContinueWith(x => queryCallback(x.Result));
}
void IIPRequestResourceAttribute(uint callback, uint resourceId)
@ -1068,7 +1107,7 @@ namespace Esiur.Net.IIP
}
else
{
#if NETSTANDARD1_5
#if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else
var fi = r.GetType().GetMethod(ft.Name);
@ -1134,7 +1173,7 @@ namespace Esiur.Net.IIP
{
(rt as Task).ContinueWith(t =>
{
#if NETSTANDARD1_5
#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
@ -1225,7 +1264,7 @@ namespace Esiur.Net.IIP
}
else
{
#if NETSTANDARD1_5
#if NETSTANDARD
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else
var fi = r.GetType().GetMethod(ft.Name);
@ -1285,7 +1324,7 @@ namespace Esiur.Net.IIP
{
(rt as Task).ContinueWith(t =>
{
#if NETSTANDARD1_5
#if NETSTANDARD
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
@ -1358,7 +1397,7 @@ namespace Esiur.Net.IIP
}
else
{
#if NETSTANDARD1_5
#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
@ -1435,7 +1474,7 @@ namespace Esiur.Net.IIP
{
if (r.Instance.GetAge(index) > age)
{
#if NETSTANDARD1_5
#if NETSTANDARD
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
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);
#else
var pi = r.GetType().GetProperty(pt.Name);
@ -1748,12 +1787,18 @@ namespace Esiur.Net.IIP
Query(path).Then(ar =>
{
//if (filter != null)
// ar = ar?.Where(filter).ToArray();
// MISSING: should dispatch the unused resources.
if (ar?.Length > 0)
rt.Trigger(ar[0]);
else
rt.Trigger(null);
}).Error(ex => rt.TriggerError(ex));
return rt;
/*

View File

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

View File

@ -56,6 +56,12 @@ namespace Esiur.Net.IIP
set;
}
public EntryPoint EntryPoint
{
get;
set;
}
//[Storable]
//[ResourceProperty]
public ushort port
@ -128,8 +134,7 @@ namespace Esiur.Net.IIP
protected override void ClientConnected(DistributedConnection sender)
{
Console.WriteLine("DistributedConnection Client Connected");
//Console.WriteLine("DistributedConnection Client Connected");
}
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)
{
//dataLengthNeeded = needed - (ends - offset);
dataLengthNeeded = needed - (ends - originalOffset);
dataLengthNeeded = needed - (ends - offset);
//dataLengthNeeded = needed - (ends - originalOffset);
return true;
}

View File

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

View File

@ -65,18 +65,24 @@ namespace Esiur.Net.TCP
}
public Instance Instance { get; set; }
TCPFilter[] filters = null;
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
TCPSocket listener;
if (ip != null)
listener =new TCPSocket(new IPEndPoint(IPAddress.Parse(ip), port));
else
listener = new TCPSocket(new IPEndPoint(IPAddress.Any, port));
Start(listener, timeout, clock);
}
else if (trigger == ResourceTrigger.Terminate)
{
@ -87,6 +93,10 @@ namespace Esiur.Net.TCP
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
Instance.Children<TCPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(true);
}
@ -97,14 +107,10 @@ namespace Esiur.Net.TCP
{
var msg = data.Read();
foreach (var resource in Instance.Children)
{
if (resource is TCPFilter)
{
var f = resource as TCPFilter;
if (f.Execute(msg, data, sender))
foreach (var filter in filters)
{
if (filter.Execute(msg, data, sender))
return;
}
}
}
@ -115,25 +121,17 @@ namespace Esiur.Net.TCP
protected override void ClientConnected(TCPConnection sender)
{
foreach (var resource in Instance.Children)
foreach (var filter in filters)
{
if (resource is TCPFilter)
{
var f = resource as TCPFilter;
f.Connected(sender);
}
filter.Connected(sender);
}
}
protected override void ClientDisconnected(TCPConnection sender)
{
foreach (var resource in Instance.Children)
foreach (var filter in filters)
{
if (resource is TCPFilter)
{
var f = resource as TCPFilter;
f.Disconnected(sender);
}
filter.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">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<TargetFramework>netstandard1.5</TargetFramework>
<Configuration>Debug</Configuration>
<TargetFramework>netstandard2.0</TargetFramework>
<PublishDir>M:\opt\esiur</PublishDir>
<Platform>Any CPU</Platform>
</PropertyGroup>

View File

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

View File

@ -35,13 +35,27 @@ namespace Esiur.Resource
{
public interface IStore:IResource
{
AsyncReply<IResource> Get(string path);
AsyncReply<IResource> Retrieve(uint iid);
AsyncReply<IResource> Get(string path);//, Func<IResource, bool> filter = null);
//AsyncReply<IResource> Retrieve(uint iid);
bool Put(IResource resource);
string Link(IResource resource);
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 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[]> 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.Security.Authority;
using Esiur.Proxy;
using Esiur.Core;
namespace Esiur.Resource
{
@ -19,16 +20,17 @@ namespace Esiur.Resource
{
string name;
AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
IResource resource;
//IQueryable<IResource> children;//
//AutoList<IResource, Instance> children;// = new AutoList<IResource, Instance>();
WeakReference<IResource> resource;
IStore store;
AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
//AutoList<IResource, Instance> parents;// = new AutoList<IResource>();
//bool inherit;
ResourceTemplate template;
AutoList<IPermissionsManager, Instance> managers;// = new AutoList<IPermissionManager, Instance>();
public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue);
//public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] users, DistributedConnection[] connections, object[] args);
@ -40,6 +42,8 @@ namespace Esiur.Resource
public event ResourceEventOccurredEvent ResourceEventOccurred;
public event ResourceDestroyedEvent ResourceDestroyed;
bool loading = false;
KeyList<string, object> attributes;
List<ulong> ages = new List<ulong>();
@ -90,7 +94,7 @@ namespace Esiur.Resource
attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers");
}
foreach(var attr in attributes)
foreach (var attr in attributes)
{
if (attr == "name")
st["name"] = this.name;
@ -109,15 +113,15 @@ namespace Esiur.Resource
}
else if (attr == "parents")
{
st["parents"] = parents.ToArray();
//st["parents"] = parents.ToArray();
}
else if (attr == "children")
{
st["children"] = children.ToArray();
//st["children"] = children.ToArray();
}
else if (attr == "childrenCount")
{
st["childrenCount"] = children.Count;
//st["childrenCount"] = children.Count;
}
else if (attr == "type")
{
@ -131,7 +135,7 @@ namespace Esiur.Resource
}
public bool SetAttributes(Structure attributes, bool clearAttributes = false)
{
{
try
{
@ -155,8 +159,13 @@ namespace Esiur.Resource
{
var settings = m["settings"] as Structure;
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
return false;
@ -166,7 +175,7 @@ namespace Esiur.Resource
{
this.attributes[attr.Key] = attr.Value;
}
}
catch
{
@ -175,7 +184,7 @@ namespace Esiur.Resource
return true;
}
/*
public Structure GetAttributes()
{
@ -256,7 +265,7 @@ namespace Esiur.Resource
return DateTime.MinValue;
}
/// <summary>
/// Load property value (used by stores)
/// </summary>
@ -266,13 +275,19 @@ namespace Esiur.Resource
/// <returns></returns>
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);
if (pt == null)
return false;
/*
#if NETSTANDARD1_5
#if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() });
#else
var pi = resource.GetType().GetProperty(pt.Name);
@ -282,18 +297,25 @@ namespace Esiur.Resource
if (pt.Info.PropertyType == typeof(DistributedPropertyContext))
return false;
try
if (pt.Info.CanWrite)
{
if (pt.Info.CanWrite)
pt.Info.SetValue(resource, DC.CastConvert(value, pt.Info.PropertyType));
}
catch(Exception ex)
{
//Console.WriteLine(resource.ToString() + " " + name);
Global.Log(ex);
try
{
loading = true;
pt.Info.SetValue(res, DC.CastConvert(value, pt.Info.PropertyType));
}
catch (Exception ex)
{
//Console.WriteLine(resource.ToString() + " " + name);
Global.Log(ex);
}
loading = false;
}
SetAge(pt.Index, age);
SetModificationDate(pt.Index, modificationDate);
@ -359,16 +381,19 @@ namespace Esiur.Resource
foreach (var pt in template.Properties)
{
/*
#if NETSTANDARD1_5
#if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
*/
var rt = pt.Info.GetValue(resource, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
IResource res;
if (resource.TryGetTarget(out res))
{
var rt = pt.Info.GetValue(res, null);
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
}
return props.ToArray();
@ -446,7 +471,7 @@ namespace Esiur.Resource
/// <returns></returns>
public bool IsStorable()
{
#if NETSTANDARD1_5
#if NETSTANDARD
var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray();
#else
var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true);
@ -458,22 +483,27 @@ namespace Esiur.Resource
internal void EmitModification(PropertyTemplate pt, object value)
{
instanceAge++;
var now = DateTime.UtcNow;
ages[pt.Index] = instanceAge;
modificationDates[pt.Index] = now;
if (pt.Storage == StorageMode.NonVolatile)
IResource res;
if (this.resource.TryGetTarget(out res))
{
store.Modify(resource, pt.Name, value, ages[pt.Index], now);
}
else if (pt.Storage == StorageMode.Recordable)
{
store.Record(resource, pt.Name, value, ages[pt.Index], now);
}
instanceAge++;
var now = DateTime.UtcNow;
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>
@ -484,6 +514,9 @@ namespace Esiur.Resource
/// <param name="oldValue"></param>
public void Modified([CallerMemberName] string propertyName = "")
{
if (loading)
return;
object value;
if (GetPropertyValue(propertyName, out value))
{
@ -496,7 +529,12 @@ namespace Esiur.Resource
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>
@ -508,7 +546,7 @@ namespace Esiur.Resource
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);
#else
@ -521,7 +559,7 @@ namespace Esiur.Resource
if (pt != null && pt.Info != null)
{
/*
#if NETSTANDARD1_5
#if NETSTANDARD
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
#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;
}
@ -556,10 +602,7 @@ namespace Esiur.Resource
/// <summary>
/// List of parents.
/// </summary>
public AutoList<IResource, Instance> Parents
{
get { return parents; }
}
//public AutoList<IResource, Instance> Parents => parents;
/// <summary>
/// Store responsible for creating and keeping the resource.
@ -572,15 +615,54 @@ namespace Esiur.Resource
/// <summary>
/// List of children.
/// </summary>
public AutoList<IResource, Instance> Children
{
get { return children; }
}
// public AutoList<IResource, Instance> Children => children;
/// <summary>
/// The unique and permanent link to the resource.
/// </summary>
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
{
@ -607,6 +689,8 @@ namespace Esiur.Resource
}
}
}
*
*/
/// <summary>
/// Instance name.
@ -623,7 +707,16 @@ namespace Esiur.Resource
/// </summary>
public IResource Resource
{
get { return resource; }
get
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
return res;
}
else
return null;
}
}
/// <summary>
@ -658,11 +751,15 @@ namespace Esiur.Resource
/// <returns>Ruling.</returns>
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);
if (r != Ruling.DontCare)
return r;
foreach (IPermissionsManager manager in managers)
{
var r = manager.Applicable(res, session, action, member, inquirer);
if (r != Ruling.DontCare)
return r;
}
}
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)
{
this.store = store;
this.resource = resource;
this.resource = new WeakReference<IResource>(resource);
this.id = id;
this.name = name;
this.instanceAge = age;
this.attributes = new KeyList<string, object>(this);
children = new AutoList<IResource, Instance>(this);
parents = new AutoList<IResource, Instance>(this);
//children = new AutoList<IResource, Instance>(this);
//parents = new AutoList<IResource, Instance>(this);
managers = new AutoList<IPermissionsManager, Instance>(this);
children.OnAdd += Children_OnAdd;
children.OnRemoved += Children_OnRemoved;
parents.OnAdd += Parents_OnAdd;
parents.OnRemoved += Parents_OnRemoved;
//children.OnAdd += Children_OnAdd;
//children.OnRemoved += Children_OnRemoved;
//parents.OnAdd += Parents_OnAdd;
//parents.OnRemoved += Parents_OnRemoved;
resource.OnDestroy += Resource_OnDestroy;
@ -715,7 +812,7 @@ namespace Esiur.Resource
// connect events
Type t = ResourceProxy.GetBaseType(resource);
#if NETSTANDARD1_5
#if NETSTANDARD
var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#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);
}
@ -804,7 +906,7 @@ namespace Esiur.Resource
if (!value.Instance.children.Contains(resource))
value.Instance.children.Add(resource);
}
*/
private void Resource_OnDestroy(object sender)
{

View File

@ -36,7 +36,7 @@ namespace Esiur.Resource
public virtual void Destroy()
{
OnDestroy?.Invoke(this);
}
public virtual AsyncReply<bool> Trigger(ResourceTrigger trigger)
@ -51,5 +51,10 @@ namespace Esiur.Resource
{
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;
#if NETSTANDARD1_5
#if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo[] methodsInfo = type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

View File

@ -32,6 +32,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Net.IIP;
using System.Text.RegularExpressions;
namespace Esiur.Resource
{
@ -40,13 +42,13 @@ namespace Esiur.Resource
{
//static byte prefixCounter;
static AutoList<IResource, Instance> stores = new AutoList<IResource, Instance>(null);
static Dictionary<uint, IResource> resources = new Dictionary<uint, IResource>();
static AutoList<IStore, Instance> stores = new AutoList<IStore, Instance>(null);
static Dictionary<uint, WeakReference<IResource>> resources = new Dictionary<uint, WeakReference<IResource>>();
static uint resourceCounter = 0;
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 StoreDisconnectedEvent(IStore store);
@ -54,7 +56,15 @@ namespace Esiur.Resource
public static event StoreConnectedEvent StoreConnected;
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>
/// Get a store by its name.
@ -77,7 +87,13 @@ namespace Esiur.Resource
public static AsyncReply<IResource> Get(uint 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
return new AsyncReply<IResource>(null);
}
@ -109,7 +125,11 @@ namespace Esiur.Resource
var rBag = new AsyncBag<bool>();
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();
@ -123,7 +143,7 @@ namespace Esiur.Resource
}
rt.Trigger(true);
storeIsOpen = true;
warehouseIsOpen = true;
});
});
@ -142,15 +162,30 @@ namespace Esiur.Resource
var bag = new AsyncBag<bool>();
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)
bag.Add(store.Trigger(ResourceTrigger.Terminate));
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)
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>();
@ -191,18 +227,16 @@ namespace Esiur.Resource
else
foreach (IResource child in resources)
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();
}
public static AsyncReply<IResource[]> Query(string 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);
}
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>
/// Get a resource by its path.
@ -236,38 +315,15 @@ namespace Esiur.Resource
/// </summary>
/// <param name="path"></param>
/// <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)
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);
}
var rt = new AsyncReply<IResource>();
// Should we create a new store ?
if (path.Contains("://"))
{
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 rt = new AsyncReply<IResource>();
if (Protocols.ContainsKey(url[0]))
{
var handler = Protocols[url[0]];
var store = handler();// Activator.CreateInstance(handler.GetType()) as IStore;
Put(store, url[0] + "://" + hostname, null, parent, null, 0, manager, attributes);
var store = handler();
Put(store, hostname, null, parent, null, 0, manager, attributes);
store.Trigger(ResourceTrigger.Open).Then(x => {
warehouseIsOpen = true;
if (pathname.Length > 0 && pathname != "")
store.Get(pathname).Then(r => {
rt.Trigger(r);
@ -296,13 +353,24 @@ namespace Esiur.Resource
rt.TriggerError(e);
Warehouse.Remove(store);
});
return rt;
}
return rt;
}
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;
return new AsyncReply<IResource>(null);
}
/// <summary>
@ -312,12 +380,31 @@ namespace Esiur.Resource
/// <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="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);
if (attributes != null)
resource.Instance.SetAttributes(attributes);
resource.Instance.SetAttributes(Structure.FromObject(attributes));
if (manager != null)
resource.Instance.Managers.Add(manager);
@ -325,6 +412,8 @@ namespace Esiur.Resource
if (store == parent)
parent = null;
/*
if (parent == null)
{
if (!(resource is IStore))
@ -332,20 +421,26 @@ namespace Esiur.Resource
}
else
parent.Instance.Children.Add(resource);
*/
if (resource is IStore)
{
stores.Add(resource as IStore);
if (resource is IStore)
StoreConnected?.Invoke(resource as IStore, name);
}
else
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);
}
@ -430,9 +525,17 @@ namespace Esiur.Resource
stores.Remove(resource as IStore);
// 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)
Remove(o);
{
IResource r;
if (o.TryGetTarget(out r))
Remove(r);
}
StoreDisconnected?.Invoke(resource as IStore);
}

View File

@ -33,7 +33,7 @@ using Esiur.Security.Authority;
namespace Esiur.Security.Permissions
{
public class ParentalPermissionsManager : IPermissionsManager
public class StorePermissionsManager : IPermissionsManager
{
Structure settings;
@ -41,20 +41,12 @@ namespace Esiur.Security.Permissions
public Ruling Applicable(IResource resource, Session session, ActionType action, MemberTemplate member, object inquirer = null)
{
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;
return resource.Instance.Store.Instance.Applicable(session, action, member, inquirer);
}
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)
{
foreach (var r in resources)
if (r.Value.Instance.Name == path)
return new AsyncReply<IResource>(r.Value);
return new AsyncReply<IResource>(null);
}
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;
}
public AsyncReply<IResource> Retrieve(uint 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
return new AsyncReply<IResource>(null);
}
@ -75,6 +87,59 @@ namespace Esiur.Stores
{
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
{
public class MyObject : Resource
public class MyObject : EntryPoint
{
[ResourceEvent]
@ -90,6 +90,16 @@ namespace Test
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]
public Structure Info
{

View File

@ -51,8 +51,6 @@ namespace Test
{
Warehouse.Protocols.Add("iip", () => new DistributedConnection());
// Create stores to keep objects.
var system = Warehouse.New<MemoryStore>("system");
var remote = Warehouse.New<MemoryStore>("remote");
@ -64,12 +62,12 @@ namespace Test
// Set membership which handles authentication.
iip.Membership = Warehouse.New<MyMembership>("ms", system);
// 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
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.
var wsOverHttp = Warehouse.New<IIPoWS>("IIPoWS", system, http);
@ -106,13 +104,10 @@ namespace Test
}
}));
else
localObject = (MyObject)(await Warehouse.Get("db/my"));//.Then((o) => { myObject = (MyObject)o; });
localObject = (MyObject)(await Warehouse.Get("db/my"));
//var obj = ProxyObject.<MyObject>();
//Warehouse.Put(obj, "dd", system);
//obj.Level2= 33;
iip.EntryPoint = localObject;
Warehouse.StoreConnected += (store, name) =>
{
@ -160,7 +155,7 @@ namespace Test
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;