2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-26 21:13:13 +00:00
This commit is contained in:
2020-11-15 03:57:49 +03:00
parent ba084b79e6
commit 8ff832d6f1
147 changed files with 835 additions and 725 deletions

View File

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

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncAwaiter<T> : INotifyCompletion
{
Action callback = null;
AsyncException exception = null;
T result;
public AsyncAwaiter(AsyncReply<T> reply)
{
reply.Then(x =>
{
this.IsCompleted = true;
this.result = (T)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 { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
}
}

119
Esiur/Core/AsyncBag.cs Normal file
View File

@ -0,0 +1,119 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncBag: AsyncReply
{
protected List<AsyncReply> replies = new List<AsyncReply>();
List<object> results = new List<object>();
int count = 0;
bool sealedBag = false;
public AsyncBag Then(Action<object[]> callback)
{
base.Then(new Action<object>(o => callback((object[])o)));
return this;
}
public new AsyncBagAwaiter GetAwaiter()
{
return new AsyncBagAwaiter(this);
}
public new object[] Wait()
{
return (object[])base.Wait();
}
public new object[] Wait(int timeout)
{
return (object[])base.Wait(timeout);
}
public void Seal()
{
if (sealedBag)
return;
sealedBag = true;
if (results.Count == 0)
Trigger(new object[0]);
for (var i = 0; i < results.Count; i++)
//foreach(var reply in results.Keys)
{
var k = replies[i];// results.Keys.ElementAt(i);
var index = i;
k.Then((r) =>
{
results[index] = r;
count++;
if (count == results.Count)
Trigger(results.ToArray());
});
}
}
public void Add(AsyncReply reply)
{
if (!sealedBag)
{
results.Add(null);
replies.Add(reply);
}
}
public void AddBag(AsyncBag bag)
{
foreach (var r in bag.replies)
Add(r);
}
public AsyncBag()
{
}
public AsyncBag(object[] results)
: base(results)
{
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncBagAwaiter : INotifyCompletion
{
Action callback = null;
AsyncException exception = null;
object[] result;
public AsyncBagAwaiter(AsyncBag reply)
{
reply.Then(x =>
{
this.IsCompleted = true;
this.result = x;
this.callback?.Invoke();
}).Error(x =>
{
exception = x;
this.IsCompleted = true;
this.callback?.Invoke();
});
}
public object[] GetResult()
{
if (exception != null)
throw exception;
return result;
}
public bool IsCompleted { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncBagAwaiter<T> : INotifyCompletion
{
Action callback = null;
AsyncException exception = null;
T[] result;
public AsyncBagAwaiter(AsyncBag<T> reply)
{
reply.Then(x =>
{
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 { get; private set; }
public void OnCompleted(Action continuation)
{
if (IsCompleted)
continuation?.Invoke();
else
// Continue....
callback = continuation;
}
}
}

View File

@ -0,0 +1,75 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncBag<T>: AsyncBag
{
public AsyncBag<T> Then(Action<T[]> callback)
{
base.Then(new Action<object>((o) => callback(((object[])o).Select(x=>(T)x).ToArray())));
return this;
}
public void Add(AsyncReply<T> reply)
{
base.Add(reply);
}
public void AddBag(AsyncBag<T> bag)
{
foreach (var r in bag.replies)
Add(r);
}
public new AsyncBagAwaiter<T> GetAwaiter()
{
return new AsyncBagAwaiter<T>(this);
}
public new T[] Wait()
{
return base.Wait().Select(x => (T)x).ToArray();
}
public AsyncBag()
{
}
public AsyncBag(T[] results)
: base(results.Select(x=>(object)x).ToArray())
{
}
}
}

View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Core
{
public class AsyncException : Exception
{
public readonly ErrorType Type;
public readonly ExceptionCode Code;
public AsyncException(Exception exception) :base(exception.Message, exception)
{
Type = ErrorType.Exception;
Code = 0;
}
public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace;
public AsyncException(ErrorType type, ushort code, string message)
: base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message)
{
this.Type = type;
this.Code = (ExceptionCode)code;
}
public override string ToString()
{
return Code.ToString() + ": " + Message;
}
}
}

84
Esiur/Core/AsyncQueue.cs Normal file
View File

@ -0,0 +1,84 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncQueue<T> : AsyncReply<T>
{
List<AsyncReply<T>> list = new List<AsyncReply<T>>();
//Action<T> callback;
object queueLock = new object();
//public AsyncQueue<T> Then(Action<T> callback)
//{
// base.Then(new Action<object>(o => callback((T)o)));
//return this;
//}
public void Add(AsyncReply<T> reply)
{
lock (queueLock)
list.Add(reply);
resultReady = false;
reply.Then(processQueue);
}
public void Remove(AsyncReply<T> reply)
{
lock (queueLock)
list.Remove(reply);
processQueue(default(T));
}
void processQueue(T o)
{
lock (queueLock)
for (var i = 0; i < list.Count; i++)
if (list[i].Ready)
{
Trigger(list[i].Result);
resultReady = false;
list.RemoveAt(i);
i--;
}
else
break;
resultReady = (list.Count == 0);
}
public AsyncQueue()
{
}
}
}

351
Esiur/Core/AsyncReply.cs Normal file
View File

@ -0,0 +1,351 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Resource;
using System.Reflection;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace Esiur.Core
{
[AsyncMethodBuilder(typeof(AsyncReplyBuilder))]
public class AsyncReply
{
public bool Debug = false;
protected List<Action<object>> callbacks = new List<Action<object>>();
protected object 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<object>> chunkCallbacks = new List<Action<object>>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
object asyncLock = new object();
//public Timer timeout;// = new Timer()
protected bool resultReady = false;
AsyncException exception;
// StackTrace trace;
AutoResetEvent mutex = new AutoResetEvent(false);
public static int MaxId;
public int Id;
public bool Ready
{
get { return resultReady; }
}
public object Wait()
{
if (resultReady)
return result;
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait");
//mutex = new AutoResetEvent(false);
mutex.WaitOne();
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait ended");
return result;
}
public object Wait(int millisecondsTimeout)
{
if (resultReady)
return result;
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait");
if (!mutex.WaitOne(millisecondsTimeout))
{
var e = new Exception("AsyncReply timeout");
TriggerError(e);
throw e;
}
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait ended");
return result;
}
public object Result
{
get { return result; }
}
public AsyncReply Then(Action<object> callback)
{
//lock (callbacksLock)
//{
lock (asyncLock)
{
// trace = new StackTrace();
if (resultReady)
{
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Then ready");
callback(result);
return this;
}
//timeout = new Timer(x =>
//{
// // Get calling method name
// Console.WriteLine(trace.GetFrame(1).GetMethod().Name);
// var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name));
// timeout.Dispose();
// tr = trace.ToString();
// throw new Exception("Request timeout " + Id);
//}, null, 15000, 0);
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Then pending");
callbacks.Add(callback);
return this;
}
}
public AsyncReply Error(Action<AsyncException> callback)
{
// lock (callbacksLock)
// {
errorCallbacks.Add(callback);
if (exception != null)
callback(exception);
return this;
//}
}
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
//lock (callbacksLock)
//{
progressCallbacks.Add(callback);
return this;
//}
}
public AsyncReply Chunk(Action<object> callback)
{
// lock (callbacksLock)
// {
chunkCallbacks.Add(callback);
return this;
// }
}
public void Trigger(object result)
{
lock (asyncLock)
{
//timeout?.Dispose();
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Trigger");
if (resultReady)
return;
this.result = result;
resultReady = true;
//if (mutex != null)
mutex.Set();
foreach (var cb in callbacks)
cb(result);
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Trigger ended");
}
}
public void TriggerError(Exception exception)
{
//timeout?.Dispose();
if (resultReady)
return;
if (exception is AsyncException)
this.exception = exception as AsyncException;
else
this.exception = new AsyncException(exception);
// lock (callbacksLock)
// {
foreach (var cb in errorCallbacks)
cb(this.exception);
// }
mutex?.Set();
}
public void TriggerProgress(ProgressType type, int value, int max)
{
//timeout?.Dispose();
//lock (callbacksLock)
//{
foreach (var cb in progressCallbacks)
cb(type, value, max);
//}
}
public void TriggerChunk(object value)
{
//timeout?.Dispose();
//lock (callbacksLock)
//{
foreach (var cb in chunkCallbacks)
cb(value);
//}
}
public AsyncAwaiter GetAwaiter()
{
return new AsyncAwaiter(this);
}
public AsyncReply()
{
// this.Debug = true;
Id = MaxId++;
}
public AsyncReply(object result)
{
// this.Debug = true;
resultReady = true;
this.result = result;
Id = MaxId++;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((t) =>
{
#if NETSTANDARD
return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
return (T)t.GetType().GetProperty("Result").GetValue(t);
#endif
});
}
}
public T Current => throw new NotImplementedException();
public AsyncReply(T result)
: base(result)
{
}
*/
}
}

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Core
{
public class AsyncReplyBuilder
{
AsyncReply reply;
AsyncReplyBuilder(AsyncReply reply)
{
this.reply = reply;
}
public static AsyncReplyBuilder Create()
{
return new AsyncReplyBuilder(new AsyncReply());
}
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
Console.WriteLine("SetStateMachine");
}
public void SetException(Exception exception)
{
reply.TriggerError(exception);
}
public void SetResult()
{
reply.Trigger(null);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
public AsyncReply Task
{
get
{
return reply;
}
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Core
{
public class AsyncReplyBuilder<T>
{
AsyncReply<T> reply;
AsyncReplyBuilder(AsyncReply<T> reply)
{
this.reply = reply;
}
public static AsyncReplyBuilder<T> Create()
{
return new AsyncReplyBuilder<T>(new AsyncReply<T>());
}
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
Console.WriteLine("SetStateMachine");
}
public void SetException(Exception exception)
{
reply.TriggerError(exception);
}
public void SetResult(T result)
{
reply.Trigger(result);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.OnCompleted(stateMachine.MoveNext);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
public AsyncReply<T> Task
{
get {
return reply;
}
}
}
}

View File

@ -0,0 +1,379 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Resource;
using System.Reflection;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace Esiur.Core
{
[AsyncMethodBuilder(typeof(AsyncReplyBuilder<>))]
public class AsyncReply<T> : AsyncReply
{
public AsyncReply<T> Then(Action<T> callback)
{
base.Then((x)=>callback((T)x));
return this;
}
public new AsyncReply<T> Progress(Action<ProgressType, int, int> callback)
{
base.Progress(callback);
return this;
}
public AsyncReply<T> Chunk(Action<T> callback)
{
chunkCallbacks.Add((x)=>callback((T)x));
return this;
}
public AsyncReply(T result)
: base(result)
{
}
public AsyncReply()
:base()
{
}
public new AsyncAwaiter<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public new T Wait()
{
return (T)base.Wait();
}
public new T Wait(int millisecondsTimeout)
{
return (T)base.Wait(millisecondsTimeout);
}
/*
protected new List<Action> callbacks = new List<Action>();
protected new object result;
protected new List<Action<AsyncException>> errorCallbacks = new List<Action<AsyncException>>();
protected new List<Action<ProgressType, int, int>> progressCallbacks = new List<Action<ProgressType, int, int>>();
protected new List<Action> chunkCallbacks = new List<Action>();
//List<AsyncAwaiter> awaiters = new List<AsyncAwaiter>();
object asyncLock = new object();
//public Timer timeout;// = new Timer()
AsyncException exception;
// StackTrace trace;
AutoResetEvent mutex = new AutoResetEvent(false);
public static int MaxId;
public int Id;
public bool Ready
{
get { return resultReady; }
}
public T Wait()
{
if (resultReady)
return result;
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait");
//mutex = new AutoResetEvent(false);
mutex.WaitOne();
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Wait ended");
return result;
}
public object Result
{
get { return result; }
}
public IAsyncReply<T> Then(Action<T> callback)
{
//lock (callbacksLock)
//{
lock (asyncLock)
{
// trace = new StackTrace();
if (resultReady)
{
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Then ready");
callback(result);
return this;
}
//timeout = new Timer(x =>
//{
// // Get calling method name
// Console.WriteLine(trace.GetFrame(1).GetMethod().Name);
// var tr = String.Join("\r\n", trace.GetFrames().Select(f => f.GetMethod().Name));
// timeout.Dispose();
// tr = trace.ToString();
// throw new Exception("Request timeout " + Id);
//}, null, 15000, 0);
if (Debug)
Console.WriteLine($"AsyncReply: {Id} 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 (asyncLock)
{
//timeout?.Dispose();
if (Debug)
Console.WriteLine($"AsyncReply: {Id} Trigger");
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: {Id} Trigger ended");
}
}
public void TriggerError(Exception exception)
{
//timeout?.Dispose();
if (resultReady)
return;
if (exception is AsyncException)
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);
// }
mutex?.Set();
}
public void TriggerProgress(ProgressType type, int value, int max)
{
//timeout?.Dispose();
if (resultReady)
return;
//lock (callbacksLock)
//{
foreach (var cb in progressCallbacks)
cb(type, value, max);
//}
}
public void TriggerChunk(object value)
{
//timeout?.Dispose();
if (resultReady)
return;
//lock (callbacksLock)
//{
foreach (var cb in chunkCallbacks)
cb((T)value);
//}
}
public AsyncAwaiter<T> GetAwaiter()
{
return new AsyncAwaiter<T>(this);
}
public AsyncReply()
{
// this.Debug = true;
Id = MaxId++;
}
public AsyncReply(T result)
{
// this.Debug = true;
resultReady = true;
this.result = result;
Id = MaxId++;
}
/*
public AsyncReply<T> Then(Action<T> callback)
{
base.Then(new Action<object>(o => callback((T)o)));
return this;
}
public void Trigger(T result)
{
Trigger((object)result);
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public AsyncReply()
{
}
public new Task<T> Task
{
get
{
return base.Task.ContinueWith<T>((t) =>
{
#if NETSTANDARD
return (T)t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
return (T)t.GetType().GetProperty("Result").GetValue(t);
#endif
});
}
}
public T Current => throw new NotImplementedException();
*/
}
}

185
Esiur/Core/AsyncReplyNon.cs Normal file
View File

@ -0,0 +1,185 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public class AsyncReply
{
protected List<Action<object>> callbacks = new List<Action<object>>();
protected object 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<object>> chunkCallbacks = new List<Action<object>>();
object callbacksLock = new object();
protected bool resultReady = false;
AsyncException exception;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
public bool Ready
{
get { return resultReady; }
}
public object Result
{
get { return result; }
}
public AsyncReply Then(Action<object> callback)
{
callbacks.Add(callback);
if (resultReady)
callback(result);
return this;
}
public AsyncReply Error(Action<AsyncException> callback)
{
errorCallbacks.Add(callback);
if (exception != null)
{
callback(exception);
tcs.SetException(exception);
}
return this;
}
public AsyncReply Progress(Action<ProgressType, int, int> callback)
{
progressCallbacks.Add(callback);
return this;
}
public AsyncReply Chunk(Action<object> callback)
{
chunkCallbacks.Add(callback);
return this;
}
public void Trigger(object result)
{
lock (callbacksLock)
{
if (resultReady)
return;
this.result = result;
resultReady = true;
foreach (var cb in callbacks)
cb(result);
tcs.TrySetResult(result);
}
}
public void TriggerError(AsyncException exception)
{
if (resultReady)
return;
this.exception = exception;
lock (callbacksLock)
{
foreach (var cb in errorCallbacks)
cb(exception);
}
tcs.TrySetException(exception);
}
public void TriggerProgress(ProgressType type, int value, int max)
{
if (resultReady)
return;
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(value);
}
}
public Task Task
{
get
{
return tcs.Task;
}
}
public AsyncReply()
{
}
public AsyncReply(object result)
{
resultReady = true;
tcs.SetResult(result);
this.result = result;
}
}
}

12
Esiur/Core/ErrorType.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Core
{
public enum ErrorType
{
Management,
Exception
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Core
{
public enum ExceptionCode : ushort
{
HostNotReachable,
AccessDenied,
UserOrTokenNotFound,
ChallengeFailed,
ResourceNotFound,
AttachDenied,
InvalidMethod,
InvokeDenied,
CreateDenied,
AddParentDenied,
AddChildDenied,
ViewAttributeDenied,
UpdateAttributeDenied,
StoreNotFound,
ParentNotFound,
ChildNotFound,
ResourceIsNotStore,
DeleteDenied,
DeleteFailed,
UpdateAttributeFailed,
GetAttributesFailed,
ClearAttributesFailed,
TemplateNotFound,
RenameDenied,
ClassNotFound,
MethodNotFound,
PropertyNotFound,
SetPropertyDenied,
ReadOnlyProperty,
GeneralFailure,
}
}

21
Esiur/Core/IAsyncReply.cs Normal file
View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace Esiur.Core
{
public interface IAsyncReply<out T>//IAsyncEnumerator<T>
{
IAsyncReply<T> Then(Action<T> callback);
IAsyncReply<T> Error(Action<AsyncException> callback);
IAsyncReply<T> Progress(Action<ProgressType, int, int> callback);
IAsyncReply<T> Chunk(Action<T> callback);
void Trigger(object result);
void TriggerError(Exception exception);
void TriggerProgress(ProgressType type, int value, int max);
void TriggerChunk(object value);
T Wait();
}
}

View File

@ -0,0 +1,39 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public delegate void DestroyedEvent(object sender);
public interface IDestructible
{
event DestroyedEvent OnDestroy;
void Destroy();
}
}

40
Esiur/Core/LogType.cs Normal file
View File

@ -0,0 +1,40 @@

/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Core
{
public enum LogType
{
Debug,
Warning,
Error,
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Core
{
public enum ProgressType
{
Execution,
Network,
}
}

311
Esiur/Data/AutoList.cs Normal file
View File

@ -0,0 +1,311 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
{
public class AutoList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
{
private readonly object syncRoot = new object();
private List<T> list = new List<T>();
public delegate void Modified(ST sender, int index, T oldValue, T newValue);
public delegate void Added(ST sender, T value);
public delegate void Removed(ST sender, T value);
public delegate void Cleared(ST sender);
public event Modified OnModified;
public event Removed OnRemoved;
public event Cleared OnCleared;
public event Added OnAdd;
bool removableList;
public ST State { get; set; }
/*
IOrderedEnumerable<T> OrderBy<T, TK>(Func<T, TK> keySelector)
{
return list.OrderBy<T,TK>(keySelector);
}
*/
public void Sort()
{
list.Sort();
}
public void Sort(IComparer<T> comparer)
{
list.Sort(comparer);
}
public void Sort(Comparison<T> comparison)
{
list.Sort(comparison);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
public AutoList(ST state)
{
State = state;
#if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
public AutoList(ST state, T[] values)
{
State = state;
#if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif
AddRange(values);
}
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
{
get
{
return syncRoot;
}
}
/// <summary>
/// First item in the list
/// </summary>
public T First()
{
return list.First();
}
/// <summary>
/// Get an item at a specified index
/// </summary>
public T this[int index]
{
get
{
return list[index];
}
set
{
var oldValue = list[index];
if (removableList)
{
if (oldValue != null)
((IDestructible)oldValue).OnDestroy -= ItemDestroyed;
if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed;
}
lock (syncRoot)
list[index] = value;
OnModified?.Invoke(State, index, oldValue, value);
}
}
/// <summary>
/// Add item to the list
/// </summary>
public void Add(T value)
{
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed;
lock (syncRoot)
list.Add(value);
OnAdd?.Invoke(State, value);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
if (removableList)
foreach (IDestructible v in list)
if (v != null)
v.OnDestroy -= ItemDestroyed;
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(State);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
public bool Remove(T value)
{
if (!list.Contains(value))
return false;
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy -= ItemDestroyed;
lock (syncRoot)
list.Remove(value);
OnRemoved?.Invoke(State, value);
return true;
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => false;
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
public void CopyTo(Array array, int index)
{
lock (syncRoot)
(list as ICollection).CopyTo(array, index);
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (syncRoot)
list.CopyTo(array, arrayIndex);
}
//bool ICollection<T>.Remove(T item)
//{
// lock(syncRoot)
// return Remove(item);
//}
}
}

714
Esiur/Data/BinaryList.cs Normal file
View File

@ -0,0 +1,714 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using System.Reflection;
using Esiur.Core;
namespace Esiur.Data
{
/// <summary>
/// BinaryList holds a list of items to be converted to binary for storage and transmission
/// </summary>
public class BinaryList
{
private List<byte> list = new List<byte>();
/// <summary>
/// Create an instance of BinaryList
/// </summary>
public BinaryList()
{
}
/*
/// <summary>
/// Converts parameters to binary in same order
/// </summary>
/// <param name="values">Variables to convert</param>
public static byte[] ToBytes(params object[] values)
{
var list = new List<byte>();
foreach (var i in values)
{
if (i is byte)
list.Add((byte)i);
else
{
#if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });
#endif
if (mi != null)
{
var b = (byte[])mi.Invoke(null, new object[] { i });
list.AddRange(b);
}
}
}
return list.ToArray();
}
/// <summary>
/// Create a new instance of BinaryList
/// </summary>
/// <param name="values">Populate the list items</param>
public BinaryList(params object[] values)
{
AddRange(values);
}
/// <summary>
/// Add an array of items at the end of the list
/// </summary>
/// <param name="values">Array of items</param>
public void AddRange(object[] values)
{
foreach (var i in values)
{
if (i is byte)
list.Add((byte)i);
else
{
#if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });
#endif
if (mi != null)
{
var b = (byte[])mi.Invoke(null, new object[] {i});
list.AddRange(b);
}
}
}
}
/// <summary>
/// Add multiple items at the end of the list
/// </summary>
/// <param name="values">Parameters of items</param>
public void Append(params object[] values)
{
AddRange(values);
}
/// <summary>
/// Insert new items to the list at a specified index
/// </summary>
/// <param name="offset">Position in the list</param>
/// <param name="values">Items to insert</param>
public void Insert(int offset, params object[] values)
{
foreach (var i in values)
{
if (i is byte)
{
list.Insert(offset++, (byte)i);
}
else
{
#if NETSTANDARD
MethodInfo mi = typeof(DC).GetTypeInfo().GetMethod("ToBytes", new Type[] { i.GetType() });
#else
MethodInfo mi = typeof(DC).GetMethod("ToBytes", new Type[] { i.GetType() });
#endif
if (mi != null)
{
var b = (byte[])mi.Invoke(null, new object[] { i });
list.InsertRange(offset, b);
offset += b.Length;
}
}
}
}
/// <summary>
/// Number of the items in the list
/// </summary>
public int Length
{
get
{
return list.Count;
}
}
/*
public void Append(byte data)
{
list.Add(data);
}
public void Append(byte[] data)
{
list.AddRange(data);
}
public void Append(int data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(uint data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(float data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(short data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(ushort data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(double data)
{
list.AddRange(DC.ToBytes(data));
}
public void Append(sbyte data)
{
list.Add((byte)data);
}
*/
public int Length => list.Count;
public BinaryList AddDateTime(DateTime value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertDateTime(int position, DateTime value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddDateTimeArray(DateTime[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertDateTimeArray(int position, DateTime[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddGuid(Guid value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertGuid(int position, Guid value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddGuidArray(Guid[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertGuidArray(int position, Guid[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt8Array(byte[] value)
{
list.AddRange(value);
return this;
}
public BinaryList InsertUInt8Array(int position, byte[] value)
{
list.InsertRange(position, value);
return this;
}
public BinaryList AddHex(string value)
{
return this.AddUInt8Array(DC.FromHex(value, null));
}
public BinaryList InsertHex(int position, string value)
{
return this.InsertUInt8Array(position, DC.FromHex(value, null));
}
public BinaryList AddString(string value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertString(int position, string value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddStringArray(string[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertStringArray(int position, string[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt8(int position, byte value)
{
list.Insert(position, value);
return this;
}
public BinaryList AddUInt8(byte value)
{
list.Add(value);
return this;
}
public BinaryList AddInt8(sbyte value)
{
list.Add((byte)value);
return this;
}
public BinaryList InsertInt8(int position, sbyte value)
{
list.Insert(position, (byte)value);
return this;
}
public BinaryList AddInt8Array(sbyte[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt8Array(int position, sbyte[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddChar(char value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertChar(int position, char value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddCharArray(char[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertCharArray(int position, char[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddBoolean(bool value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertBoolean(int position, bool value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddBooleanArray(bool[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertBooleanArray(int position, bool[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt16(ushort value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt16(int position, ushort value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt16Array(ushort[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt16Array(int position, ushort[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt16(short value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt16(int position, short value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt16Array(short[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt16Array(int position, short[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt32(uint value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt32(int position, uint value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt32Array(uint[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt32Array(int position, uint[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt32(int value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt32(int position, int value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt32Array(int[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt32Array(int position, int[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt64(ulong value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt64(int position, ulong value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddUInt64Array(ulong[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertUInt64Array(int position, ulong[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt64(long value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt64(int position, long value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddInt64Array(long[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertInt64Array(int position, long[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddFloat32(float value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertFloat32(int position, float value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddFloat32Array(float[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertFloat32Array(int position, float[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddFloat64(double value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertFloat64(int position, double value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList AddFloat64Array(double[] value)
{
list.AddRange(DC.ToBytes(value));
return this;
}
public BinaryList InsertFloat64Array(int position, double[] value)
{
list.InsertRange(position, DC.ToBytes(value));
return this;
}
public BinaryList Add(DataType type, object value)
{
switch (type)
{
case DataType.Bool:
AddBoolean((bool)value);
return this;
case DataType.BoolArray:
AddBooleanArray((bool[])value);
return this;
case DataType.UInt8:
AddUInt8((byte)value);
return this;
case DataType.UInt8Array:
AddUInt8Array((byte[])value);
return this;
case DataType.Int8:
AddInt8((sbyte)value);
return this;
case DataType.Int8Array:
AddInt8Array((sbyte[])value);
return this;
case DataType.Char:
AddChar((char)value);
return this;
case DataType.CharArray:
AddCharArray((char[])value);
return this;
case DataType.UInt16:
AddUInt16((ushort)value);
return this;
case DataType.UInt16Array:
AddUInt16Array((ushort[])value);
return this;
case DataType.Int16:
AddInt16((short)value);
return this;
case DataType.Int16Array:
AddInt16Array((short[])value);
return this;
case DataType.UInt32:
AddUInt32((uint)value);
return this;
case DataType.UInt32Array:
AddUInt32Array((uint[])value);
return this;
case DataType.Int32:
AddInt32((int)value);
return this;
case DataType.Int32Array:
AddInt32Array((int[])value);
return this;
case DataType.UInt64:
AddUInt64((ulong)value);
return this;
case DataType.UInt64Array:
AddUInt64Array((ulong[])value);
return this;
case DataType.Int64:
AddInt64((long)value);
return this;
case DataType.Int64Array:
AddInt64Array((long[])value);
return this;
case DataType.Float32:
AddFloat32((float)value);
return this;
case DataType.Float32Array:
AddFloat32Array((float[])value);
return this;
case DataType.Float64:
AddFloat64((double)value);
return this;
case DataType.Float64Array:
AddFloat64Array((double[])value);
return this;
case DataType.String:
AddString((string)value);
return this;
case DataType.StringArray:
AddStringArray((string[])value);
return this;
case DataType.DateTime:
AddDateTime((DateTime)value);
return this;
case DataType.DateTimeArray:
AddDateTimeArray((DateTime[])value);
return this;
default:
throw new Exception("Not Implemented " + type.ToString());
//return this;
}
}
/// <summary>
/// Convert the list to an array of bytes
/// </summary>
/// <returns>Bytes array</returns>
public byte[] ToArray()
{
return list.ToArray();
}
public virtual AsyncReply<object[]> Done()
{
return null;
//
}
}
}

1297
Esiur/Data/Codec.cs Normal file

File diff suppressed because it is too large Load Diff

985
Esiur/Data/DataConverter.cs Normal file
View File

@ -0,0 +1,985 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Net.IIP;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Data
{
public static class DC // Data Converter
{
public static object CastConvert(object value, Type destinationType)
{
if (value == null)
return null;
var sourceType = value.GetType();
if (destinationType == sourceType)
{
return value;
}
else
{
if (sourceType.IsArray && (destinationType.IsArray || destinationType == typeof(object)))
{
destinationType = destinationType.GetElementType();
var v = value as Array;
var rt = Array.CreateInstance(destinationType, v.Length);
for (var i = 0; i < rt.Length; i++)
{
rt.SetValue(CastConvert(v.GetValue(i), destinationType), i);
}
return rt;
}
else
{
try
{
var underType = Nullable.GetUnderlyingType(destinationType);
if (underType != null)
{
if (value == null)
return null;
else
destinationType = underType;
}
if (destinationType.IsInstanceOfType(value))
{
return value;
}
else if (typeof(IUserType).IsAssignableFrom(destinationType))
{
var rt = Activator.CreateInstance(destinationType) as IUserType;
rt.Set(value);
return rt;
}
else if (sourceType == typeof(Structure) && sourceType.IsAssignableFrom(destinationType))
{
return Structure.FromStructure((Structure)value, destinationType);
}
else if (destinationType.IsEnum)
{
return Enum.ToObject(destinationType, value);
}
else
{
return Convert.ChangeType(value, destinationType);
}
}
catch
{
return null;
}
}
}
}
public static byte[] ToBytes(sbyte value)
{
return new byte[1] { (byte)value };
}
public static byte[] ToBytes(byte value)
{
return new byte[1] { value };
}
public static byte[] ToBytes(IPAddress ip)
{
return ip.GetAddressBytes();
}
public static byte[] ToBytes(PhysicalAddress mac)
{
return mac.GetAddressBytes();
}
public static byte[] ToBytes(bool value)
{
return new byte[1] { value ? (byte)1 : (byte)0 };
}
public static byte ToByte(bool value)
{
return value ? (byte)1 : (byte)0;
}
public static byte ToByte(sbyte value)
{
return (byte)value;
}
public static byte[] ToBytes(byte[] value)
{
return value;
}
public static byte[] ToBytes(bool[] value)
{
byte[] ba = new byte[value.Length];
for (int i = 0; i < ba.Length; i++)
ba[i] = DC.ToByte(value[i]);
return ba;
}
public static byte[] ToBytes(sbyte[] value)
{
byte[] ba = new byte[value.Length];
for (int i = 0; i < ba.Length; i++)
ba[i] = DC.ToByte(value[i]);
return ba;
}
public static byte[] ToBytes(char value)
{
byte[] ret = BitConverter.GetBytes(value);
Array.Reverse(ret);
return ret;
}
public static byte[] ToBytes(Guid value)
{
return value.ToByteArray();
}
public static byte[] ToBytes(Guid[] value)
{
var rt = new List<byte>();
foreach (var g in value)
rt.AddRange(g.ToByteArray());
return rt.ToArray();
}
public static byte[] ToBytes(char[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(short[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(ushort[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static void Append(ref byte[] dst, byte[] src)
{
Append(ref dst, src, (uint)0, (uint)src.Length);
}
public static void Append(ref byte[] dst, byte[] src, uint srcOffset, uint length)
{
var dstOffset = dst.Length;
Array.Resize<byte>(ref dst, dstOffset + (int)length);
Buffer.BlockCopy(src, (int)srcOffset, dst, dstOffset, (int)length);
}
public static byte[] Combine(byte[] src1, uint src1Offset, uint src1Length, byte[] src2, uint src2Offset, uint src2Length)
{
var rt = new byte[src1Length + src2Length];
Buffer.BlockCopy(src1, (int)src1Offset, rt, 0, (int)src1Length);
Buffer.BlockCopy(src2, (int)src2Offset, rt, (int)src1Length, (int)src2Length);
return rt;
}
public static byte[] Merge(params byte[][] arrays)
{
var s = arrays.Sum(x => x.Length);
var r = new byte[s];
var offset = 0;
foreach (var array in arrays)
{
Buffer.BlockCopy(array, 0, r, offset, array.Length);
offset += array.Length;
}
return r;
}
public static byte[] ToBytes(this int[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this uint[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this long[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this ulong[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this float[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this double[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this decimal[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this DateTime[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
rt.AddRange(ToBytes(value[i]));
return rt.ToArray();
}
public static byte[] ToBytes(this string[] value)
{
List<byte> rt = new List<byte>();
for (int i = 0; i < value.Length; i++)
{
byte[] ba = ToBytes(value[i]);
// add string length
rt.AddRange(ToBytes(ba.Length));
// add encoded string
rt.AddRange(ba);
}
return rt.ToArray();
}
public static unsafe byte[] ToBytes(this int value)
{
var rt = new byte[4];
byte* p = (byte*)&value;
rt[0] = *(p + 3);
rt[1] = *(p + 2);
rt[2] = *(p + 1);
rt[3] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this short value)
{
var rt = new byte[2];
byte* p = (byte*)&value;
rt[0] = *(p + 1);
rt[1] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this float value)
{
var rt = new byte[4];
//float rt = 0;
byte* p = (byte*)&value;
rt[0] = *(p + 3);
rt[1] = *(p + 2);
rt[2] = *(p + 1);
rt[3] = *(p);
return rt;
}
public static byte[] ToBytes(this string value)
{
return Encoding.UTF8.GetBytes(value);
}
public unsafe static byte[] ToBytes(this double value)
{
var rt = new byte[8];
byte* p = (byte*)&value;
rt[0] = *(p + 7);
rt[1] = *(p + 6);
rt[2] = *(p + 5);
rt[3] = *(p + 4);
rt[4] = *(p + 3);
rt[5] = *(p + 2);
rt[6] = *(p + 1);
rt[7] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this long value)
{
var rt = new byte[8];
byte* p = (byte*)&value;
rt[0] = *(p + 7);
rt[1] = *(p + 6);
rt[2] = *(p + 5);
rt[3] = *(p + 4);
rt[4] = *(p + 3);
rt[5] = *(p + 2);
rt[6] = *(p + 1);
rt[7] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this DateTime value)
{
var rt = new byte[8];
var v = value.ToUniversalTime().Ticks;
byte* p = (byte*)&v;
rt[0] = *(p + 7);
rt[1] = *(p + 6);
rt[2] = *(p + 5);
rt[3] = *(p + 4);
rt[4] = *(p + 3);
rt[5] = *(p + 2);
rt[6] = *(p + 1);
rt[7] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this ulong value)
{
var rt = new byte[8];
byte* p = (byte*)&value;
rt[0] = *(p + 7);
rt[1] = *(p + 6);
rt[2] = *(p + 5);
rt[3] = *(p + 4);
rt[4] = *(p + 3);
rt[5] = *(p + 2);
rt[6] = *(p + 1);
rt[7] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this uint value)
{
var rt = new byte[4];
byte* p = (byte*)&value;
rt[0] = *(p + 3);
rt[1] = *(p + 2);
rt[2] = *(p + 1);
rt[3] = *(p + 0);
return rt;
}
public static unsafe byte[] ToBytes(this ushort value)
{
var rt = new byte[2];
byte* p = (byte*)&value;
rt[0] = *(p + 1);
rt[1] = *(p);
return rt;
}
public static byte[] ToBytes(this decimal value)
{
byte[] ret = new byte[0];// BitConverter.GetBytes(value);
Array.Reverse(ret);
return ret;
}
public static string ToHex(this byte[] ba)
{
if (ba == null)
return "NULL";
return ToHex(ba, 0, (uint)ba.Length);
}
public static string ToHex(this byte[] ba, uint offset, uint length, string separator = " ")
{
StringBuilder hex = new StringBuilder((int)length * 2);
for (var i = offset; i < offset + length; i++)
{
hex.AppendFormat("{0:x2}", ba[i]);
if (separator != null)
hex.Append(separator);
}
return hex.ToString();
}
public static byte[] FromHex(string hexString, string separator = " ")
{
var rt = new List<byte>();
if (separator == null)
{
for (var i = 0; i < hexString.Length; i += 2)
rt.Add(Convert.ToByte(hexString.Substring(i, 2), 16));
}
else
{
var hexes = hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
foreach (var h in hexes)
rt.Add(Convert.ToByte(h, 16));
}
return rt.ToArray();
}
public static string FlagsEnumToString<T>(ulong value)
{
string rt = typeof(T).Name + ":";
for (int i = 0; i < 64; i++)
{
ulong bit = (ulong)(Convert.ToUInt64(Math.Pow(2, i)) & value);
if (bit != 0)
{
rt += " " + Enum.GetName(typeof(T), bit);
}
}
return rt;
}
public static bool TryParse<T>(object Input, out T Results)
{
try
{
#if NETSTANDARD
var tryParse = typeof(T).GetTypeInfo().GetDeclaredMethod("TryParse");
if ((bool)tryParse.Invoke(null, new object[] { Input, null }))
{
var parse = typeof(T).GetTypeInfo().GetDeclaredMethod("Parse");
Results = (T)parse.Invoke(null, new object[] { Input });
return true;
}
#else
if ((bool)typeof(T).InvokeMember("TryParse", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { Input, null }))
{
Results = (T)typeof(T).InvokeMember("Parse", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { Input });
return true;
}
#endif
else
{
Results = default(T);
return false;
}
}
catch //Exception ex)
{
Results = default(T);
return false;
}
}
public static DateTime FromUnixTime(uint seconds)
{
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((double)seconds);
}
public static DateTime FromUnixTime(ulong milliseconds)
{
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((double)milliseconds);
}
public static sbyte GetInt8(this byte[] data, uint offset)
{
return (sbyte)data[offset];
}
public static sbyte[] GetInt8Array(this byte[] data, uint offset, uint length)
{
var rt = new sbyte[length];
Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length);
return rt;
}
public static byte GetUInt8(this byte[] data, uint offset)
{
return data[offset];
}
public static byte[] GetUInt8Array(this byte[] data, uint offset, uint length)
{
var rt = new byte[length];
Buffer.BlockCopy(data, (int)offset, rt, 0, (int)length);
return rt;
}
public static Int16 GetInt16(this byte[] data, uint offset)
{
return (Int16)((data[offset] << 8) | data[offset + 1]);
}
public static Int16[] GetInt16Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new Int16[length / 2];
for (var i = offset; i < end; i += 2)
rt[j++] = GetInt16(data, i);
return rt;
}
public static UInt16 GetUInt16(this byte[] data, uint offset)
{
return (UInt16)((data[offset] << 8) | data[offset + 1]);
}
public static UInt16[] GetUInt16Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new UInt16[length / 2];
for (var i = offset; i < end; i += 2)
rt[j++] = GetUInt16(data, i);
return rt;
}
public static Int32 GetInt32(this byte[] data, uint offset)
{
return (Int32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]);
}
public static Int32[] GetInt32Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new Int32[length / 4];
for (var i = offset; i < end; i += 4)
rt[j++] = GetInt32(data, i);
return rt;
}
public static UInt32 GetUInt32(this byte[] data, uint offset)
{
return (UInt32)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]);
}
public static UInt32[] GetUInt32Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new UInt32[length / 4];
for (var i = offset; i < end; i += 4)
rt[j++] = GetUInt16(data, i);
return rt;
}
public static unsafe UInt64 GetUInt64(this byte[] data, uint offset)
{
UInt64 rt = 0;
byte* p = (byte*)&rt;
*(p + 7) = data[offset++];
*(p + 6) = data[offset++];
*(p + 5) = data[offset++];
*(p + 4) = data[offset++];
*(p + 3) = data[offset++];
*(p + 2) = data[offset++];
*(p + 1) = data[offset++];
*(p) = data[offset++];
return rt;
}
public static Int64[] GetInt64Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new Int64[length / 8];
for (var i = offset; i < end; i += 8)
rt[j++] = GetInt64(data, i);
return rt;
}
public static unsafe Int64 GetInt64(this byte[] data, uint offset)
{
Int64 rt = 0;
byte* p = (byte*)&rt;
*(p + 7) = data[offset++];
*(p + 6) = data[offset++];
*(p + 5) = data[offset++];
*(p + 4) = data[offset++];
*(p + 3) = data[offset++];
*(p + 2) = data[offset++];
*(p + 1) = data[offset++];
*(p) = data[offset++];
return rt;
/* Or
return (Int64)(
(data[offset] << 56)
| (data[offset + 1] << 48)
| (data[offset + 2] << 40)
| (data[offset + 3] << 32)
| (data[offset + 4] << 24)
| (data[offset + 5] << 16)
| (data[offset + 6] << 8)
| (data[offset + 7])
);
*/
}
public static UInt64[] GetUInt64Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new UInt64[length / 8];
for (var i = offset; i < end; i += 8)
rt[j++] = GetUInt64(data, i);
return rt;
}
public static unsafe float GetFloat32(this byte[] data, uint offset)
{
float rt = 0;
byte* p = (byte*)&rt;
*p = data[offset + 3];
*(p + 1) = data[offset + 2];
*(p + 2) = data[offset + 1];
*(p + 3) = data[offset];
return rt;
}
public static float[] GetFloat32Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new float[length / 4];
for (var i = offset; i < end; i += 4)
rt[j++] = GetFloat32(data, i);
return rt;
}
public static unsafe double GetFloat64(this byte[] data, uint offset)
{
double rt = 0;
byte* p = (byte*)&rt;
*(p + 7) = data[offset++];
*(p + 6) = data[offset++];
*(p + 5) = data[offset++];
*(p + 4) = data[offset++];
*(p + 3) = data[offset++];
*(p + 2) = data[offset++];
*(p + 1) = data[offset++];
*(p) = data[offset++];
return rt;
}
public static double[] GetFloat64Array(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new double[length / 8];
for (var i = offset; i < end; i += 8)
rt[j++] = GetFloat64(data, i);
return rt;
}
public static bool GetBoolean(this byte[] data, uint offset)
{
return data[offset] > 0;
}
public static bool[] GetBooleanArray(this byte[] data, uint offset, uint length)
{
var rt = new bool[length];
for (var i = 0; i < length; i++)
rt[i] = data[offset + i] > 0;
return rt;
}
public static char GetChar(this byte[] data, uint offset)
{
return Convert.ToChar(((data[offset] << 8) | data[offset + 1]));
}
public static char[] GetCharArray(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new char[length / 2];
for (var i = offset; i < end; i += 2)
rt[j++] = GetChar(data, i);
return rt;
}
public static string GetString(this byte[] data, uint offset, uint length)
{
return Encoding.UTF8.GetString(data, (int)offset, (int)length);
}
public static string[] GetStringArray(this byte[] data, uint offset, uint length)
{
List<string> ar = new List<string>();
uint i = 0;
while (i < length)
{
var cl = GetUInt32(data, offset + i);
i += 4;
ar.Add(Encoding.UTF8.GetString(data, (int)(offset + i), (int)cl));
i += cl;
}
return ar.ToArray();
}
public static Guid GetGuid(this byte[] data, uint offset)
{
return new Guid(Clip(data, offset, 16));
}
public static Guid[] GetGuidArray(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new Guid[length / 16];
for (var i = offset; i < end; i += 16)
rt[j++] = GetGuid(data, i);
return rt;
}
public static DateTime GetDateTime(this byte[] data, uint offset)
{
var ticks = GetInt64(data, offset);
return new DateTime(ticks, DateTimeKind.Utc);
}
public static DateTime[] GetDateTimeArray(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new DateTime[length / 8];
for (var i = offset; i < end; i += 8)
rt[j++] = GetDateTime(data, i);
return rt;
}
public static IPAddress GetIPv4Address(this byte[] data, uint offset)
{
return new IPAddress((long)GetUInt32(data, offset));
}
public static IPAddress[] GetIPv4AddressArray(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new IPAddress[length / 4];
for (var i = offset; i < end; i += 4)
rt[j++] = GetIPv6Address(data, i);
return rt;
}
public static IPAddress GetIPv6Address(this byte[] data, uint offset)
{
return new IPAddress(Clip(data, offset, 16));
}
public static IPAddress[] GetIPv6AddressArray(this byte[] data, uint offset, uint length)
{
var j = 0; var end = offset + length;
var rt = new IPAddress[length / 16];
for (var i = offset; i < end; i += 16)
rt[j++] = GetIPv6Address(data, i);
return rt;
}
public static byte[] Clip(this byte[] data, uint offset, uint length)
{
if (data.Length < offset + length)
return null;
// if (length == data.Length && offset == 0)
// return data.ToArray();
var b = new byte[length];
Buffer.BlockCopy(data, (int)offset, b, 0, (int)length);
return b;
}
public static string ToISODateTime(this DateTime date)
{
return date.ToString("yyyy-MM-dd HH:mm:ss");
}
public static uint ToUnixTime(this DateTime date)
{
return (uint)(date - new DateTime(1970, 1, 1)).TotalSeconds;
}
}
}

119
Esiur/Data/DataType.cs Normal file
View File

@ -0,0 +1,119 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Data
{
public enum DataType : byte
{
Void = 0x0,
//Variant,
Bool,
Int8,
UInt8,
Char,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float32,
Float64,
Decimal,
DateTime,
Resource,
DistributedResource,
ResourceLink,
String,
Structure,
//Stream,
//Array = 0x80,
VarArray = 0x80,
BoolArray,
Int8Array,
UInt8Array,
CharArray,
Int16Array,
UInt16Array,
Int32Array,
UInt32Array,
Int64Array,
UInt64Array,
Float32Array,
Float64Array,
DecimalArray,
DateTimeArray,
ResourceArray,
DistributedResourceArray,
ResourceLinkArray,
StringArray,
StructureArray,
NotModified = 0x7f,
Unspecified = 0xff,
}
public static class DataTypeExpansions
{
public static int Size(this DataType t)
{
switch (t)
{
case DataType.Void:
case DataType.NotModified:
return 0;
case DataType.Bool:
case DataType.UInt8:
case DataType.Int8:
return 1;
case DataType.Char:
case DataType.UInt16:
case DataType.Int16:
return 2;
case DataType.Int32:
case DataType.UInt32:
case DataType.Float32:
case DataType.Resource:
return 4;
case DataType.Int64:
case DataType.UInt64:
case DataType.Float64:
case DataType.DateTime:
return 8;
case DataType.DistributedResource:
return 4;
default:
return -1;
}
}
}
}

12
Esiur/Data/IUserType.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public interface IUserType
{
object Get();
void Set(object value);
}
}

244
Esiur/Data/KeyList.cs Normal file
View File

@ -0,0 +1,244 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.IO;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Esiur.Core;
namespace Esiur.Data
{
public class KeyList<KT, T> : IEnumerable<KeyValuePair<KT, T>>
{
private readonly object syncRoot = new object();
private Dictionary<KT, T> dic;
public delegate void Modified(KT key, T oldValue, T newValue, KeyList<KT, T> sender);
public delegate void Added(T value, KeyList<KT, T> sender);
public delegate void Removed(KT key, T value, KeyList<KT, T> sender);
public delegate void Cleared(KeyList<KT, T> sender);
public event Modified OnModified;
public event Removed OnRemoved;
public event Cleared OnCleared;
public event Added OnAdd;
bool removableList;
public object SyncRoot
{
get
{
return syncRoot;
}
}
public T Take(KT key)
{
if (dic.ContainsKey(key))
{
var v = dic[key];
Remove(key);
return v;
}
else
return default(T);
}
public void Sort(Func<KeyValuePair<KT, T>, object> keySelector)
{
dic = dic.OrderBy(keySelector).ToDictionary(x => x.Key, x => x.Value);
}
public T[] ToArray()
{
var a = new T[Count];
dic.Values.CopyTo(a, 0);
return a;
}
public void Add(KT key, T value)
{
lock (syncRoot)
{
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy += ItemDestroyed;
if (dic.ContainsKey(key))
{
var oldValue = dic[key];
if (removableList)
if (oldValue != null)
((IDestructible)oldValue).OnDestroy -= ItemDestroyed;
dic[key] = value;
if (OnModified != null)
OnModified(key, oldValue, value, this);
}
else
{
dic.Add(key, value);
if (OnAdd != null)
OnAdd(value, this);
}
}
}
private void ItemDestroyed(object sender)
{
RemoveValue((T)sender);
}
public void RemoveValue(T value)
{
var toRemove = new List<KT>();
foreach (var kv in dic)
if (kv.Value.Equals(value))
toRemove.Add(kv.Key);
foreach (var k in toRemove)
Remove(k);
}
public T this[KT key]
{
get
{
if (dic.ContainsKey(key))
return dic[key];
else
return default(T);
}
set
{
Add(key, value);
}
}
public IEnumerator<KeyValuePair<KT, T>> GetEnumerator()
{
return dic.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dic.GetEnumerator();
}
public void Clear()
{
if (removableList)
foreach (IDestructible v in dic.Values)
if (v != null)
v.OnDestroy -= ItemDestroyed;
lock (syncRoot)
dic.Clear();
if (OnCleared != null)
OnCleared(this);
}
public Dictionary<KT, T>.KeyCollection Keys
{
get { return dic.Keys; }
}
public Dictionary<KT, T>.ValueCollection Values
{
get
{
return dic.Values;
}
}
public void Remove(KT key)
{
if (!dic.ContainsKey(key))
return;
var value = dic[key];
if (removableList)
if (value != null)
((IDestructible)value).OnDestroy -= ItemDestroyed;
lock (syncRoot)
dic.Remove(key);
if (OnRemoved != null)
OnRemoved(key, value, this);
}
public object Owner
{
get;
set;
}
public int Count
{
get { return dic.Count; }
}
public bool Contains(KT Key)
{
return dic.ContainsKey(Key);
}
public bool ContainsKey(KT Key)
{
return dic.ContainsKey(Key);
}
public bool ContainsValue(T Value)
{
return dic.ContainsValue(Value);
}
public KeyList(object owner = null)
{
#if NETSTANDARD
removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()));
#else
removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T)));
#endif
this.Owner = owner;
if (typeof(KT) == typeof(string))
dic = (Dictionary<KT, T>)(object)new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
else
dic = new Dictionary<KT, T>();
}
}
}

37
Esiur/Data/NotModified.cs Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Data
{
public class NotModified
{
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public class PropertyValue
{
/// <summary>
/// Get or set the value.
/// </summary>
public object Value { get; set; }
/// <summary>
/// Get or set date of modification or occurrence.
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Get or set property age.
/// </summary>
public ulong Age { get; set; }
/// <summary>
/// Create an instance of PropertyValue.
/// </summary>
/// <param name="value">Value.</param>
/// <param name="age">Age.</param>
/// <param name="date">Date.</param>
public PropertyValue(object value, ulong age, DateTime date)
{
Value = value;
Age = age;
Date = date;
}
}
}

274
Esiur/Data/ResourceList.cs Normal file
View File

@ -0,0 +1,274 @@
/*
Copyright (c) 2020 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.Linq;
using System.Text;
using System.Collections;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
{
public class ResourceList<T, ST> : IEnumerable<T>, ICollection, ICollection<T>
{
private readonly object syncRoot = new object();
private List<T> list = new List<T>();
public delegate void Modified(ST sender, int index, T oldValue, T newValue);
public delegate void Added(ST sender, T value);
public delegate void Removed(ST sender, int index, T value);
public delegate void Cleared(ST sender);
public event Modified OnModified;
public event Removed OnRemoved;
public event Cleared OnCleared;
public event Added OnAdd;
ST state;
public void Sort()
{
list.Sort();
}
public void Sort(IComparer<T> comparer)
{
list.Sort(comparer);
}
public void Sort(Comparison<T> comparison)
{
list.Sort(comparison);
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return list.Where(predicate);
}
/// <summary>
/// Convert AutoList to array
/// </summary>
/// <returns>Array</returns>
public T[] ToArray()
{
// list.OrderBy()
return list.ToArray();
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="state">State object to be included when an event is raised.</param>
public ResourceList(ST state)
{
this.state = state;
}
/// <summary>
/// Create a new instance of AutoList
/// </summary>
/// <param name="values">Populate the list with items</param>
/// <returns></returns>
public ResourceList(ST state, T[] values)
{
this.state = state;
AddRange(values);
}
/// <summary>
/// Synchronization lock of the list
/// </summary>
public object SyncRoot
{
get
{
return syncRoot;
}
}
/// <summary>
/// First item in the list
/// </summary>
public T First()
{
return list.First();
}
/// <summary>
/// Get an item at a specified index
/// </summary>
public T this[int index]
{
get
{
return list[index];
}
set
{
var oldValue = list[index];
lock (syncRoot)
list[index] = value;
OnModified?.Invoke(state, index, oldValue, value);
}
}
/// <summary>
/// Add item to the list
/// </summary>
public void Add(T value)
{
lock (syncRoot)
list.Add(value);
OnAdd?.Invoke(state, value);
}
/// <summary>
/// Add an array of items to the list
/// </summary>
public void AddRange(T[] values)
{
foreach (var v in values)
Add(v);
}
private void ItemDestroyed(object sender)
{
Remove((T)sender);
}
/// <summary>
/// Clear the list
/// </summary>
public void Clear()
{
lock (syncRoot)
list.Clear();
OnCleared?.Invoke(state);
}
/// <summary>
/// Remove an item from the list
/// <param name="value">Item to remove</param>
/// </summary>
public void Remove(T value)
{
var index = 0;
lock (syncRoot)
{
index = list.IndexOf(value);
if (index == -1)
return;
list.RemoveAt(index);
}
OnRemoved?.Invoke(state, index, value);
}
/// <summary>
/// Number of items in the list
/// </summary>
public int Count
{
get { return list.Count; }
}
public bool IsSynchronized => (list as ICollection).IsSynchronized;
public bool IsReadOnly => throw new NotImplementedException();
/// <summary>
/// Check if an item exists in the list
/// </summary>
/// <param name="value">Item to check if exists</param>
public bool Contains(T value)
{
return list.Contains(value);
}
/// <summary>
/// Check if any item of the given array is in the list
/// </summary>
/// <param name="values">Array of items</param>
public bool ContainsAny(T[] values)
{
foreach (var v in values)
if (list.Contains(v))
return true;
return false;
}
/// <summary>
/// Check if any item of the given list is in the list
/// </summary>
/// <param name="values">List of items</param>
public bool ContainsAny(AutoList<T, ST> values)
{
foreach (var v in values)
if (list.Contains((T)v))
return true;
return false;
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)list).GetEnumerator();
}
public void CopyTo(Array array, int index)
{
(list as ICollection).CopyTo(array, index);
}
public void CopyTo(T[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
bool ICollection<T>.Remove(T item)
{
return list.Remove(item);
}
}
}

220
Esiur/Data/StringKeyList.cs Normal file
View File

@ -0,0 +1,220 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using System.Linq;
namespace Esiur.Data
{
public class StringKeyList : IEnumerable<KeyValuePair<string, string>>
{
//private List<string> m_keys = new List<string>();
//private List<string> m_values = new List<string>();
private List<KeyValuePair<string, string>> m_Variables = new List<KeyValuePair<string, string>>();
private bool allowMultiple;
public delegate void Modified(string Key, string NewValue);
public event Modified OnModified;
public StringKeyList(bool AllowMultipleValues = false)
{
allowMultiple = AllowMultipleValues;
}
public void Add(string Key, string Value)
{
if (OnModified != null)
OnModified(Key, Value);
var key = Key.ToLower();
if (!allowMultiple)
{
foreach(var kv in m_Variables)
{
if (kv.Key.ToLower() == key)
{
m_Variables.Remove(kv);
break;
}
}
}
m_Variables.Add(new KeyValuePair<string, string>(Key, Value));
}
public string this[string Key]
{
get
{
var key = Key.ToLower();
foreach (var kv in m_Variables)
if (kv.Key.ToLower() == key)
return kv.Value;
return null;
}
set
{
var key = Key.ToLower();
var toRemove = m_Variables.Where(x => x.Key.ToLower() == key).ToArray();
foreach (var item in toRemove)
m_Variables.Remove(item);
m_Variables.Add(new KeyValuePair<string, string>(Key, value));
OnModified?.Invoke(Key, value);
}
}
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator()
{
//return m_keys.GetEnumerator();
return m_Variables.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return m_Variables.GetEnumerator();
}
public void Clear()
{
if (OnModified != null)
OnModified(null, null);
m_Variables.Clear();
}
/*
public string[] Keys
{
get
{
return m_keys.ToArray();
}
}
//public Dictionary<string, string>.ValueCollection Values
public string[] Values
{
get
{
//return m_Variables.Values;
return m_values.ToArray();
}
}
*/
public List<string> GetValues(string Key)
{
var key = Key.ToLower();
List<string> values = new List<string>();
foreach (var kv in m_Variables)
if (kv.Key.ToLower() == key)
values.Add(kv.Value);
return values;
}
public void RemoveAll(string Key)
{
while (Remove(Key)){}
}
public bool Remove(string Key)
{
var key = Key.ToLower();
foreach(var kv in m_Variables)
{
if (kv.Key.ToLower() == key)
{
if (OnModified != null)
OnModified(Key, null);
m_Variables.Remove(kv);
return true;
}
}
return false;
}
public int Count
{
get { return m_Variables.Count; }
}
public bool ContainsKey(string Key)
{
var key = Key.ToLower();
foreach (var kv in m_Variables)
if (kv.Key.ToLower() == key)
return true;
return false;
}
/*
public bool ContainsKey(string Key)
{
//return m_Variables.ContainsKey(Key);
return m_keys.Contains(Key.ToLower());
}
*/
public bool ContainsValue(string Value)
{
var value = Value.ToLower();
foreach (var kv in m_Variables)
if (kv.Value.ToLower() == value)
return true;
return false;
}
//internal KeyList()
//{
// m_Session = Session;
// m_Server = Server;
//}
}
}

166
Esiur/Data/Structure.cs Normal file
View File

@ -0,0 +1,166 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using System.Reflection;
namespace Esiur.Data
{
public class Structure : IEnumerable<KeyValuePair<string, object>>
{
public struct StructureMetadata
{
public string[] Keys;
public DataType[] Types;
}
private Dictionary<string, object> dic = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
private object syncRoot = new object();
public bool ContainsKey(string key)
{
return dic.ContainsKey(key);
}
public override string ToString()
{
var rt = "";
foreach (var kv in dic)
rt += kv.Key + ": " + kv.Value.ToString() + " \r\n";
return rt.TrimEnd('\r', '\n');
}
public Structure(Structure source)
{
dic = source.dic;
}
public Structure()
{
}
public static Structure FromStructure(Structure source, Type destinationType)
{
var rt = Activator.CreateInstance(destinationType) as Structure;
rt.dic = source.dic;
return rt;
}
public static T FromStructure<T>(Structure source) where T : Structure
{
var rt = Activator.CreateInstance<T>();
rt.dic = source.dic;
return rt;
}
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().Where(x=>x.CanRead);
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();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dic.GetEnumerator();
}
public int Length
{
get { return dic.Count; }
}
public KeyValuePair<string, object> At(int index)
{
return dic.ElementAt(index);
}
public object SyncRoot
{
get { return syncRoot; }
}
public string[] GetKeys() => dic.Keys.ToArray();//GetKeys()
//{
// return dic.Keys.ToArray();
//}
public Structure Add(string key, object value)
{
if (dic.ContainsKey(key))
dic[key] = value;
else
dic.Add(key, value);
return this;
}
public object this[string index]
{
get
{
if (dic.ContainsKey(index))
return dic[index];
else
return null;
}
set
{
if (dic.ContainsKey(index))
dic[index] = value;
else
dic.Add(index, value);
}
}
}
}

63
Esiur/Esiur.csproj Normal file
View File

@ -0,0 +1,63 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<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.5.0</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion>1.3.1.0</AssemblyVersion>
<Company>Esiur Foundation</Company>
<FileVersion>1.3.1.0</FileVersion>
<AssemblyName>Esiur</AssemblyName>
<RootNamespace>Esiur</RootNamespace>
<PackageId>Esiur</PackageId>
<Product>Esiur</Product>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Core\AsyncReplyNon.cs" />
<Compile Remove="Core\IAsyncReply.cs" />
<Compile Remove="Resource\ResourceEvent.cs" />
<Compile Remove="Resource\ResourceFunction.cs" />
<Compile Remove="Resource\ResourceProperty.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Net\DataLink\Sources\" />
<Folder Include="obj\" />
</ItemGroup>
<ItemGroup>
<None Include="Core\AsyncReplyNon.cs" />
<None Include="Core\IAsyncReply.cs" />
<None Include="Resource\ResourceEvent.cs" />
<None Include="Resource\ResourceFunction.cs" />
<None Include="Resource\ResourceProperty.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Diagnostics.StackTrace" Version="4.3.0" />
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
<PackageReference Include="System.Interactive.Async" Version="4.1.1" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>
</Project>

463
Esiur/Misc/Global.cs Normal file
View File

@ -0,0 +1,463 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.IO;
using System.Collections;
using System.Xml;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using Esiur.Data;
using System.Collections.Generic;
//using Esiur.Net.Packets;
using System.Text.RegularExpressions;
using System.Net.NetworkInformation;
using System.Linq;
using Esiur.Core;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Esiur.Misc
{
public static class Global
{
private static KeyList<string, object> variables = new KeyList<string, object>();
// private static Hashtable m_Cached = new Hashtable();
//internal static bool SystemIsWorking = false;
private static Random rand = new Random(System.Environment.TickCount);
//public static Encoding DefaultEncoding = Encoding.GetEncoding(1252);// .GetEncoding("windows-1252");
public static KeyList<string, long> Counters = new KeyList<string, long>();
public delegate void LogEvent(string service, LogType type, string message);
public static event LogEvent SystemLog;
public static string Version { get; }= FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
//FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
// string version = fvi.FileVersion;
/*
public static char GetDirectorySeparator()
{
return System.IO.Path.DirectorySeparatorChar;
}
*/
public static void Log(Exception ex, params object[] arguments)
{
try
{
var stack = new StackTrace(ex, true);
var frame = stack.GetFrames().First();
var method = frame.GetMethod();
var parameters = method.GetParameters();
var service = method.DeclaringType.Name;
var message = "";
if (arguments.Length > 0 && parameters.Length > 0)
{
message = "Arguments ( ";
for (int i = 0; i < parameters.Length && i < arguments.Length; i++)
{
message += parameters[i].Name + ": " + arguments[i].ToString() + " ";
}
message += ")" + Environment.NewLine + "------------------------------------------------";
}
message += ex.ToString();
Log(service, LogType.Error, message);
Log(service, LogType.Error, ex.ToString());
}
catch
{
}
}
public static void Log(string service, LogType type, string message, bool appendHeader = true)
{
//if (type != LogType.Debug)
Console.WriteLine(service + " " + message);
SystemLog?.Invoke(service, type, message);
}
/*
public static string GetTempPath()
{
return System.IO.Path.GetTempPath();
}
*/
public static string RemoveControlCharacters(string inString)
{
if (inString == null) return null;
StringBuilder newString = new StringBuilder();
char ch;
for (int i = 0; i < inString.Length; i++)
{
ch = inString[i];
if (!char.IsControl(ch))
{
newString.Append(ch);
}
}
return newString.ToString();
}
public static void PrintCounters()
{
string[] keys = new string[Counters.Keys.Count];
Counters.Keys.CopyTo(keys, 0);
foreach (string k in keys)
{
Console.WriteLine(k + ":" + Counters[k]);
}
}
// Encoding ANSI = Encoding.GetEncoding(1252);
/*
public static Hashtable Cached
{
get
{
return m_Cached;
}
}*/
/*
public static string ByteArrayToMAC(byte[] array)
{
string rt="";
if (array == null)
return "00:00:00:00:00:00";
else
{
//for (int i = 0; i < array.Length - 1; i++)
// rt += Convert.ToString(array[i], 16) + ":";
//rt += Convert.ToString(array[array.Length - 1], 16);
rt = BitConverter.ToString(array);
rt = rt.Replace('-', ':');
return rt;
}
}
*/
/*
public static string IPAddressFromInt32(UInt32 IP)
{
//var dIP = DC.ToBytes(IP);
return (IP >> 24) + "." + ((IP >> 16) & 0xFF) + "." + ((IP >> 8) & 0xFF) + "." + (IP & 0xFF);
}
*/
public static KeyList<string, object> Variables
{
get
{
return variables;
}
}
public static uint CurrentUnixTime()
{
return (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
}
public static void SetConsoleColors(ConsoleColor ForegroundColor, ConsoleColor BackgroundColor)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
switch (ForegroundColor)
{
case ConsoleColor.Black:
Console.Write("\u001B[30m");
break;
case ConsoleColor.Blue:
Console.Write("\u001B[1;34m");
break;
case ConsoleColor.Cyan:
Console.Write("\u001B[1;36m");
break;
case ConsoleColor.Gray:
case ConsoleColor.DarkGray:
Console.Write("\u001B[1;30m");
break;
case ConsoleColor.Green:
Console.Write("\u001B[1;32m");
break;
case ConsoleColor.Magenta:
Console.Write("\u001B[1;35m");
break;
case ConsoleColor.Red:
Console.Write("\u001B[1;31m");
break;
case ConsoleColor.White:
Console.Write("\u001B[1;37m");
break;
case ConsoleColor.Yellow:
Console.Write("\u001B[1;33m");
break;
case ConsoleColor.DarkBlue:
Console.Write("\u001B[34m");
break;
case ConsoleColor.DarkCyan:
Console.Write("\u001B[36m");
break;
case ConsoleColor.DarkGreen:
Console.Write("\u001B[32m");
break;
case ConsoleColor.DarkMagenta:
Console.Write("\u001B[35m");
break;
case ConsoleColor.DarkRed:
Console.Write("\u001B[31m");
break;
case ConsoleColor.DarkYellow:
Console.Write("\u001B[33m");
break;
}
switch (BackgroundColor)
{
case ConsoleColor.Black:
Console.Write("\u001B[40m");
break;
case ConsoleColor.Blue:
Console.Write("\u001B[1;44m");
break;
case ConsoleColor.Cyan:
Console.Write("\u001B[1;46m");
break;
case ConsoleColor.Gray:
case ConsoleColor.DarkGray:
Console.Write("\u001B[1;40m");
break;
case ConsoleColor.Green:
Console.Write("\u001B[1;42m");
break;
case ConsoleColor.Magenta:
Console.Write("\u001B[1;45m");
break;
case ConsoleColor.Red:
Console.Write("\u001B[1;41m");
break;
case ConsoleColor.White:
Console.Write("\u001B[1;47m");
break;
case ConsoleColor.Yellow:
Console.Write("\u001B[1;43m");
break;
case ConsoleColor.DarkBlue:
Console.Write("\u001B[44m");
break;
case ConsoleColor.DarkCyan:
Console.Write("\u001B[46m");
break;
case ConsoleColor.DarkGreen:
Console.Write("\u001B[42m");
break;
case ConsoleColor.DarkMagenta:
Console.Write("\u001B[45m");
break;
case ConsoleColor.DarkRed:
Console.Write("\u001B[41m");
break;
case ConsoleColor.DarkYellow:
Console.Write("\u001B[43m");
break;
}
}
else
{
Console.ForegroundColor = ForegroundColor;
Console.BackgroundColor = BackgroundColor;
}
}
public static string GetUserPart(string strAddress)
{
return strAddress.Substring(0, strAddress.IndexOf("@", 0));
}
public static byte[][] GetBytesFromChunk(byte[] Data, int ChunkSize)
{
if (ChunkSize == 1)
{
byte[][] ar = new byte[0][];
int ptr = 0;
while (ptr < Data.Length)
{
Array.Resize<byte[]>(ref ar, ar.Length + 1);
ar[ar.Length - 1] = new byte[Data[ptr]];
Buffer.BlockCopy(Data, ++ptr, ar[ar.Length - 1], 0, Data[ptr]);
ptr += Data[ptr] + 1;
}
return ar;
}
return null;
}
public static string GetFileTitle(string Filename)
{
string[] s = Filename.Split(Path.DirectorySeparatorChar);
return s[s.Length - 1];
}
public static string GetNewFileName(string FileDir)
{
string tempGetNewFileName = null;
short i = 0;
string NewFile = null;
NewFile = FileDir;
Begin:
FileInfo FF = new FileInfo(NewFile);
if (FF.Exists)
{
//If FSO.FileExists(NewFile) Then
i++; //= i + 1;
NewFile = FileDir.Substring(0, FileDir.Length - 4) + "_" + i + "." + FileDir.Substring(FileDir.Length - 3);
goto Begin;
}
else
{
tempGetNewFileName = NewFile;
}
return tempGetNewFileName;
}
/////////////////////////////////////
public static string TrimEx(string strIn)
{
return strIn.Replace("\r", "").Replace("\n", "");
}
/*
public static bool IsUnix()
{
// Linux OSs under Mono 1.2 uses unknown integer numbers so this should identify all non windows as unix
return (Environment.OSVersion.Platform != PlatformID.Win32NT
&& Environment.OSVersion.Platform != PlatformID.Win32Windows); // || Environment.OSVersion.Platform == PlatformID.Linux;
}
*/
public static string GenerateCode()
{
return GenerateCode(16);
}
public static byte[] GenerateBytes(int Length)
{
var b = new byte[Length];
rand.NextBytes(b);
return b;
}
public static string GenerateCode(int length)
{
return GenerateCode(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");// ~!@#$%^&*()_-+=\\?/");
}
public static string GenerateCode(int length, string chars)
//public static string GenerateCode(int Length)
{
//var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_-+=\\?/";
var result = new string(
Enumerable.Repeat(chars, length)
.Select(s => s[rand.Next(s.Length)])
.ToArray());
//if (result.Length < length)
// Console.WriteLine();
return result;
/*
int len = 0;
string code = "";
while(len < Length)
{
var c = Convert.ToChar((byte)(rand.NextDouble() * 255));
if (Char.IsLetterOrDigit(c))
{
code += c;
len++;
}
}
return code;
*/
}
public static string ReplaceOnce(string Expression, string Find, string Replacement)
{
int pos = Expression.IndexOf(Find);
if (pos != -1)
return Expression.Substring(0, pos) + Replacement + Expression.Substring(pos + Find.Length);
else
return Expression;
}
//public void Replace(string Expression, string Find, string Replacement, int Start, int Count)
//{
// Expression.IndexOf(
//}
}
}

View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Core;
using Esiur.Data;
using Esiur.Net.Packets;
using Esiur.Resource;
namespace Esiur.Net.DataLink
{
public abstract class PacketFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(Packet packet);
public void Destroy()
{
}
}
}

View File

@ -0,0 +1,123 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Core;
using Esiur.Data;
using System.Runtime.InteropServices;
using Esiur.Net.Packets;
using Esiur.Resource;
namespace Esiur.Net.DataLink
{
public class PacketServer:IResource
{
List<PacketSource> sources = new List<PacketSource>();
List<PacketFilter> filters = new List<PacketFilter>();
[Storable]
public string Mode
{
get;
set;
}
public Instance Instance
{
get;
set;
}
public List<PacketSource> Sources
{
get
{
return sources;
}
}
public event DestroyedEvent OnDestroy;
public void Destroy()
{
throw new NotImplementedException();
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
/*
foreach (var resource in Instance.Children<IResource>())
{
if (resource is PacketFilter)
{
filters.Add(resource as PacketFilter);
}
else if (resource is PacketSource)
{
sources.Add(resource as PacketSource);
}
}
*/
foreach (var src in sources)
{
src.OnNewPacket += PacketReceived;
src.Open();
}
}
else if (trigger == ResourceTrigger.Terminate)
{
// foreach (var src in sources)
// src.Close();
}
else if (trigger == ResourceTrigger.SystemReload)
{
foreach (var src in sources)
{
src.Close();
src.Open();
}
}
return new AsyncReply<bool>( true);
}
void PacketReceived(Packet Packet)
{
foreach (var f in filters)
{
if (f.Execute(Packet))
{
break;
}
}
}
}
}

View File

@ -0,0 +1,95 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Net.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.DataLink
{
public abstract class PacketSource: IResource
{
public delegate void NewPacket(Packet Packet);
public abstract event NewPacket OnNewPacket;
public event DestroyedEvent OnDestroy;
public Instance Instance
{
get;
set;
}
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool RawMode
{
set;
get;
}
//public PacketSource(PacketServer Server, bool RawMode)
//{
// this.RawMode = RawMode;
//}
public abstract bool Open();
public abstract bool Close();
public abstract bool Write(Packet packet);
public void Destroy()
{
throw new NotImplementedException();
}
/*
public virtual string TypeName
{
get
{
return "Raw";
}
}
*/
public abstract byte[] Address
{
get;
}
public abstract string DeviceId
{
get;
}
}
}

View File

@ -0,0 +1,437 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Net.Sockets;
using Esiur.Data;
using Esiur.Net.Packets;
using Esiur.Misc;
using System.Security.Cryptography;
using Esiur.Core;
namespace Esiur.Net.HTTP
{
public class HTTPConnection : NetworkConnection
{
public bool WSMode { get; internal set; }
public HTTPServer Server { get; internal set; }
public WebsocketPacket WSRequest { get; set; }
public HTTPRequestPacket Request { get; set; }
public HTTPResponsePacket Response { get; } = new HTTPResponsePacket();
HTTPSession session;
public KeyList<string, object> Variables { get; } = new KeyList<string, object>();
internal long Parse(byte[] data)
{
if (WSMode)
{
// now parse WS protocol
WebsocketPacket ws = new WebsocketPacket();
var pSize = ws.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
WSRequest = ws;
return 0;
}
else
{
return pSize;
}
}
else
{
var rp = new HTTPRequestPacket();
var pSize = rp.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
Request = rp;
return 0;
}
else
{
return pSize;
}
}
}
public void Flush()
{
// close the connection
if (Request.Headers["connection"].ToLower() != "keep-alive" & IsConnected)
Close();
}
public bool Upgrade()
{
if (IsWebsocketRequest())
{
string magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
string ret = Request.Headers["Sec-WebSocket-Key"] + magicString;
// Compute the SHA1 hash
SHA1 sha = SHA1.Create();
byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));
Response.Headers["Upgrade"] = Request.Headers["Upgrade"];
Response.Headers["Connection"] = Request.Headers["Connection"];// "Upgrade";
Response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash);
if (Request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
Response.Headers["Sec-WebSocket-Protocol"] = Request.Headers["Sec-WebSocket-Protocol"];
Response.Number = HTTPResponsePacket.ResponseCode.Switching;
Response.Text = "Switching Protocols";
WSMode = true;
Send();
return true;
}
return false;
}
public HTTPServer Parent
{
get
{
return Server;
}
}
public void Send(WebsocketPacket packet)
{
if (packet.Data != null)
base.Send(packet.Data);
}
public override void Send(string data)
{
Response.Message = Encoding.UTF8.GetBytes(data);
Send();
}
public override void Send(byte[] msg, int offset, int length)
{
Response.Message = DC.Clip(msg, (uint)offset, (uint)length);
Send();
}
public override void Send(byte[] message)
{
Response.Message = message;
Send();
}
public void Send(HTTPResponsePacket.ComposeOptions Options = HTTPResponsePacket.ComposeOptions.AllCalculateLength)
{
if (Response.Handled)
return;
try
{
Response.Compose(Options);
base.Send(Response.Data);
// Refresh the current session
if (session != null)
session.Refresh();
}
catch
{
try
{
Close();
}
finally { }
}
finally
{
}
}
public void CreateNewSession()
{
if (session == null)
{
// Create a new one
session = Server.CreateSession(Global.GenerateCode(12), 60 * 20);
HTTPResponsePacket.HTTPCookie cookie = new HTTPResponsePacket.HTTPCookie("SID", session.Id);
cookie.Expires = DateTime.MaxValue;
cookie.Path = "/";
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
}
public bool IsWebsocketRequest()
{
if (Request.Headers.ContainsKey("connection")
&& Request.Headers["connection"].ToLower().Contains("upgrade")
&& Request.Headers.ContainsKey("upgrade")
&& Request.Headers["upgrade"].ToLower() == "websocket"
&& Request.Headers.ContainsKey("Sec-WebSocket-Version")
&& Request.Headers["Sec-WebSocket-Version"] == "13"
&& Request.Headers.ContainsKey("Sec-WebSocket-Key"))
//&& Request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
{
return true;
}
else
{
return false;
}
}
protected override void DataReceived(NetworkBuffer data)
{
byte[] msg = data.Read();
var BL = Parse(msg);
if (BL == 0)
{
if (Request.Method == HTTPRequestPacket.HTTPMethod.UNKNOWN)
{
Close();
return;
}
if (Request.URL == "")
{
Close();
return;
}
}
else if (BL == -1)
{
data.HoldForNextWrite(msg);
return;
}
else if (BL < 0)
{
data.HoldFor(msg, (uint)(msg.Length - BL));
return;
}
else if (BL > 0)
{
if (BL > Server.MaxPost)
{
Send(
"<html><body>POST method content is larger than "
+ Server.MaxPost
+ " bytes.</body></html>");
Close();
}
else
{
data.HoldFor(msg, (uint)(msg.Length + BL));
}
return;
}
else if (BL < 0) // for security
{
Close();
return;
}
if (IsWebsocketRequest() & !WSMode)
{
Upgrade();
//return;
}
//return;
try
{
if (!Server.Execute(this))
{
Response.Number = HTTPResponsePacket.ResponseCode.InternalServerError;
Send("Bad Request");
Close();
}
}
catch (Exception ex)
{
if (ex.Message != "Thread was being aborted.")
{
Global.Log("HTTPServer", LogType.Error, ex.ToString());
//Console.WriteLine(ex.ToString());
//EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error);
Send(Error500(ex.Message));
}
}
}
private string Error500(string msg)
{
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";
}
public async AsyncReply<bool> SendFile(string filename)
{
if (Response.Handled == true)
return false;
try
{
//HTTP/1.1 200 OK
//Server: Microsoft-IIS/5.0
//Content-Location: http://127.0.0.1/index.html
//Date: Wed, 10 Dec 2003 19:10:25 GMT
//Content-Type: text/html
//Accept-Ranges: bytes
//Last-Modified: Mon, 22 Sep 2003 22:36:56 GMT
//Content-Length: 1957
if (!File.Exists(filename))
{
Response.Number = HTTPResponsePacket.ResponseCode.NotFound;
Send("File Not Found");
return true;
}
var fileEditTime = File.GetLastWriteTime(filename).ToUniversalTime();
if (Request.Headers.ContainsKey("if-modified-since"))
{
try
{
var ims = DateTime.Parse(Request.Headers["if-modified-since"]);
if ((fileEditTime - ims).TotalSeconds < 2)
{
Response.Number = HTTPResponsePacket.ResponseCode.NotModified;
Response.Headers.Clear();
//Response.Text = "Not Modified";
Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly);
return true;
}
}
catch
{
return false;
}
}
Response.Number = HTTPResponsePacket.ResponseCode.OK;
// Fri, 30 Oct 2007 14:19:41 GMT
Response.Headers["Last-Modified"] = fileEditTime.ToString("ddd, dd MMM yyyy HH:mm:ss");
FileInfo fi = new FileInfo(filename);
Response.Headers["Content-Length"] = fi.Length.ToString();
Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly);
//var fd = File.ReadAllBytes(filename);
//base.Send(fd);
using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var buffer = new byte[60000];
while (true)
{
var n = fs.Read(buffer, 0, 60000);
if (n <= 0)
break;
//Thread.Sleep(50);
await base.SendAsync(buffer, 0, n);
}
}
return true;
}
catch
{
try
{
Close();
}
finally {
}
return false;
}
}
protected override void Connected()
{
// do nothing
}
protected override void Disconencted()
{
// do nothing
}
}
}

View File

@ -0,0 +1,82 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.HTTP
{
public abstract class HTTPFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
/*
public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue)
{
}
public virtual void SessionExpired(HTTPSession session)
{
}
*/
public abstract AsyncReply<bool> Execute(HTTPConnection sender);
public virtual void ClientConnected(HTTPConnection HTTP)
{
//return false;
}
public virtual void ClientDisconnected(HTTPConnection HTTP)
{
//return false;
}
public void Destroy()
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,300 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Net.Sockets;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using Esiur.Net.Packets;
using System.Security.Cryptography.X509Certificates;
using Esiur.Resource;
namespace Esiur.Net.HTTP
{
public class HTTPServer : NetworkServer<HTTPConnection>, IResource
{
Dictionary<string, HTTPSession> sessions= new Dictionary<string, HTTPSession>();
HTTPFilter[] filters = new HTTPFilter[0];
public Instance Instance
{
get;
set;
}
[Attribute]
public virtual string IP
{
get;
set;
}
[Attribute]
public virtual ushort Port
{
get;
set;
}
//[Attribute]
//public virtual uint Timeout
//{
// get;
// set;
//}
//[Attribute]
//public virtual uint Clock
//{
// get;
// set;
//}
[Attribute]
public virtual uint MaxPost
{
get;
set;
}
[Attribute]
public virtual bool SSL
{
get;
set;
}
[Attribute]
public virtual string Certificate
{
get;
set;
}
public HTTPSession CreateSession(string id, int timeout)
{
var s = new HTTPSession();
s.Set(id, timeout);
sessions.Add(id, s);
return s;
}
public static string MakeCookie(string Item, string Value, DateTime Expires, string Domain, string Path, bool HttpOnly)
{
//Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/
//Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/
string Cookie = Item + "=" + Value;
if (Expires.Ticks != 0)
{
Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT";
}
if (Domain != null)
{
Cookie += "; domain=" + Domain;
}
if (Path != null)
{
Cookie += "; path=" + Path;
}
if (HttpOnly)
{
Cookie += "; HttpOnly";
}
return Cookie;
}
protected override void ClientDisconnected(HTTPConnection connection)
{
foreach (var filter in filters)
filter.ClientDisconnected(connection);
}
internal bool Execute(HTTPConnection sender)
{
foreach (var resource in filters)
if (resource.Execute(sender).Wait(30000))
return true;
return false;
}
/*
protected override void SessionEnded(NetworkSession session)
{
// verify wether there are no active connections related to the session
foreach (HTTPConnection c in Connections)//.Values)
{
if (c.Session == session)
{
session.Refresh();
return;
}
}
foreach (Instance instance in Instance.Children)
{
var f = (HTTPFilter)instance.Resource;
f.SessionExpired((HTTPSession)session);
}
base.SessionEnded((HTTPSession)session);
//Sessions.Remove(Session.ID);
//Session.Dispose();
}
*/
/*
public int TTL
{
get
{
return Timeout;// mTimeout;
}
}
*/
public async AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
//var ip = (IPAddress)Instance.Attributes["ip"];
//var port = (int)Instance.Attributes["port"];
//var ssl = (bool)Instance.Attributes["ssl"];
//var cert = (string)Instance.Attributes["certificate"];
//if (ip == null) ip = IPAddress.Any;
Sockets.ISocket listener;
IPAddress ipAdd;
if (IP == null)
ipAdd = IPAddress.Any;
else
ipAdd = IPAddress.Parse(IP);
if (SSL)
listener = new SSLSocket(new IPEndPoint(ipAdd, Port), new X509Certificate2(Certificate));
else
listener = new TCPSocket(new IPEndPoint(ipAdd, Port));
Start(listener);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
await Trigger(ResourceTrigger.Terminate);
await Trigger(ResourceTrigger.Initialize);
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
filters = await Instance.Children<HTTPFilter>();
}
return true;
}
public override void Add(HTTPConnection connection)
{
connection.Server = this;
base.Add(connection);
}
public override void Remove(HTTPConnection connection)
{
connection.Server = null;
base.Remove(connection);
}
protected override void ClientConnected(HTTPConnection connection)
{
if (filters.Length == 0)
{
connection.Close();
return;
}
foreach (var resource in filters)
{
resource.ClientConnected(connection);
}
}
/*
public int LocalPort
{
get
{
return cServer.LocalPort;
}
}
*/
/*
public HTTPServer(int Port)
{
cServer = new TServer();
cServer.LocalPort = Port;
cServer.StartServer();
cServer.ClientConnected += new TServer.eClientConnected(ClientConnected);
cServer.ClientDisConnected += new TServer.eClientDisConnected(ClientDisConnected);
cServer.ClientIsSwitching += new TServer.eClientIsSwitching(ClientIsSwitching);
cServer.DataReceived += new TServer.eDataReceived(DataReceived);
}*/
//~HTTPServer()
//{
// cServer.StopServer();
//}
}
}

View File

@ -0,0 +1,130 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
namespace Esiur.Net.HTTP
{
public class HTTPSession : IDestructible //<T> where T : TClient
{
public delegate void SessionModifiedEvent(HTTPSession session, string key, object oldValue, object newValue);
public delegate void SessionEndedEvent(HTTPSession session);
private string id;
private Timer timer;
private int timeout;
DateTime creation;
DateTime lastAction;
private KeyList<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{
get { return variables; }
}
public HTTPSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
internal void Set(string id, int timeout)
{
//modified = sessionModifiedEvent;
//ended = sessionEndEvent;
this.id = id;
if (this.timeout != 0)
{
this.timeout = timeout;
timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
creation = DateTime.Now;
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> sender)
{
OnModify?.Invoke(this, key, oldValue, newValue);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
timer.Dispose();
timer = null;
}
internal void Refresh()
{
lastAction = DateTime.Now;
timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
}
public int Timeout // Seconds
{
get
{
return timeout;
}
set
{
timeout = value;
Refresh();
}
}
public string Id
{
get { return id; }
}
public DateTime LastAction
{
get { return lastAction; }
}
}
}

View File

@ -0,0 +1,39 @@
using Esiur.Core;
using Esiur.Net.IIP;
using Esiur.Net.Packets;
using Esiur.Resource;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.HTTP
{
public class IIPoHTTP : HTTPFilter
{
[Attribute]
EntryPoint EntryPoint { get; set; }
public override AsyncReply<bool> Execute(HTTPConnection sender)
{
if (sender.Request.URL != "iip")
return new AsyncReply<bool>(false);
IIPPacket.IIPPacketAction action = (IIPPacket.IIPPacketAction)Convert.ToByte(sender.Request.Query["a"]);
if (action == IIPPacket.IIPPacketAction.QueryLink)
{
EntryPoint.Query(sender.Request.Query["l"], null).Then(x =>
{
});
}
return new AsyncReply<bool>(true);
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}
}

125
Esiur/Net/HTTP/IIPoWS.cs Normal file
View File

@ -0,0 +1,125 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Resource;
using Esiur.Net.IIP;
using Esiur.Net.Sockets;
using Esiur.Core;
namespace Esiur.Net.HTTP
{
public class IIPoWS: HTTPFilter
{
[Attribute]
public DistributedServer Server
{
get;
set;
}
public override AsyncReply<bool> Execute(HTTPConnection sender)
{
if (sender.IsWebsocketRequest())
{
if (Server == null)
return new AsyncReply<bool>(false);
var tcpSocket = sender.Unassign();
if (tcpSocket == null)
return new AsyncReply<bool>(false);
var httpServer = sender.Parent;
var wsSocket = new WSSocket(tcpSocket);
httpServer.Remove(sender);
var iipConnection = new DistributedConnection();
Server.Add(iipConnection);
iipConnection.Assign(wsSocket);
wsSocket.Begin();
return new AsyncReply<bool>(true);
}
return new AsyncReply<bool>( false);
/*
if (sender.Request.Filename.StartsWith("/iip/"))
{
// find the service
var path = sender.Request.Filename.Substring(5);// sender.Request.Query["path"];
Warehouse.Get(path).Then((r) =>
{
if (r is DistributedServer)
{
var httpServer = sender.Parent;
var iipServer = r as DistributedServer;
var tcpSocket = sender.Unassign();
if (tcpSocket == null)
return;
var wsSocket = new WSSocket(tcpSocket);
httpServer.RemoveConnection(sender);
//httpServer.Connections.Remove(sender);
var iipConnection = new DistributedConnection();
// iipConnection.OnReady += IipConnection_OnReady;
// iipConnection.Server = iipServer;
// iipConnection.Assign(wsSocket);
iipServer.AddConnection(iipConnection);
iipConnection.Assign(wsSocket);
wsSocket.Begin();
}
});
return true;
}
return false;
*/
}
private void IipConnection_OnReady(DistributedConnection sender)
{
Warehouse.Put(sender, sender.RemoteUsername, null, sender.Server);
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.IIP
{
public class DistributedPropertyContext
{
public object Value { get; private set; }
public DistributedConnection Connection { get; private set; }
public Func<DistributedConnection, object> Method { get; private set; }
public DistributedPropertyContext(DistributedConnection connection, object value)
{
this.Value = value;
this.Connection = connection;
}
public DistributedPropertyContext(Func<DistributedConnection, object> method)
{
this.Method = method;
}
public static implicit operator DistributedPropertyContext(Func<DistributedConnection, object> method)
=> new DistributedPropertyContext(method);
}
}

View File

@ -0,0 +1,464 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Collections;
using System.ComponentModel;
using Esiur.Misc;
using Esiur.Data;
using System.Dynamic;
using System.Security.Cryptography;
using Esiur.Core;
using System.Runtime.CompilerServices;
using System.Reflection.Emit;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Esiur.Resource;
using Esiur.Resource.Template;
namespace Esiur.Net.IIP
{
//[System.Runtime.InteropServices.ComVisible(true)]
public class DistributedResource : DynamicObject, IResource
{
/// <summary>
/// Raised when the distributed resource is destroyed.
/// </summary>
public event DestroyedEvent OnDestroy;
public event Instance.ResourceModifiedEvent OnModified;
uint instanceId;
DistributedConnection connection;
bool attached = false;
bool destroyed = false;
bool suspended = false;
//Structure properties = new Structure();
string link;
//ulong age;
//ulong[] ages;
object[] properties;
internal List<DistributedResource> parents = new List<DistributedResource>();
internal List<DistributedResource> children = new List<DistributedResource>();
DistributedResourceEvent[] events;
/// <summary>
/// Resource template for the remotely located resource.
/// </summary>
//public ResourceTemplate Template
//{
// get { return template; }
//}
/// <summary>
/// Connection responsible for the distributed resource.
/// </summary>
public DistributedConnection Connection
{
get { return connection; }
}
/// <summary>
/// Resource link
/// </summary>
public string Link
{
get { return link; }
}
/// <summary>
/// Instance Id given by the other end.
/// </summary>
public uint Id
{
get { return instanceId; }
}
/// <summary>
/// IDestructible interface.
/// </summary>
public void Destroy()
{
destroyed = true;
attached = false;
connection.SendDetachRequest(instanceId);
OnDestroy?.Invoke(this);
}
/// <summary>
/// Suspend resource
/// </summary>
internal void Suspend()
{
suspended = true;
attached = false;
}
/// <summary>
/// Resource is attached when all its properties are received.
/// </summary>
internal bool Attached => attached;
internal bool Suspended => suspended;
// public DistributedResourceStack Stack
//{
// get { return stack; }
//}
/// <summary>
/// Create a new distributed resource.
/// </summary>
/// <param name="connection">Connection responsible for the distributed resource.</param>
/// <param name="template">Resource template.</param>
/// <param name="instanceId">Instance Id given by the other end.</param>
/// <param name="age">Resource age.</param>
public DistributedResource(DistributedConnection connection, uint instanceId, ulong age, string link)
{
this.link = link;
this.connection = connection;
this.instanceId = instanceId;
//this.Instance.Template = template;
//this.Instance.Age = age;
//this.template = template;
//this.age = age;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
/// <returns></returns>
internal PropertyValue[] _Serialize()
{
var props = new PropertyValue[properties.Length];
for (byte i = 0; i < properties.Length; i++)
props[i] = new PropertyValue(properties[i], Instance.GetAge(i), Instance.GetModificationDate(i));
return props;
}
internal bool _Attach(PropertyValue[] properties)
{
if (attached)
return false;
else
{
suspended = false;
this.properties = new object[properties.Length];
this.events = new DistributedResourceEvent[Instance.Template.Events.Length];
for (byte i = 0; i < properties.Length; i++)
{
Instance.SetAge(i, properties[i].Age);
Instance.SetModificationDate(i, properties[i].Date);
this.properties[i] = properties[i].Value;
}
// trigger holded events/property updates.
//foreach (var r in afterAttachmentTriggers)
// r.Key.Trigger(r.Value);
//afterAttachmentTriggers.Clear();
attached = true;
}
return true;
}
internal void _EmitEventByIndex(byte index, object[] args)
{
var et = Instance.Template.GetEventTemplateByIndex(index);
events[index]?.Invoke(this, args);
Instance.EmitResourceEvent(et.Name, args);
}
public AsyncReply<object> _InvokeByNamedArguments(byte index, Structure namedArgs)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
if (suspended)
throw new Exception("Trying to access suspended object");
if (index >= Instance.Template.Functions.Length)
throw new Exception("Function index is incorrect");
return connection.SendInvokeByNamedArguments(instanceId, index, namedArgs);
}
public AsyncReply<object> _InvokeByArrayArguments(byte index, object[] args)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
if (suspended)
throw new Exception("Trying to access suspended object");
if (index >= Instance.Template.Functions.Length)
throw new Exception("Function index is incorrect");
return connection.SendInvokeByArrayArguments(instanceId, index, args);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var ft = Instance.Template.GetFunctionTemplateByName(binder.Name);
var reply = new AsyncReply<object>();
if (attached && ft!=null)
{
if (args.Length == 1)
{
// Detect anonymous types
var type = args[0].GetType();
if (Codec.IsAnonymous(type))
{
var namedArgs = new Structure();
var pi = type.GetTypeInfo().GetProperties();
foreach (var p in pi)
namedArgs[p.Name] = p.GetValue(args[0]);
result = _InvokeByNamedArguments(ft.Index, namedArgs);
}
else
{
result = _InvokeByArrayArguments(ft.Index, args);
}
}
else
{
result = _InvokeByArrayArguments(ft.Index, args);
}
return true;
}
else
{
result = null;
return false;
}
}
/// <summary>
/// Get a property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns>
internal object _Get(byte index)
{
if (index >= properties.Length)
return null;
return properties[index];
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
result = null;
if (!attached)
return false;
var pt = Instance.Template.GetPropertyTemplateByName(binder.Name);
if (pt != null)
{
result = properties[pt.Index];
return true;
}
else
{
var et = Instance.Template.GetEventTemplateByName(binder.Name);
if (et == null)
return false;
result = events[et.Index];
return true;
}
}
internal void _UpdatePropertyByIndex(byte index, object value)
{
var pt = Instance.Template.GetPropertyTemplateByIndex(index);
properties[index] = value;
Instance.EmitModification(pt, value);
}
/// <summary>
/// Set property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns>
internal AsyncReply<object> _Set(byte index, object value)
{
if (index >= properties.Length)
return null;
var reply = new AsyncReply<object>();
var parameters = Codec.Compose(value, connection);
connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty)
.AddUInt32(instanceId)
.AddUInt8(index)
.AddUInt8Array(parameters)
.Done()
.Then((res) =>
{
// not really needed, server will always send property modified,
// this only happens if the programmer forgot to emit in property setter
properties[index] = value;
reply.Trigger(null);
});
return reply;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
if (suspended)
throw new Exception("Trying to access suspended object");
if (!attached)
return false;
var pt = Instance.Template.GetPropertyTemplateByName(binder.Name);
if (pt != null)
{
_Set(pt.Index, value);
return true;
}
else
{
var et = Instance.Template.GetEventTemplateByName(binder.Name);
if (et == null)
return false;
events[et.Index] = (DistributedResourceEvent)value;
return true;
}
}
/*
public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender)
{
// get function parameters
Type t = this.GetType();
MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance | BindingFlags.InvokeMethod);
if (mi != null)
{
try
{
var res = await invokeMethod(mi, arguments, sender);
object rt = Codec.Compose(res);
sender.SendParams((byte)0x80, instanceId, index, rt);
}
catch(Exception ex)
{
var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg));
}
}
}
*/
/// <summary>
/// Resource interface.
/// </summary>
public Instance Instance
{
get;
set;
}
/// <summary>
/// Create a new instance of distributed resource.
/// </summary>
public DistributedResource()
{
//stack = new DistributedResourceStack(this);
//this.Instance.ResourceModified += this.OnModified;
}
/// <summary>
/// Resource interface.
/// </summary>
/// <param name="trigger"></param>
/// <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

@ -0,0 +1,34 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.IIP
{
public delegate void DistributedResourceEvent(DistributedResource sender, params object[] arguments);
}

View File

@ -0,0 +1,73 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.IIP
{
public class DistributedResourceQueueItem
{
public enum DistributedResourceQueueItemType
{
Propery,
Event
}
DistributedResourceQueueItemType type;
byte index;
object value;
DistributedResource resource;
public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index)
{
this.resource = resource;
this.index = index;
this.type = type;
this.value = value;
}
public DistributedResource Resource
{
get { return resource; }
}
public DistributedResourceQueueItemType Type
{
get { return type; }
}
public byte Index
{
get { return index; }
}
public object Value
{
get { return value; }
}
}
}

View File

@ -0,0 +1,169 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Net.Sockets;
using Esiur.Misc;
using System.Threading;
using Esiur.Data;
using Esiur.Core;
using System.Net;
using Esiur.Resource;
using Esiur.Security.Membership;
namespace Esiur.Net.IIP
{
public class DistributedServer : NetworkServer<DistributedConnection>, IResource
{
[Attribute]
public string IP
{
get;
set;
}
[Attribute]
public IMembership Membership
{
get;
set;
}
[Attribute]
public EntryPoint EntryPoint
{
get;
set;
}
[Attribute]
public ushort Port
{
get;
set;
}
public Instance Instance
{
get;
set;
}
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);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
return new AsyncReply<bool>(true);
}
//protected override void DataReceived(DistributedConnection sender, NetworkBuffer data)
//{
// //throw new NotImplementedException();
//}
//protected override void ClientConnected(DistributedConnection sender)
//{
// //Console.WriteLine("DistributedConnection Client Connected");
//}
//private void ConnectionReadyEventReceiver(DistributedConnection sender)
//{
// sender.OnReady -= ConnectionReadyEventReceiver;
// Warehouse.Put(sender, sender.LocalUsername, null, this);
//}
//public override void RemoveConnection(DistributedConnection connection)
//{
// connection.OnReady -= Sender_OnReady;
// //connection.Server = null;
// base.RemoveConnection(connection);
//}
//public override void AddConnection(DistributedConnection connection)
//{
// connection.OnReady += Sender_OnReady;
// connection.Server = this;
// base.AddConnection(connection);
//}
protected override void ClientConnected(DistributedConnection connection)
{
//connection.OnReady += ConnectionReadyEventReceiver;
}
public override void Add(DistributedConnection connection)
{
connection.Server = this;
base.Add(connection);
}
public override void Remove(DistributedConnection connection)
{
connection.Server = null;
base.Remove(connection);
}
protected override void ClientDisconnected(DistributedConnection connection)
{
//connection.OnReady -= ConnectionReadyEventReceiver;
//Warehouse.Remove(connection);
}
}
}

View File

@ -0,0 +1,38 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Esiur.Net.Sockets;
using Esiur.Security.Authority;
namespace Esiur.Net.IIP
{
public class DistributedSession : NetworkSession
{
Source Source { get; }
Authentication Authentication;
}
}

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);
protected abstract override bool Create();
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net
{
public interface INetworkReceiver<T>
{
void NetworkClose(T sender);
void NetworkReceive(T sender, NetworkBuffer buffer);
//void NetworkError(T sender);
void NetworkConnect(T sender);
}
}

208
Esiur/Net/NetworkBuffer.cs Normal file
View File

@ -0,0 +1,208 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Data;
using Esiur.Misc;
namespace Esiur.Net
{
public class NetworkBuffer
{
byte[] data;
uint neededDataLength = 0;
//bool trim;
object syncLock = new object();
//public object SyncLock
//{
// get { return syncLock; }
//}
public NetworkBuffer()
{
data = new byte[0];
}
public bool Protected
{
get
{
return neededDataLength > data.Length;
}
}
public uint Available
{
get
{
return (uint)data.Length;
}
}
//public void HoldForAtLeast(byte[] src, uint offset, uint size, uint needed)
//{
// HoldFor(src, offset, size, needed);
// //trim = false;
//}
//public void HoldForAtLeast(byte[] src, uint needed)
//{
// HoldForAtLeast(src, 0, (uint)src.Length, needed);
//}
public void HoldForNextWrite(byte[] src)
{
//HoldForAtLeast(src, (uint)src.Length + 1);
HoldFor(src, (uint)src.Length + 1);
}
public void HoldForNextWrite(byte[] src, uint offset, uint size)
{
//HoldForAtLeast(src, offset, size, size + 1);
HoldFor(src, offset, size, size + 1);
}
public void HoldFor(byte[] src, uint offset, uint size, uint needed)
{
lock (syncLock)
{
if (size >= needed)
throw new Exception("Size >= Needed !");
//trim = true;
data = DC.Combine(src, offset, size, data, 0, (uint)data.Length);
neededDataLength = needed;
// Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace);
//Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode());
}
}
public void HoldFor(byte[] src, uint needed)
{
HoldFor(src, 0, (uint)src.Length, needed);
}
public bool Protect(byte[] data, uint offset, uint needed)//, bool exact = false)
{
uint dataLength = (uint)data.Length - offset;
// protection
if (dataLength < needed)
{
//if (exact)
// HoldFor(data, offset, dataLength, needed);
//else
//HoldForAtLeast(data, offset, dataLength, needed);
HoldFor(data, offset, dataLength, needed);
return true;
}
else
return false;
}
public void Write(byte[] src)
{
Write(src, 0, (uint)src.Length);
}
public void Write(byte[] src, uint offset, uint length)
{
//if (data.Length > 0)
// Console.WriteLine();
lock(syncLock)
DC.Append(ref data, src, offset, length);
}
public bool CanRead
{
get
{
if (data.Length == 0)
return false;
if (data.Length < neededDataLength)
return false;
return true;
}
}
public byte[] Read()
{
lock (syncLock)
{
if (data.Length == 0)
return null;
byte[] rt = null;
if (neededDataLength == 0)
{
rt = data;
data = new byte[0];
}
else
{
//Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength);
if (data.Length >= neededDataLength)
{
//Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim);
//if (trim)
//{
// rt = DC.Clip(data, 0, neededDataLength);
// data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength);
//}
//else
//{
// return all data
rt = data;
data = new byte[0];
//}
neededDataLength = 0;
return rt;
}
else
{
return null;
}
}
return rt;
}
}
}
}

View File

@ -0,0 +1,367 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Misc;
using Esiur.Core;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Resource;
namespace Esiur.Net
{
public abstract class NetworkConnection: IDestructible, INetworkReceiver<ISocket>// <TS>: IResource where TS : NetworkSession
{
private Sockets.ISocket sock;
// private bool connected;
private DateTime lastAction;
//public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data);
//public delegate void ConnectionClosedEvent(NetworkConnection sender);
public delegate void NetworkConnectionEvent(NetworkConnection connection);
public event NetworkConnectionEvent OnConnect;
//public event DataReceivedEvent OnDataReceived;
public event NetworkConnectionEvent OnClose;
public event DestroyedEvent OnDestroy;
//object receivingLock = new object();
//object sendLock = new object();
bool processing = false;
// public INetworkReceiver<NetworkConnection> Receiver { get; set; }
public virtual void Destroy()
{
// remove references
//sock.OnClose -= Socket_OnClose;
//sock.OnConnect -= Socket_OnConnect;
//sock.OnReceive -= Socket_OnReceive;
sock.Destroy();
//Receiver = null;
Close();
sock = null;
OnClose = null;
OnConnect = null;
//OnDataReceived = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public ISocket Socket
{
get
{
return sock;
}
}
public virtual void Assign(ISocket socket)
{
lastAction = DateTime.Now;
sock = socket;
sock.Receiver = this;
//socket.OnReceive += Socket_OnReceive;
//socket.OnClose += Socket_OnClose;
//socket.OnConnect += Socket_OnConnect;
}
//private void Socket_OnConnect()
//{
// OnConnect?.Invoke(this);
//}
//private void Socket_OnClose()
//{
// ConnectionClosed();
// OnClose?.Invoke(this);
//}
//protected virtual void ConnectionClosed()
//{
//}
//private void Socket_OnReceive(NetworkBuffer buffer)
//{
//}
public ISocket Unassign()
{
if (sock != null)
{
// connected = false;
//sock.OnClose -= Socket_OnClose;
//sock.OnConnect -= Socket_OnConnect;
//sock.OnReceive -= Socket_OnReceive;
sock.Receiver = null;
var rt = sock;
sock = null;
return rt;
}
else
return null;
}
//protected virtual void DataReceived(NetworkBuffer data)
//{
// if (OnDataReceived != null)
// {
// try
// {
// OnDataReceived?.Invoke(this, data);
// }
// catch (Exception ex)
// {
// Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString());
// }
// }
//}
public void Close()
{
//if (!connected)
// return;
try
{
if (sock != null)
sock.Close();
}
catch (Exception ex)
{
Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString());
}
//finally
//{
//connected = false;
//}
}
public DateTime LastAction
{
get { return lastAction; }
}
public IPEndPoint RemoteEndPoint
{
get
{
if (sock != null)
return (IPEndPoint)sock.RemoteEndPoint;
else
return null;
}
}
public IPEndPoint LocalEndPoint
{
get
{
if (sock != null)
return (IPEndPoint)sock.LocalEndPoint;
else
return null;
}
}
public bool IsConnected
{
get
{
return sock.State == SocketState.Established;
}
}
/*
public void CloseAndWait()
{
try
{
if (!connected)
return;
if (sock != null)
sock.Close();
while (connected)
{
Thread.Sleep(100);
}
}
finally
{
}
}
*/
public virtual AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
try
{
lastAction = DateTime.Now;
return sock.SendAsync(message, offset, length);
}
catch
{
return new AsyncReply<bool>(false);
}
}
public virtual void Send(byte[] msg)
{
try
{
sock?.Send(msg);
lastAction = DateTime.Now;
}
catch
{
}
}
public virtual void Send(byte[] msg, int offset, int length)
{
try
{
sock.Send(msg, offset, length);
lastAction = DateTime.Now;
}
catch
{
}
}
public virtual void Send(string data)
{
Send(Encoding.UTF8.GetBytes(data));
}
public void NetworkClose(ISocket socket)
{
Disconencted();
OnClose?.Invoke(this);
}
public void NetworkConnect(ISocket socket)
{
Connected();
OnConnect?.Invoke(this);
}
//{
//ConnectionClosed();
//OnClose?.Invoke(this);
//Receiver?.NetworkClose(this);
//}
//public void NetworkConenct(ISocket sender)
//{
// OnConnect?.Invoke(this);
//}
protected abstract void DataReceived(NetworkBuffer buffer);
protected abstract void Connected();
protected abstract void Disconencted();
public void NetworkReceive(ISocket sender, NetworkBuffer buffer)
{
try
{
// Unassigned ?
if (sock == null)
return;
// Closed ?
if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) // || !connected)
return;
lastAction = DateTime.Now;
if (!processing)
{
processing = true;
try
{
//lock(buffer.SyncLock)
while (buffer.Available > 0 && !buffer.Protected)
{
//Receiver?.NetworkReceive(this, buffer);
DataReceived(buffer);
}
}
catch
{
}
processing = false;
}
}
catch (Exception ex)
{
Global.Log("NetworkConnection", LogType.Warning, ex.ToString());
}
}
//{
// Receiver?.NetworkError(this);
//throw new NotImplementedException();
//}
//public void NetworkConnect(ISocket sender)
//{
// Receiver?.NetworkConnect(this);
//throw new NotImplementedException();
//}
}
}

311
Esiur/Net/NetworkServer.cs Normal file
View File

@ -0,0 +1,311 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Threading;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using Esiur.Net.Sockets;
using Esiur.Resource;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Esiur.Net
{
public abstract class NetworkServer<TConnection> : IDestructible where TConnection : NetworkConnection, new()
{
//private bool isRunning;
private Sockets.ISocket listener;
public AutoList<TConnection, NetworkServer<TConnection>> Connections { get; private set; }
private Thread thread;
//protected abstract void DataReceived(TConnection sender, NetworkBuffer data);
//protected abstract void ClientConnected(TConnection sender);
//protected abstract void ClientDisconnected(TConnection sender);
private Timer timer;
//public KeyList<string, TSession> Sessions = new KeyList<string, TSession>();
public event DestroyedEvent OnDestroy;
//public AutoList<TConnection, NetworkServer<TConnection>> Connections => connections;
private void MinuteThread(object state)
{
List<TConnection> ToBeClosed = null;
lock (Connections.SyncRoot)
{
foreach (TConnection c in Connections)
{
if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= Timeout)
{
if (ToBeClosed == null)
ToBeClosed = new List<TConnection>();
ToBeClosed.Add(c);
}
}
}
if (ToBeClosed != null)
{
//Console.WriteLine("Term: " + ToBeClosed.Count + " " + this.listener.LocalEndPoint.ToString());
foreach (TConnection c in ToBeClosed)
c.Close();// CloseAndWait();
ToBeClosed.Clear();
ToBeClosed = null;
}
}
public void Start(Sockets.ISocket socket)//, uint timeout, uint clock)
{
if (listener != null)
return;
Connections = new AutoList<TConnection, NetworkServer<TConnection>>(this);
if (Timeout > 0 & Clock > 0)
{
timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(Clock));
}
listener = socket;
// Start accepting
//var r = listener.Accept();
//r.Then(NewConnection);
//r.timeout?.Dispose();
//var rt = listener.Accept().Then()
thread = new Thread(new ThreadStart(() =>
{
while (true)
{
try
{
var s = listener.Accept();
if (s == null)
{
Console.Write("sock == null");
return;
}
var c = new TConnection();
//c.OnClose += ClientDisconnectedEventReceiver;
c.Assign(s);
Add(c);
//Connections.Add(c);
try
{
//ClientConnected(c);
ClientConnected(c);
//NetworkConnect(c);
}
catch
{
// something wrong with the child.
}
s.Begin();
// Accept more
//listener.Accept().Then(NewConnection);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}));
thread.Start();
}
[Attribute]
public uint Timeout
{
get;
set;
}
[Attribute]
public uint Clock
{
get;
set;
}
public void Stop()
{
var port = 0;
try
{
if (listener != null)
{
port = listener.LocalEndPoint.Port;
listener.Close();
}
// wait until the listener stops
//while (isRunning)
//{
// Thread.Sleep(100);
//}
//Console.WriteLine("Listener stopped");
var cons = Connections.ToArray();
//lock (connections.SyncRoot)
//{
foreach (TConnection con in cons)
con.Close();
//}
//Console.WriteLine("Sockets Closed");
//while (connections.Count > 0)
//{
// Console.WriteLine("Waiting... " + connections.Count);
// Thread.Sleep(1000);
//}
}
finally
{
Console.WriteLine("Server@{0} is down", port);
}
}
public virtual void Remove(TConnection connection)
{
//connection.OnDataReceived -= OnDataReceived;
//connection.OnConnect -= OnClientConnect;
connection.OnClose -= ClientDisconnectedEventReceiver;
Connections.Remove(connection);
}
public virtual void Add(TConnection connection)
{
//connection.OnDataReceived += OnDataReceived;
//connection.OnConnect += OnClientConnect;
connection.OnClose += ClientDisconnectedEventReceiver;// OnClientClose;
Connections.Add(connection);
}
public bool IsRunning
{
get
{
return listener.State == SocketState.Listening;
//isRunning;
}
}
//public void OnDataReceived(ISocket sender, NetworkBuffer data)
//{
// DataReceived((TConnection)sender, data);
//}
//public void OnClientConnect(ISocket sender)
//{
// if (sender == null)
// return;
// if (sender.RemoteEndPoint == null || sender.LocalEndPoint == null)
// { }
// //Console.WriteLine("NULL");
// else
// Global.Log("Connections", LogType.Debug, sender.RemoteEndPoint.Address.ToString()
// + "->" + sender.LocalEndPoint.Port + " at " + DateTime.UtcNow.ToString("d")
// + " " + DateTime.UtcNow.ToString("d"), false);
// // Console.WriteLine("Connected " + sender.RemoteEndPoint.ToString());
// ClientConnected((TConnection)sender);
//}
//public void OnClientClose(ISocket sender)
//{
//}
public void Destroy()
{
Stop();
OnDestroy?.Invoke(this);
}
private void ClientDisconnectedEventReceiver(NetworkConnection connection)
{
try
{
var con = connection as TConnection;
con.Destroy();
// con.OnClose -= ClientDisconnectedEventReceiver;
Remove(con);
//Connections.Remove(con);
ClientDisconnected(con);
//RemoveConnection((TConnection)sender);
//connections.Remove(sender)
//ClientDisconnected((TConnection)sender);
}
catch (Exception ex)
{
Global.Log("NetworkServer:OnClientDisconnect", LogType.Error, ex.ToString());
}
}
protected abstract void ClientDisconnected(TConnection connection);
protected abstract void ClientConnected(TConnection connection);
~NetworkServer()
{
Stop();
listener = null;
}
}
}

130
Esiur/Net/NetworkSession.cs Normal file
View File

@ -0,0 +1,130 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
namespace Esiur.Net
{
public class NetworkSession:IDestructible //<T> where T : TClient
{
public delegate void SessionModifiedEvent(NetworkSession session, string key, object oldValue, object newValue);
public delegate void SessionEndedEvent(NetworkSession session);
private string id;
private Timer timer;
private int timeout;
DateTime creation;
DateTime lastAction;
private KeyList<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{
get { return variables; }
}
public NetworkSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
internal void Set(string id, int timeout )
{
//modified = sessionModifiedEvent;
//ended = sessionEndEvent;
this.id = id;
if (this.timeout != 0)
{
this.timeout = timeout;
timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
creation = DateTime.Now;
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> sender)
{
OnModify?.Invoke(this, key, oldValue, newValue);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
timer.Dispose();
timer = null;
}
internal void Refresh()
{
lastAction = DateTime.Now;
timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
}
public int Timeout // Seconds
{
get
{
return timeout;
}
set
{
timeout = value;
Refresh();
}
}
public string Id
{
get { return id; }
}
public DateTime LastAction
{
get { return lastAction; }
}
}
}

View File

@ -0,0 +1,313 @@

/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
using System.Net;
namespace Esiur.Net.Packets
{
public class HTTPRequestPacket : Packet
{
public enum HTTPMethod:byte
{
GET,
POST,
HEAD,
PUT,
DELETE,
OPTIONS,
TRACE,
CONNECT,
UNKNOWN
}
public StringKeyList Query;
public HTTPMethod Method;
public StringKeyList Headers;
public bool WSMode;
public string Version;
public StringKeyList Cookies; // String
public string URL; /// With query
public string Filename; /// Without query
//public byte[] PostContents;
public KeyList<string, object> PostForms;
public byte[] Message;
private HTTPMethod getMethod(string method)
{
switch (method.ToLower())
{
case "get":
return HTTPMethod.GET;
case "post":
return HTTPMethod.POST;
case "head":
return HTTPMethod.HEAD;
case "put":
return HTTPMethod.PUT;
case "delete":
return HTTPMethod.DELETE;
case "options":
return HTTPMethod.OPTIONS;
case "trace":
return HTTPMethod.TRACE;
case "connect":
return HTTPMethod.CONNECT;
default:
return HTTPMethod.UNKNOWN;
}
}
public override string ToString()
{
return "HTTPRequestPacket"
+ "\n\tVersion: " + Version
+ "\n\tMethod: " + Method
+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
public override long Parse(byte[] data, uint offset, uint ends)
{
string[] sMethod = null;
string[] sLines = null;
uint headerSize = 0;
for (uint i = offset; i < ends - 3; i++)
{
if (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{
sLines = Encoding.ASCII.GetString(data, (int)offset,(int)( i - offset)).Split(new string[] { "\r\n" },
StringSplitOptions.None);
headerSize = i + 4;
break;
}
}
if (headerSize == 0)
return -1;
Cookies = new StringKeyList();
PostForms = new KeyList<string, object>();
Query = new StringKeyList();
Headers = new StringKeyList();
sMethod = sLines[0].Split(' ');
Method = getMethod(sMethod[0].Trim());
if (sMethod.Length == 3)
{
sMethod[1] = WebUtility.UrlDecode(sMethod[1]);
if (sMethod[1].Length >= 7)
{
if (sMethod[1].StartsWith("http://"))
{
sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7));
}
}
URL = sMethod[1].Trim();
if (URL.IndexOf("?", 0) != -1)
{
Filename = URL.Split(new char[] { '?' }, 2)[0];
}
else
{
Filename = URL;
}
if (Filename.IndexOf("%", 0) != -1)
{
Filename = WebUtility.UrlDecode(Filename);
}
Version = sMethod[2].Trim();
}
// Read all headers
for (int i = 1; i < sLines.Length; i++)
{
if (sLines[i] == String.Empty)
{
// Invalid header
return 0;
}
if (sLines[i].IndexOf(':') == -1)
{
// Invalid header
return 0;
}
string[] header = sLines[i].Split(new char[] { ':' }, 2);
header[0] = header[0].ToLower();
Headers[header[0]] = header[1].Trim();
if (header[0] == "cookie")
{
string[] cookies = header[1].Split(';');
foreach (string cookie in cookies)
{
if (cookie.IndexOf('=') != -1)
{
string[] splitCookie = cookie.Split('=');
splitCookie[0] = splitCookie[0].Trim();
splitCookie[1] = splitCookie[1].Trim();
if (!(Cookies.ContainsKey(splitCookie[0].Trim())))
Cookies.Add(splitCookie[0], splitCookie[1]);
}
else
{
if (!(Cookies.ContainsKey(cookie.Trim())))
{
Cookies.Add(cookie.Trim(), String.Empty);
}
}
}
}
}
// Query String
if (URL.IndexOf("?", 0) != -1)
{
string[] SQ = URL.Split(new char[] { '?' }, 2)[1].Split('&');
foreach (string S in SQ)
{
if (S.IndexOf("=", 0) != -1)
{
string[] qp = S.Split(new char[] { '=' }, 2);
if (!Query.ContainsKey(WebUtility.UrlDecode(qp[0])))
{
Query.Add(WebUtility.UrlDecode(qp[0]), WebUtility.UrlDecode(qp[1]));
}
}
else
{
if (!(Query.ContainsKey(WebUtility.UrlDecode(S))))
{
Query.Add(WebUtility.UrlDecode(S), null);
}
}
}
}
// Post Content-Length
if (Method == HTTPMethod.POST)
{
try
{
uint postSize = uint.Parse((string)Headers["content-length"]);
// check limit
if (postSize > data.Length - headerSize)
return -(postSize - (data.Length - headerSize));
if (
Headers["content-type"] == null
|| Headers["content-type"] == ""
|| Headers["content-type"].StartsWith("application/x-www-form-urlencoded"))
{
string[] PostVars = null;
PostVars = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split('&');
for (int J = 0; J < PostVars.Length; J++)
{
if (PostVars[J].IndexOf("=") != -1)
{
string key = WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0]));
if (PostForms.Contains(key))
PostForms[key] = WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1]));
else
PostForms.Add(key, WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1])));
}
else
if (PostForms.Contains("unknown"))
PostForms["unknown"] = PostForms["unknown"]
+ "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]));
else
PostForms.Add("unknown", WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J])));
}
}
else if (Headers["content-type"].StartsWith("multipart/form-data"))
{
int st = 1;
int ed = 0;
string strBoundry = "--" + Headers["content-type"].Substring(
Headers["content-type"].IndexOf("boundary=", 0) + 9);
string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split(
new string[] { strBoundry }, StringSplitOptions.None);
for (int j = 1; j < sc.Length - 1; j++)
{
string[] ps = sc[j].Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.None);
ps[1] = ps[1].Substring(0, ps[1].Length - 2); // remove the empty line
st = ps[0].IndexOf("name=", 0) + 6;
ed = ps[0].IndexOf("\"", st);
PostForms.Add(ps[0].Substring(st, ed - st), ps[1]);
}
}
else
{
//PostForms.Add(Headers["content-type"], Encoding.Default.GetString( ));
Message = DC.Clip(data, headerSize, postSize);
}
return headerSize + postSize;
}
catch
{
return 0;
}
}
return headerSize;
}
}
}

View File

@ -0,0 +1,304 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets
{
public class HTTPResponsePacket : Packet
{
public enum ComposeOptions : int
{
AllCalculateLength,
AllDontCalculateLength,
SpecifiedHeadersOnly,
DataOnly
}
public enum ResponseCode : int
{
Switching= 101,
OK = 200,
Created = 201,
Accepted = 202,
NoContent = 204,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
TemporaryRedirect = 307,
BadRequest = 400,
Unauthorized = 401,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
PreconditionFailed = 412,
UnsupportedMediaType = 415,
InternalServerError = 500,
NotImplemented = 501,
}
public struct HTTPCookie
{
public string Name;
public string Value;
public DateTime Expires;
public string Path;
public bool HttpOnly;
public string Domain;
public HTTPCookie(string name, string value)
{
this.Name = name;
this.Value = value;
this.Path = null;
this.Expires = DateTime.MinValue;
this.HttpOnly = false;
this.Domain = null;
}
public HTTPCookie(string name, string value, DateTime expires)
{
this.Name = name;
this.Value = value;
this.Expires = expires;
this.HttpOnly = false;
this.Domain = null;
this.Path = null;
}
public override string ToString()
{
//Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/
//Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/
var cookie = Name + "=" + Value;
if (Expires.Ticks != 0)
cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT";
if (Domain != null)
cookie += "; domain=" + Domain;
if (Path != null)
cookie += "; path=" + Path;
if (HttpOnly)
cookie += "; HttpOnly";
return cookie;
}
}
public StringKeyList Headers = new StringKeyList(true);
public string Version = "HTTP/1.1";
public byte[] Message;
public ResponseCode Number;
public string Text;
public List<HTTPCookie> Cookies = new List<HTTPCookie>();
public bool Handled;
public override string ToString()
{
return "HTTPResponsePacket"
+ "\n\tVersion: " + Version
//+ "\n\tMethod: " + Method
//+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
private string MakeHeader(ComposeOptions options)
{
string header = $"{Version} {(int)Number} {Text}\r\nServer: Esiur {Global.Version}\r\nDate: {DateTime.Now.ToUniversalTime().ToString("r")}\r\n";
if (options == ComposeOptions.AllCalculateLength)
Headers["Content-Length"] = Message?.Length.ToString() ?? "0";
foreach (var kv in Headers)
header += kv.Key + ": " + kv.Value + "\r\n";
// Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2007 21:00:00 GMT; path=/
// Set-Cookie: ASPSESSIONIDQABBDSQA=IPDPMMMALDGFLMICEJIOCIPM; path=/
foreach (var Cookie in Cookies)
header += "Set-Cookie: " + Cookie.ToString() + "\r\n";
header += "\r\n";
return header;
}
public bool Compose(ComposeOptions options)
{
List<byte> msg = new List<byte>();
if (options != ComposeOptions.DataOnly)
{
msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options)));
}
if (options != ComposeOptions.SpecifiedHeadersOnly)
{
if (Message != null)
msg.AddRange(Message);
}
Data = msg.ToArray();
return true;
}
public override bool Compose()
{
return Compose(ComposeOptions.AllDontCalculateLength);
}
public override long Parse(byte[] data, uint offset, uint ends)
{
string[] sMethod = null;
string[] sLines = null;
uint headerSize = 0;
for (uint i = offset; i < ends - 3; i++)
{
if (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{
sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
StringSplitOptions.None);
headerSize = i + 4;
break;
}
}
if (headerSize == 0)
return -1;
//Cookies = new DStringDictionary();
//Headers = new DStringDictionary(true);
sMethod = sLines[0].Split(' ');
if (sMethod.Length == 3)
{
Version = sMethod[0].Trim();
Number = (ResponseCode)(Convert.ToInt32(sMethod[1].Trim()));
Text = sMethod[2];
}
// Read all headers
for (int i = 1; i < sLines.Length; i++)
{
if (sLines[i] == String.Empty)
{
// Invalid header
return 0;
}
if (sLines[i].IndexOf(':') == -1)
{
// Invalid header
return 0;
}
string[] header = sLines[i].Split(new char[] { ':' }, 2);
header[0] = header[0].ToLower();
Headers[header[0]] = header[1].Trim();
//Set-Cookie: NAME=VALUE; expires=DATE;
if (header[0] == "set-cookie")
{
string[] cookie = header[1].Split(';');
if (cookie.Length >= 1)
{
string[] splitCookie = cookie[0].Split('=');
HTTPCookie c = new HTTPCookie(splitCookie[0], splitCookie[1]);
for (int j = 1; j < cookie.Length; j++)
{
splitCookie = cookie[j].Split('=');
switch (splitCookie[0].ToLower())
{
case "domain":
c.Domain = splitCookie[1];
break;
case "path":
c.Path = splitCookie[1];
break;
case "httponly":
c.HttpOnly = true;
break;
case "expires":
// Wed, 13-Jan-2021 22:23:01 GMT
c.Expires = DateTime.Parse(splitCookie[1]);
break;
}
}
}
}
}
// Content-Length
try
{
uint contentLength = uint.Parse((string)Headers["content-length"]);
// check limit
if (contentLength > data.Length - headerSize)
{
return contentLength - (data.Length - headerSize);
}
Message = DC.Clip(data, offset, contentLength);
return headerSize + contentLength;
}
catch
{
return 0;
}
}
}
}

View File

@ -0,0 +1,412 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Data;
using Esiur.Security.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Packets
{
class IIPAuthPacket : Packet
{
public enum IIPAuthPacketCommand : byte
{
Action = 0,
Declare,
Acknowledge,
Error,
}
public enum IIPAuthPacketAction : byte
{
// Authenticate
AuthenticateHash,
//Challenge,
//CertificateRequest,
//CertificateReply,
//EstablishRequest,
//EstablishReply
NewConnection = 0x20,
ResumeConnection,
ConnectionEstablished = 0x28
}
public IIPAuthPacketCommand Command
{
get;
set;
}
public IIPAuthPacketAction Action
{
get;
set;
}
public byte ErrorCode { get; set; }
public string ErrorMessage { get; set; }
public AuthenticationMethod LocalMethod
{
get;
set;
}
public byte[] SourceInfo
{
get;
set;
}
public byte[] Hash
{
get;
set;
}
public byte[] SessionId
{
get;
set;
}
public AuthenticationMethod RemoteMethod
{
get;
set;
}
public string Domain
{
get;
set;
}
public long CertificateId
{
get; set;
}
public string LocalUsername
{
get;
set;
}
public string RemoteUsername
{
get;
set;
}
public byte[] LocalPassword
{
get;
set;
}
public byte[] RemotePassword
{
get;
set;
}
public byte[] LocalToken
{
get;
set;
}
public byte[] RemoteToken
{
get;
set;
}
public byte[] AsymetricEncryptionKey
{
get;
set;
}
public byte[] LocalNonce
{
get;
set;
}
public byte[] RemoteNonce
{
get;
set;
}
public ulong RemoteTokenIndex { get; set; }
private uint dataLengthNeeded;
bool NotEnough(uint offset, uint ends, uint needed)
{
if (offset + needed > ends)
{
dataLengthNeeded = needed - (ends - offset);
return true;
}
else
return false;
}
public override string ToString()
{
return Command.ToString() + " " + Action.ToString();
}
public override long Parse(byte[] data, uint offset, uint ends)
{
var oOffset = offset;
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
Command = (IIPAuthPacketCommand)(data[offset] >> 6);
if (Command == IIPAuthPacketCommand.Action)
{
Action = (IIPAuthPacketAction)(data[offset++] & 0x3f);
if (Action == IIPAuthPacketAction.AuthenticateHash)
{
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
Hash = data.Clip(offset, 32);
//var hash = new byte[32];
//Buffer.BlockCopy(data, (int)offset, hash, 0, 32);
//Hash = hash;
offset += 32;
}
else if (Action == IIPAuthPacketAction.NewConnection)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var length = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, length))
return -dataLengthNeeded;
SourceInfo = data.Clip(offset, length);
//var sourceInfo = new byte[length];
//Buffer.BlockCopy(data, (int)offset, sourceInfo, 0, length);
//SourceInfo = sourceInfo;
offset += 32;
}
else if (Action == IIPAuthPacketAction.ResumeConnection
|| Action == IIPAuthPacketAction.ConnectionEstablished)
{
//var sessionId = new byte[32];
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
SessionId = data.Clip(offset, 32);
//Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32);
//SessionId = sessionId;
offset += 32;
}
}
else if (Command == IIPAuthPacketCommand.Declare)
{
RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3);
LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var domainLength = data[offset++];
if (NotEnough(offset, ends, domainLength))
return -dataLengthNeeded;
var domain = data.GetString(offset, domainLength);
Domain = domain;
offset += domainLength;
if (RemoteMethod == AuthenticationMethod.Credentials)
{
if (LocalMethod == AuthenticationMethod.None)
{
if (NotEnough(offset, ends, 33))
return -dataLengthNeeded;
//var remoteNonce = new byte[32];
//Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32);
//RemoteNonce = remoteNonce;
RemoteNonce = data.Clip(offset, 32);
offset += 32;
var length = data[offset++];
if (NotEnough(offset, ends, length))
return -dataLengthNeeded;
RemoteUsername = data.GetString(offset, length);
offset += length;
}
}
else if (RemoteMethod == AuthenticationMethod.Token)
{
if (LocalMethod == AuthenticationMethod.None)
{
if (NotEnough(offset, ends, 37))
return -dataLengthNeeded;
RemoteNonce = data.Clip(offset, 32);
offset += 32;
RemoteTokenIndex = data.GetUInt64(offset);
offset += 8;
}
}
if (encrypt)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var keyLength = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, keyLength))
return -dataLengthNeeded;
//var key = new byte[keyLength];
//Buffer.BlockCopy(data, (int)offset, key, 0, keyLength);
//AsymetricEncryptionKey = key;
AsymetricEncryptionKey = data.Clip(offset, keyLength);
offset += keyLength;
}
}
else if (Command == IIPAuthPacketCommand.Acknowledge)
{
RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3);
LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
if (RemoteMethod == AuthenticationMethod.Credentials
|| RemoteMethod == AuthenticationMethod.Token)
{
if (LocalMethod == AuthenticationMethod.None)
{
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
RemoteNonce = data.Clip(offset, 32);
offset += 32;
}
}
if (encrypt)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var keyLength = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, keyLength))
return -dataLengthNeeded;
//var key = new byte[keyLength];
//Buffer.BlockCopy(data, (int)offset, key, 0, keyLength);
//AsymetricEncryptionKey = key;
AsymetricEncryptionKey = data.Clip(offset, keyLength);
offset += keyLength;
}
}
else if (Command == IIPAuthPacketCommand.Error)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
offset++;
ErrorCode = data[offset++];
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ErrorMessage = data.GetString(offset, cl);
offset += cl;
}
return offset - oOffset;
}
}
}

View File

@ -0,0 +1,823 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Data;
using Esiur.Core;
using Esiur.Misc;
using Esiur.Net.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Packets
{
class IIPPacket : Packet
{
public override string ToString()
{
var rt = Command.ToString();
if (Command == IIPPacketCommand.Event)
{
rt += " " + Event.ToString();
//if (Event == IIPPacketEvent.AttributesUpdated)
// rt +=
}
else if (Command == IIPPacketCommand.Request)
{
rt += " " + Action.ToString();
if (Action == IIPPacketAction.AttachResource)
{
rt += " CID: " + CallbackId + " RID: " + ResourceId;
}
}
else if (Command == IIPPacketCommand.Reply)
rt += " " + Action.ToString();
else if (Command == IIPPacketCommand.Report)
rt += " " + Report.ToString();
return rt;
}
public enum IIPPacketCommand : byte
{
Event = 0,
Request,
Reply,
Report,
}
public enum IIPPacketEvent : byte
{
// Event Manage
ResourceReassigned = 0,
ResourceDestroyed,
ChildAdded,
ChildRemoved,
Renamed,
// Event Invoke
PropertyUpdated = 0x10,
EventOccurred,
// Attribute
AttributesUpdated = 0x18
}
public enum IIPPacketAction : byte
{
// Request Manage
AttachResource = 0,
ReattachResource,
DetachResource,
CreateResource,
DeleteResource,
AddChild,
RemoveChild,
RenameResource,
// Request Inquire
TemplateFromClassName = 0x8,
TemplateFromClassId,
TemplateFromResourceId,
QueryLink,
ResourceHistory,
ResourceChildren,
ResourceParents,
// Request Invoke
InvokeFunctionArrayArguments = 0x10,
GetProperty,
GetPropertyIfModified,
SetProperty,
InvokeFunctionNamedArguments,
// Request Attribute
GetAllAttributes = 0x18,
UpdateAllAttributes,
ClearAllAttributes,
GetAttributes,
UpdateAttributes,
ClearAttributes
}
public enum IIPPacketReport : byte
{
ManagementError,
ExecutionError,
ProgressReport = 0x8,
ChunkStream = 0x9
}
public IIPPacketReport Report
{
get;
set;
}
public IIPPacketCommand Command
{
get;
set;
}
public IIPPacketAction Action
{
get;
set;
}
public IIPPacketEvent Event
{
get;
set;
}
public IIPPacketCommand PreviousCommand
{
get;
set;
}
public IIPPacketAction PreviousAction
{
get;
set;
}
public IIPPacketEvent PreviousEvent
{
get;
set;
}
public uint ResourceId { get; set; }
public uint NewResourceId { get; set; }
//public uint ParentId { get; set; }
public uint ChildId { get; set; }
public uint StoreId { get; set; }
public ulong ResourceAge { get; set; }
public byte[] Content { get; set; }
public ushort ErrorCode { get; set; }
public string ErrorMessage { get; set; }
public string ClassName { get; set; }
public string ResourceLink { get; set; }
public Guid ClassId { get; set; }
public byte MethodIndex { get; set; }
public string MethodName { get; set; }
public uint CallbackId { get; set; }
public int ProgressValue { get; set; }
public int ProgressMax { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public ulong FromAge { get; set; }
public ulong ToAge { get; set; }
private uint dataLengthNeeded;
private uint originalOffset;
public override bool Compose()
{
return base.Compose();
}
bool NotEnough(uint offset, uint ends, uint needed)
{
if (offset + needed > ends)
{
dataLengthNeeded = needed - (ends - offset);
//dataLengthNeeded = needed - (ends - originalOffset);
return true;
}
else
return false;
}
public override long Parse(byte[] data, uint offset, uint ends)
{
originalOffset = offset;
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
PreviousCommand = Command;
Command = (IIPPacketCommand)(data[offset] >> 6);
if (Command == IIPPacketCommand.Event)
{
Event = (IIPPacketEvent)(data[offset++] & 0x3f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Command == IIPPacketCommand.Report)
{
Report = (IIPPacketReport)(data[offset++] & 0x3f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset);
offset += 4;
}
else
{
PreviousAction = Action;
Action = (IIPPacketAction)(data[offset++] & 0x3f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset);
offset += 4;
}
if (Command == IIPPacketCommand.Event)
{
if (Event == IIPPacketEvent.ResourceReassigned)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
NewResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Event == IIPPacketEvent.ResourceDestroyed)
{
// nothing to parse
}
else if (Event == IIPPacketEvent.ChildAdded
|| Event == IIPPacketEvent.ChildRemoved)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ChildId = data.GetUInt32(offset);
offset += 4;
}
else if (Event == IIPPacketEvent.Renamed)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Event == IIPPacketEvent.PropertyUpdated)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
MethodIndex = data[offset++];
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
else if (Event == IIPPacketEvent.EventOccurred)
{
if (NotEnough(offset, ends, 5))
return -dataLengthNeeded;
MethodIndex = data[offset++];
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
// Attribute
else if (Event == IIPPacketEvent.AttributesUpdated)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
}
else if (Command == IIPPacketCommand.Request)
{
if (Action == IIPPacketAction.AttachResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.ReattachResource)
{
if (NotEnough(offset, ends, 12))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
ResourceAge = data.GetUInt64(offset);
offset += 8;
}
else if (Action == IIPPacketAction.DetachResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.CreateResource)
{
if (NotEnough(offset, ends, 12))
return -dataLengthNeeded;
StoreId = data.GetUInt32(offset);
offset += 4;
ResourceId = data.GetUInt32(offset);
offset += 4;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
this.Content = data.Clip(offset, cl);
}
else if (Action == IIPPacketAction.DeleteResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.AddChild
|| Action == IIPPacketAction.RemoveChild)
{
if (NotEnough(offset, ends, 8))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
ChildId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.RenameResource)
{
if (NotEnough(offset, ends, 6))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.TemplateFromClassName)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var cl = data[offset++];
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ClassName = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.TemplateFromClassId)
{
if (NotEnough(offset, ends, 16))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
}
else if (Action == IIPPacketAction.TemplateFromResourceId)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.QueryLink)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ResourceLink = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.ResourceChildren
|| Action == IIPPacketAction.ResourceParents)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.ResourceHistory)
{
if (NotEnough(offset, ends, 20))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
FromDate = data.GetDateTime(offset);
offset += 8;
ToDate = data.GetDateTime(offset);
offset += 8;
}
else if (Action == IIPPacketAction.InvokeFunctionArrayArguments
|| Action == IIPPacketAction.InvokeFunctionNamedArguments)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.GetProperty)
{
if (NotEnough(offset, ends, 5))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
}
else if (Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
ResourceAge = data.GetUInt64(offset);
offset += 8;
}
else if (Action == IIPPacketAction.SetProperty)
{
if (NotEnough(offset, ends, 6))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
// Attributes
else if (Action == IIPPacketAction.UpdateAllAttributes
|| Action == IIPPacketAction.GetAttributes
|| Action == IIPPacketAction.UpdateAttributes
|| Action == IIPPacketAction.ClearAttributes)
{
if (NotEnough(offset, ends, 8))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
}
else if (Command == IIPPacketCommand.Reply)
{
if (Action == IIPPacketAction.AttachResource
|| Action == IIPPacketAction.ReattachResource)
{
if (NotEnough(offset, ends, 26))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
ResourceAge = data.GetUInt64(offset);
offset += 8;
uint cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ResourceLink = data.GetString(offset, cl);
offset += cl;
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.DetachResource)
{
// nothing to do
}
else if (Action == IIPPacketAction.CreateResource)
{
if (NotEnough(offset, ends, 20))
return -dataLengthNeeded;
//ClassId = data.GetGuid(offset);
//offset += 16;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.DetachResource)
{
// nothing to do
}
// Inquire
else if (Action == IIPPacketAction.TemplateFromClassName
|| Action == IIPPacketAction.TemplateFromClassId
|| Action == IIPPacketAction.TemplateFromResourceId
|| Action == IIPPacketAction.QueryLink
|| Action == IIPPacketAction.ResourceChildren
|| Action == IIPPacketAction.ResourceParents
|| Action == IIPPacketAction.ResourceHistory
// Attribute
|| Action == IIPPacketAction.GetAllAttributes
|| Action == IIPPacketAction.GetAttributes)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.InvokeFunctionArrayArguments
|| Action == IIPPacketAction.InvokeFunctionNamedArguments
|| Action == IIPPacketAction.GetProperty
|| Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
else if (Action == IIPPacketAction.SetProperty)
{
// nothing to do
}
}
else if (Command == IIPPacketCommand.Report)
{
if (Report == IIPPacketReport.ManagementError)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
ErrorCode = data.GetUInt16(offset);
offset += 2;
}
else if (Report == IIPPacketReport.ExecutionError)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
ErrorCode = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ErrorMessage = data.GetString(offset, cl);
offset += cl;
}
else if (Report == IIPPacketReport.ProgressReport)
{
if (NotEnough(offset, ends, 8))
return -dataLengthNeeded;
ProgressValue = data.GetInt32(offset);
offset += 4;
ProgressMax = data.GetInt32(offset);
offset += 4;
}
else if (Report == IIPPacketReport.ChunkStream)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
}
return offset - originalOffset;
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
struct IIPPacketAttachInfo
{
public string Link;
public ulong Age;
public byte[] Content;
public Guid ClassId;
public IIPPacketAttachInfo(Guid classId, ulong age, string link, byte[] content)
{
ClassId = classId;
Age = age;
Content = content;
Link = link;
}
}
}

369
Esiur/Net/Packets/Packet.cs Normal file
View File

@ -0,0 +1,369 @@
/********************************************************************************\
* Uruky Project *
* *
* Copyright (C) 2006 Ahmed Zamil - ahmed@dijlh.com *
* http://www.dijlh.com *
* *
* 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. *
* *
* File: Packet.cs *
* Description: Ethernet/ARP/IPv4/TCP/UDP Packet Decoding & Encoding Class *
* Compatibility: .Net Framework 2.0 / Mono 1.1.8 *
* *
\********************************************************************************/
using System;
using System.Text;
using Esiur.Misc;
using Esiur.Net.DataLink;
using System.Net.NetworkInformation;
using Esiur.Data;
namespace Esiur.Net.Packets
{
internal static class Functions
{
public static void AddData(ref byte[] dest, byte[] src)
{
int I = 0;
if (src == null)
{
return;
}
if (dest != null)
{
I = dest.Length;
Array.Resize(ref dest, dest.Length + src.Length);
//dest = (byte[])Resize(dest, dest.Length + src.Length);
}
else
{
dest = new byte[src.Length];
}
Array.Copy(src, 0, dest, I, src.Length);
}
/*
public static Array Resize(Array array, int newSize)
{
Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']'));
Array nA = Array.CreateInstance(myType, newSize);
Array.Copy(array, nA, (newSize > array.Length ? array.Length : newSize));
return nA;
} */
//Computes the checksum used in IP, ARP..., ie the
// "The 16 bit one's complement of the one 's complement sum
//of all 16 bit words" as seen in RFCs
// Returns a 4 characters hex string
// data's lenght must be multiple of 4, else zero padding
public static ushort IP_CRC16(byte[] data)
{
ulong Sum = 0;
bool Padding = false;
/// * Padding if needed
if (data.Length % 2 != 0)
{
Array.Resize(ref data, data.Length + 1);
//data = (byte[])Resize(data, data.Length + 1);
Padding = true;
}
int count = data.Length;
///* add 16-bit words */
while (count > 0) //1)
{
///* this is the inner loop */
Sum += GetInteger(data[count - 2], data[count - 1]);
///* Fold 32-bit sum to 16-bit */
while (Sum >> 16 != 0)
{
Sum = (Sum & 0XFFFF) + (Sum >> 16);
}
count -= 2;
}
/// * reverse padding
if (Padding)
{
Array.Resize(ref data, data.Length - 1);
//data = (byte[])Resize(data, data.Length - 1);
}
///* Return one's compliment of final sum.
//return (ushort)(ushort.MaxValue - (ushort)Sum);
return (ushort)(~Sum);
}
public static ushort GetInteger(byte B1, byte B2)
{
return BitConverter.ToUInt16(new byte[] { B2, B1 }, 0);
//return System.Convert.ToUInt16("&h" + GetHex(B1) + GetHex(B2));
}
public static uint GetLong(byte B1, byte B2, byte B3, byte B4)
{
return BitConverter.ToUInt32(new byte[] { B4, B3, B2, B1 }, 0);
//return System.Convert.ToUInt32("&h" + GetHex(B1) + GetHex(B2) + GetHex(B3) + GetHex(B4));
}
public static string GetHex(byte B)
{
return (((B < 15) ? 0 + System.Convert.ToString(B, 16).ToUpper() : System.Convert.ToString(B, 16).ToUpper()));
}
public static bool GetBit(uint B, byte Pos)
{
//return BitConverter.ToBoolean(BitConverter.GetBytes(B), Pos + 1);
return (B & (uint)(Math.Pow(2, (Pos - 1)))) == (Math.Pow(2, (Pos - 1)));
}
public static ushort RemoveBit(ushort I, byte Pos)
{
return (ushort)RemoveBit((uint)I, Pos);
}
public static uint RemoveBit(uint I, byte Pos)
{
if (GetBit(I, Pos))
{
return I - (uint)(Math.Pow(2, (Pos - 1)));
}
else
{
return I;
}
}
public static void SplitInteger(ushort I, ref byte BLeft, ref byte BRight)
{
byte[] b = BitConverter.GetBytes(I);
BLeft = b[1];
BRight = b[0];
//BLeft = I >> 8;
//BRight = (I << 8) >> 8;
}
public static void SplitLong(uint I, ref byte BLeft, ref byte BLeftMiddle, ref byte BRightMiddle, ref byte BRight)
{
byte[] b = BitConverter.GetBytes(I);
BLeft = b[3];
BLeftMiddle = b[2];
BRightMiddle = b[1];
BRight = b[0];
//BLeft = I >> 24;
//BLeftMiddle = (I << 8) >> 24;
//BRightMiddle = (I << 16) >> 24;
//BRight = (I << 24) >> 24;
}
}
public class PosixTime
{
ulong seconds;
ulong microseconds;
PosixTime(ulong Seconds, ulong Microseconds)
{
seconds = Seconds;
microseconds = Microseconds;
}
public override string ToString()
{
return seconds + "." + microseconds;
}
}
public class Packet
{
//public EtherServer2.EthernetSource Source;
public PacketSource Source;
public DateTime Timestamp;
public enum PPPType : ushort
{
IP = 0x0021, // Internet Protocol version 4 [RFC1332]
SDTP = 0x0049, // Serial Data Transport Protocol (PPP-SDTP) [RFC1963]
IPv6HeaderCompression = 0x004f, // IPv6 Header Compression
IPv6 = 0x0057, // Internet Protocol version 6 [RFC5072]
W8021dHelloPacket = 0x0201, // 802.1d Hello Packets [RFC3518]
IPv6ControlProtocol = 0x8057, // IPv6 Control Protocol [RFC5072]
}
public enum ProtocolType : ushort
{
IP = 0x800, // IPv4
ARP = 0x806, // Address Resolution Protocol
IPv6 = 0x86DD, // IPv6
FrameRelayARP = 0x0808, // Frame Relay ARP [RFC1701]
VINESLoopback = 0x0BAE, // VINES Loopback [RFC1701]
VINESEcho = 0x0BAF, // VINES ECHO [RFC1701]
TransEtherBridging = 0x6558, // TransEther Bridging [RFC1701]
RawFrameRelay = 0x6559, // Raw Frame Relay [RFC1701]
IEE8021QVLAN = 0x8100, // IEEE 802.1Q VLAN-tagged frames (initially Wellfleet)
SNMP = 0x814C, // SNMP [JKR1]
TCPIP_Compression = 0x876B, // TCP/IP Compression [RFC1144]
IPAutonomousSystems = 0x876C, // IP Autonomous Systems [RFC1701]
SecureData = 0x876D, // Secure Data [RFC1701]
PPP = 0x880B, // PPP [IANA]
MPLS = 0x8847, // MPLS [RFC5332]
MPLS_UpstreamAssignedLabel = 0x8848, // MPLS with upstream-assigned label [RFC5332]
PPPoEDiscoveryStage = 0x8863, // PPPoE Discovery Stage [RFC2516]
PPPoESessionStage = 0x8864, // PPPoE Session Stage [RFC2516]
}
/*
public static void GetPacketMACAddresses(Packet packet, out byte[] srcMAC, out byte[] dstMAC)
{
// get the node address
Packet root = packet.RootPacket;
if (root is TZSPPacket)
{
TZSPPacket tp = (TZSPPacket)root;
if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet)
{
EthernetPacket ep = (EthernetPacket)tp.SubPacket;
srcMAC = ep.SourceMAC;
dstMAC = ep.DestinationMAC;
}
else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11)
{
W802_11Packet wp = (W802_11Packet)tp.SubPacket;
srcMAC = wp.SA;
dstMAC = wp.DA;
}
else
{
srcMAC = null;
dstMAC = null;
}
}
else if (root is EthernetPacket)
{
EthernetPacket ep = (EthernetPacket)root;
srcMAC = ep.SourceMAC;
dstMAC = ep.DestinationMAC;
}
else if (root is W802_11Packet)
{
W802_11Packet wp = (W802_11Packet)root;
srcMAC = wp.SA;
dstMAC = wp.DA;
}
else
{
srcMAC = null;
dstMAC = null;
}
}
public static void GetPacketAddresses(Packet packet, ref string srcMAC, ref string dstMAC, ref string srcIP, ref string dstIP)
{
if (packet is TCPv4Packet)
{
if (packet.ParentPacket is IPv4Packet)
{
IPv4Packet ip = (IPv4Packet)packet.ParentPacket;
srcIP = ip.SourceIP.ToString();
dstIP = ip.DestinationIP.ToString();
}
}
// get the node address
Packet root = packet.RootPacket;
if (root is TZSPPacket)
{
TZSPPacket tp = (TZSPPacket)root;
if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet)
{
EthernetPacket ep = (EthernetPacket)tp.SubPacket;
srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString();
}
else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11)
{
W802_11Packet wp = (W802_11Packet)tp.SubPacket;
srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
}
}
else if (root is EthernetPacket)
{
EthernetPacket ep = (EthernetPacket)root;
srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString();
}
else if (root is W802_11Packet)
{
W802_11Packet wp = (W802_11Packet)root;
srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
}
}
*/
PosixTime Timeval;
public byte[] Header;
public byte[] Preamble;
//public byte[] Payload;
public byte[] Data;
public Packet SubPacket;
public Packet ParentPacket;
public virtual long Parse(byte[] data, uint offset, uint ends) { return 0; }
public virtual bool Compose() { return false; }
public Packet RootPacket
{
get
{
Packet root = this;
while (root.ParentPacket != null)
root = root.ParentPacket;
return root;
}
}
public Packet LeafPacket
{
get
{
Packet leaf = this;
while (leaf.SubPacket != null)
leaf = leaf.SubPacket;
return leaf;
}
}
}
}
/************************************ EOF *************************************/

View File

@ -0,0 +1,217 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets
{
public class WebsocketPacket : Packet
{
public enum WSOpcode : byte
{
ContinuationFrame = 0x0, // %x0 denotes a continuation frame
TextFrame = 0x1, // %x1 denotes a text frame
BinaryFrame = 0x2, // %x2 denotes a binary frame
// %x3-7 are reserved for further non-control frames
ConnectionClose = 0x8, // %x8 denotes a connection close
Ping = 0x9, // %x9 denotes a ping
Pong = 0xA, // %xA denotes a pong
//* %xB-F are reserved for further control frames
}
public bool FIN;
public bool RSV1;
public bool RSV2;
public bool RSV3;
public WSOpcode Opcode;
public bool Mask;
public long PayloadLength;
// public UInt32 MaskKey;
public byte[] MaskKey;
public byte[] Message;
public override string ToString()
{
return "WebsocketPacket"
+ "\n\tFIN: " + FIN
+ "\n\tOpcode: " + Opcode
+ "\n\tPayload: " + PayloadLength
+ "\n\tMaskKey: " + MaskKey
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
public override bool Compose()
{
var pkt = new List<byte>();
pkt.Add((byte)((FIN ? 0x80 : 0x0) |
(RSV1 ? 0x40 : 0x0) |
(RSV2 ? 0x20 : 0x0) |
(RSV3 ? 0x10 : 0x0) |
(byte)Opcode));
// calculate length
if (Message.Length > UInt16.MaxValue)
// 4 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127));
pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount()));
}
else if (Message.Length > 125)
// 2 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126));
pkt.AddRange(DC.ToBytes((UInt16)Message.Length));
}
else
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | Message.Length));
}
if (Mask)
{
pkt.AddRange(MaskKey);
}
pkt.AddRange(Message);
Data = pkt.ToArray();
return true;
}
public override long Parse(byte[] data, uint offset, uint ends)
{
try
{
long needed = 2;
var length = (ends - offset);
if (length < needed)
{
//Console.WriteLine("stage 1 " + needed);
return length - needed;
}
uint oOffset = offset;
FIN = ((data[offset] & 0x80) == 0x80);
RSV1 = ((data[offset] & 0x40) == 0x40);
RSV2 = ((data[offset] & 0x20) == 0x20);
RSV3 = ((data[offset] & 0x10) == 0x10);
Opcode = (WSOpcode)(data[offset++] & 0xF);
Mask = ((data[offset] & 0x80) == 0x80);
PayloadLength = (long)(data[offset++] & 0x7F);
if (Mask)
needed += 4;
if (PayloadLength == 126)
{
needed += 2;
if (length < needed)
{
//Console.WriteLine("stage 2 " + needed);
return length - needed;
}
PayloadLength = DC.GetUInt16(data, offset);
offset += 2;
}
else if (PayloadLength == 127)
{
needed += 8;
if (length < needed)
{
//Console.WriteLine("stage 3 " + needed);
return length - needed;
}
PayloadLength = DC.GetInt64(data, offset);
offset += 8;
}
/*
if (Mask)
{
MaskKey = new byte[4];
MaskKey[0] = data[offset++];
MaskKey[1] = data[offset++];
MaskKey[2] = data[offset++];
MaskKey[3] = data[offset++];
//MaskKey = DC.GetUInt32(data, offset);
//offset += 4;
}
*/
needed += PayloadLength;
if (length < needed)
{
//Console.WriteLine("stage 4");
return length - needed;
}
else
{
if (Mask)
{
MaskKey = new byte[4];
MaskKey[0] = data[offset++];
MaskKey[1] = data[offset++];
MaskKey[2] = data[offset++];
MaskKey[3] = data[offset++];
Message = DC.Clip(data, offset, (uint)PayloadLength);
//var aMask = BitConverter.GetBytes(MaskKey);
for (int i = 0; i < Message.Length; i++)
Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]);
}
else
Message = DC.Clip(data, offset, (uint)PayloadLength);
return (offset - oOffset) + (int)PayloadLength;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine(offset + "::" + DC.ToHex(data));
throw ex;
}
}
}
}

26
Esiur/Net/SendList.cs Normal file
View File

@ -0,0 +1,26 @@
using Esiur.Core;
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net
{
public class SendList : BinaryList
{
NetworkConnection connection;
AsyncReply<object[]> reply;
public SendList(NetworkConnection connection, AsyncReply<object[]> reply)
{
this.reply = reply;
this.connection = connection;
}
public override AsyncReply<object[]> Done()
{
connection.Send(this.ToArray());
return reply;
}
}
}

View File

@ -0,0 +1,74 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using System.Collections.Concurrent;
using Esiur.Resource;
using Esiur.Core;
namespace Esiur.Net.Sockets
{
//public delegate void ISocketReceiveEvent(NetworkBuffer buffer);
//public delegate void ISocketConnectEvent();
//public delegate void ISocketCloseEvent();
public interface ISocket : IDestructible
{
SocketState State { get; }
//event ISocketReceiveEvent OnReceive;
//event ISocketConnectEvent OnConnect;
//event ISocketCloseEvent OnClose;
INetworkReceiver<ISocket> Receiver { get; set; }
AsyncReply<bool> SendAsync(byte[] message, int offset, int length);
void Send(byte[] message);
void Send(byte[] message, int offset, int length);
void Close();
AsyncReply<bool> Connect(string hostname, ushort port);
bool Begin();
AsyncReply<bool> BeginAsync();
//ISocket Accept();
AsyncReply<ISocket> AcceptAsync();
ISocket Accept();
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
void Hold();
void Unhold();
}
}

View File

@ -0,0 +1,555 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Core;
using System.Threading;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Esiur.Resource;
using System.Threading.Tasks;
using Esiur.Data;
namespace Esiur.Net.Sockets
{
public class SSLSocket : ISocket
{
public INetworkReceiver<ISocket> Receiver { get; set; }
Socket sock;
byte[] receiveBuffer;
bool held;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
bool asyncSending;
bool began = false;
SocketState state = SocketState.Initial;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
SslStream ssl;
X509Certificate2 cert;
bool server;
string hostname;
public async AsyncReply<bool> Connect(string hostname, ushort port)
{
var rt = new AsyncReply<bool>();
this.hostname = hostname;
this.server = false;
state = SocketState.Connecting;
await sock.ConnectAsync(hostname, port);
try
{
await BeginAsync();
state = SocketState.Established;
//OnConnect?.Invoke();
Receiver?.NetworkConnect(this);
}
catch (Exception ex)
{
state = SocketState.Closed;// .Terminated;
Close();
Global.Log(ex);
}
return true;
}
//private void DataSent(Task task)
//{
// try
// {
// if (sendBufferQueue.Count > 0)
// {
// byte[] data = sendBufferQueue.Dequeue();
// lock (sendLock)
// ssl.WriteAsync(data, 0, data.Length).ContinueWith(DataSent);
// }
// else
// {
// asyncSending = false;
// }
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// asyncSending = false;
// Global.Log("SSLSocket", LogType.Error, ex.ToString());
// }
//}
private void SendCallback(IAsyncResult ar)
{
if (ar != null)
{
try
{
ssl.EndWrite(ar);
if (ar.AsyncState != null)
((AsyncReply<bool>)ar.AsyncState).Trigger(true);
}
catch
{
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Closed;//.Terminated;
Close();
}
}
}
lock (sendLock)
{
if (sendBufferQueue.Count > 0)
{
var kv = sendBufferQueue.Dequeue();
try
{
ssl.BeginWrite(kv.Value, 0, kv.Value.Length, SendCallback, kv.Key);
}
catch (Exception ex)
{
asyncSending = false;
try
{
if (kv.Key != null)
kv.Key.Trigger(false);
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Terminated;
Close();
}
}
catch (Exception ex2)
{
//state = SocketState.Closed;// .Terminated;
Close();
}
//Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
else
{
asyncSending = false;
}
}
}
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public SSLSocket()
{
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
}
public SSLSocket(IPEndPoint localEndPoint, X509Certificate2 certificate)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
state = SocketState.Listening;
// bind
sock.Bind(localEndPoint);
// start listening
sock.Listen(UInt16.MaxValue);
cert = certificate;
}
public IPEndPoint RemoteEndPoint
{
get { return (IPEndPoint)sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return state;
}
}
public SSLSocket(Socket socket, X509Certificate2 certificate, bool authenticateAsServer)
{
cert = certificate;
sock = socket;
receiveBuffer = new byte[sock.ReceiveBufferSize];
ssl = new SslStream(new NetworkStream(sock));
server = authenticateAsServer;
if (socket.Connected)
state = SocketState.Established;
}
public void Close()
{
if (state != SocketState.Closed)// && state != SocketState.Terminated)
{
state = SocketState.Closed;
if (sock.Connected)
{
try
{
sock.Shutdown(SocketShutdown.Both);
}
catch
{
//state = SocketState.Terminated;
}
}
Receiver?.NetworkClose(this);
//OnClose?.Invoke();
}
}
public void Send(byte[] message)
{
Send(message, 0, message.Length);
}
public void Send(byte[] message, int offset, int size)
{
var msg = message.Clip((uint)offset, (uint)size);
lock (sendLock)
{
if (!sock.Connected)
return;
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size));
}
else
{
asyncSending = true;
try
{
ssl.BeginWrite(msg, 0, msg.Length, SendCallback, null);
}
catch
{
asyncSending = false;
//state = SocketState.Terminated;
Close();
}
}
}
}
//public void Send(byte[] message)
//{
// Send(message, 0, message.Length);
//}
//public void Send(byte[] message, int offset, int size)
//{
// lock (sendLock)
// {
// if (asyncSending)
// {
// sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size));
// }
// else
// {
// asyncSending = true;
// ssl.WriteAsync(message, offset, size).ContinueWith(DataSent);
// }
// }
//}
//private void DataReceived(Task<int> task)
//{
// try
// {
// if (state == SocketState.Closed || state == SocketState.Terminated)
// return;
// if (task.Result <= 0)
// {
// Close();
// return;
// }
// receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result);
// OnReceive?.Invoke(receiveNetworkBuffer);
// if (state == SocketState.Established)
// ssl.ReadAsync(receiveBuffer, 0, receiveBuffer.Length).ContinueWith(DataReceived);
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// Global.Log("SSLSocket", LogType.Error, ex.ToString());
// }
//}
public bool Begin()
{
if (began)
return false;
began = true;
if (server)
ssl.AuthenticateAsServer(cert);
else
ssl.AuthenticateAsClient(hostname);
if (state == SocketState.Established)
{
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
return true;
}
else
return false;
}
public async AsyncReply<bool> BeginAsync()
{
if (began)
return false;
began = true;
if (server)
await ssl.AuthenticateAsServerAsync(cert);
else
await ssl.AuthenticateAsClientAsync(hostname);
if (state == SocketState.Established)
{
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
return true;
}
else
return false;
}
private void ReceiveCallback(IAsyncResult results)
{
try
{
if (state != SocketState.Established)
return;
var bytesReceived = ssl.EndRead(results);
if (bytesReceived <= 0)
{
Close();
return;
}
receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)bytesReceived);
//OnReceive?.Invoke(receiveNetworkBuffer);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
}
catch (Exception ex)
{
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Terminated;
Close();
}
//Global.Log("SSLSocket", LogType.Error, ex.ToString());
}
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
Receiver = null;
receiveNetworkBuffer = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public async AsyncReply<ISocket> AcceptAsync()
{
try
{
var s = await sock.AcceptAsync();
return new SSLSocket(s, cert, true);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public void Hold()
{
held = true;
}
public void Unhold()
{
try
{
SendCallback(null);
}
catch (Exception ex)
{
Global.Log(ex);
}
finally
{
held = false;
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
var msg = message.Clip((uint)offset, (uint)length);
lock (sendLock)
{
if (!sock.Connected)
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>();
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(rt, msg));
}
else
{
asyncSending = true;
try
{
ssl.BeginWrite(msg, 0, msg.Length, SendCallback, rt);// null);
}
catch (Exception ex)
{
rt.TriggerError(ex);
asyncSending = false;
//state = SocketState.Terminated;
Close();
}
}
return rt;
}
}
public ISocket Accept()
{
try
{
return new SSLSocket(sock.Accept(), cert, true);
}
catch
{
state = SocketState.Closed;// .Terminated;
return null;
}
}
}
}

View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Sockets
{
public enum SocketState
{
Initial,
Listening,
Connecting,
Established,
Closed,
//Terminated
}
}

View File

@ -0,0 +1,659 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Core;
using System.Threading;
using Esiur.Resource;
using System.Threading.Tasks;
using Esiur.Data;
namespace Esiur.Net.Sockets
{
public class TCPSocket : ISocket
{
public INetworkReceiver<ISocket> Receiver { get; set; }
Socket sock;
byte[] receiveBuffer;
bool held;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
bool asyncSending;
bool began = false;
SocketState state = SocketState.Initial;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
//SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();
private AsyncCallback receiveCallback;
private AsyncCallback sendCallback;
public AsyncReply<bool> BeginAsync()
{
return new AsyncReply<bool>(Begin());
}
private AsyncReply<bool> currentReply = null;
public bool Begin()
{
if (began)
return false;
began = true;
/*
socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
socketArgs.Completed += SocketArgs_Completed;
if (!sock.ReceiveAsync(socketArgs))
SocketArgs_Completed(null, socketArgs);
*/
receiveCallback = new AsyncCallback(ReceiveCallback);
sendCallback = new AsyncCallback(SendCallback);
sock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, receiveCallback, this);
//sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived);
return true;
}
private static void ReceiveCallback(IAsyncResult ar)
{
var socket = ar.AsyncState as TCPSocket;
try
{
if (socket.state != SocketState.Established)
return;
var recCount = socket.sock.EndReceive(ar);
if (recCount > 0)
{
socket.receiveNetworkBuffer.Write(socket.receiveBuffer, 0, (uint)recCount);
socket.Receiver?.NetworkReceive(socket, socket.receiveNetworkBuffer);
if (socket.state == SocketState.Established)
socket.sock.BeginReceive(socket.receiveBuffer, 0, socket.receiveBuffer.Length, SocketFlags.None, socket.receiveCallback, socket);
}
else
{
socket.Close();
return;
}
}
catch (Exception ex)
{
if (socket.state != SocketState.Closed && !socket.sock.Connected)
{
//socket.state = SocketState.Terminated;
socket.Close();
}
//Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
public AsyncReply<bool> Connect(string hostname, ushort port)
{
var rt = new AsyncReply<bool>();
try
{
state = SocketState.Connecting;
sock.ConnectAsync(hostname, port).ContinueWith((x) =>
{
if (x.IsFaulted)
rt.TriggerError(x.Exception);
else
{
state = SocketState.Established;
//OnConnect?.Invoke();
Receiver?.NetworkConnect(this);
Begin();
rt.Trigger(true);
}
});
}
catch (Exception ex)
{
rt.TriggerError(ex);
}
return rt;
}
//private void DataReceived(Task<int> task)
//{
// try
// {
// // SocketError err;
// if (state == SocketState.Closed || state == SocketState.Terminated)
// return;
// if (task.Result <= 0)
// {
// Close();
// return;
// }
// receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result);
// //OnReceive?.Invoke(receiveNetworkBuffer);
// Receiver?.NetworkReceive(this, receiveNetworkBuffer);
// if (state == SocketState.Established)
// sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived);
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// Global.Log("TCPSocket", LogType.Error, ex.ToString());
// }
//}
//private void SocketArgs_Completed(object sender, SocketAsyncEventArgs e)
//{
// try
// {
// if (state != SocketState.Established)
// return;
// if (e.BytesTransferred <= 0)
// {
// Close();
// return;
// }
// else if (e.SocketError != SocketError.Success)
// {
// Close();
// return;
// }
// var recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred;
// receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount);
// //OnReceive?.Invoke(receiveNetworkBuffer);
// Receiver?.NetworkReceive(this, receiveNetworkBuffer);
// if (state == SocketState.Established)
// while (!sock.ReceiveAsync(e))
// {
// if (e.SocketError != SocketError.Success)
// {
// Close();
// return;
// }
// if (State != SocketState.Established)
// return;
// //if (e.BytesTransferred < 0)
// // Console.WriteLine("BytesTransferred is less than zero");
// if (e.BytesTransferred <= 0)
// {
// Close();
// return;
// }
// else if (e.SocketError != SocketError.Success)
// {
// Close();
// return;
// }
// //if (e.BytesTransferred > 100000)
// // Console.WriteLine("BytesTransferred is large " + e.BytesTransferred);
// recCount = e.BytesTransferred > e.Count ? e.Count : e.BytesTransferred;
// receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)recCount);
// //OnReceive?.Invoke(receiveNetworkBuffer);
// Receiver?.NetworkReceive(this, receiveNetworkBuffer);
// }
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// Global.Log("TCPSocket", LogType.Error, ex.ToString());
// }
//}
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public TCPSocket()
{
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
//receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
}
public TCPSocket(string hostname, ushort port)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
//receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
Connect(hostname, port);
}
//private void DataSent(Task<int> task)
//{
// try
// {
// lock (sendLock)
// {
// if (sendBufferQueue.Count > 0)
// {
// byte[] data = sendBufferQueue.Dequeue();
// //Console.WriteLine(Encoding.UTF8.GetString(data));
// sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None).ContinueWith(DataSent);
// }
// else
// {
// asyncSending = false;
// }
// }
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// asyncSending = false;
// Global.Log("TCPSocket", LogType.Error, ex.ToString());
// }
//}
public TCPSocket(IPEndPoint localEndPoint)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
state = SocketState.Listening;
// bind
sock.Bind(localEndPoint);
// start listening
sock.Listen(UInt16.MaxValue);
}
public IPEndPoint RemoteEndPoint
{
get { return (IPEndPoint)sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return state;
}
}
public TCPSocket(Socket socket)
{
sock = socket;
receiveBuffer = new byte[sock.ReceiveBufferSize];
// receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
if (socket.Connected)
state = SocketState.Established;
}
public void Close()
{
if (state != SocketState.Closed)// && state != SocketState.Terminated)
{
state = SocketState.Closed;
if (sock.Connected)
{
try
{
sock.Shutdown(SocketShutdown.Both);
}
catch
{
}
}
try
{
sendBufferQueue?.Clear();
Receiver?.NetworkClose(this);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
}
public void Send(byte[] message)
{
Send(message, 0, message.Length);
}
public void Send(byte[] message, int offset, int size)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return;
var msg = message.Clip((uint)offset, (uint)size);
lock (sendLock)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return;
if (!sock.Connected)
return;
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size));
}
else
{
asyncSending = true;
try
{
sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this);
}
catch
{
asyncSending = false;
//state = SocketState.Closed;//.Terminated;
Close();
}
//sock.SendAsync(new ArraySegment<byte>(msg), SocketFlags.None).ContinueWith(DataSent);
}
}
}
private static void Flush(TCPSocket socket)
{
lock (socket.sendLock)
{
socket.currentReply?.Trigger(true);
socket.currentReply = null;
if (socket.state == SocketState.Closed) //|| socket.state == SocketState.Terminated)
return;
if (socket.sendBufferQueue.Count > 0)
{
var kv = socket.sendBufferQueue.Dequeue();
try
{
socket.currentReply = kv.Key;
socket.sock.BeginSend(kv.Value, 0, kv.Value.Length, SocketFlags.None,
socket.sendCallback, socket);
}
catch (Exception ex)
{
socket.asyncSending = false;
try
{
kv.Key?.Trigger(false);
if (socket.state != SocketState.Closed && !socket.sock.Connected)
{
// socket.state = SocketState.Closed;// Terminated;
socket.Close();
}
}
catch (Exception ex2)
{
socket.Close();
//socket.state = SocketState.Closed;// .Terminated;
}
Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
else
{
socket.asyncSending = false;
}
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
var socket = (TCPSocket)ar.AsyncState;
socket.sock?.EndSend(ar);
Flush(socket);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Global.Counters["Sck_D_1"]++;
Close();
receiveNetworkBuffer = null;
receiveCallback = null;
sendCallback = null;
sock = null;
receiveBuffer = null;
receiveNetworkBuffer = null;
sendBufferQueue = null;
//socketArgs.Completed -= SocketArgs_Completed;
//socketArgs.Dispose();
//socketArgs = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
Global.Counters["Sck_D_2"]++;
}
public ISocket Accept()
{
try
{
var s = sock.Accept();
return new TCPSocket(s);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public async AsyncReply<ISocket> AcceptAsync()
{
try
{
var s = await sock.AcceptAsync();
return new TCPSocket(s);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public void Hold()
{
held = true;
}
public void Unhold()
{
try
{
Flush(this);
//SendCallback(null);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
held = false;
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return new AsyncReply<bool>(false);
var msg = message.Clip((uint)offset, (uint)length);
lock (sendLock)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return new AsyncReply<bool>(false);
if (!sock.Connected)
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>();
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(rt, msg));
}
else
{
asyncSending = true;
try
{
currentReply = rt;
sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, sendCallback, this);// null);
}
catch (Exception ex)
{
rt.TriggerError(ex);
asyncSending = false;
//state = SocketState.Terminated;
Close();
}
//sock.SendAsync(new ArraySegment<byte>(msg), SocketFlags.None).ContinueWith(DataSent);
}
return rt;
}
}
}
}

View File

@ -0,0 +1,363 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Net.Packets;
using Esiur.Misc;
using System.IO;
using Esiur.Core;
using Esiur.Resource;
using Esiur.Data;
using System.Globalization;
namespace Esiur.Net.Sockets
{
public class WSSocket : ISocket, INetworkReceiver<ISocket>
{
WebsocketPacket pkt_receive = new WebsocketPacket();
WebsocketPacket pkt_send = new WebsocketPacket();
ISocket sock;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
NetworkBuffer sendNetworkBuffer = new NetworkBuffer();
object sendLock = new object();
bool held;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
long totalSent, totalReceived;
bool processing = false;
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public IPEndPoint RemoteEndPoint
{
get { return sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return sock.State;
}
}
public INetworkReceiver<ISocket> Receiver { get; set; }
public WSSocket(ISocket socket)
{
pkt_send.FIN = true;
pkt_send.Mask = false;
pkt_send.Opcode = WebsocketPacket.WSOpcode.BinaryFrame;
sock = socket;
sock.Receiver = this;
//sock.OnClose += Sock_OnClose;
//sock.OnConnect += Sock_OnConnect;
//sock.OnReceive += Sock_OnReceive;
}
//private void Sock_OnReceive(NetworkBuffer buffer)
//{
//}
//private void Sock_OnConnect()
//{
// OnConnect?.Invoke();
//}
//private void Sock_OnClose()
//{
// OnClose?.Invoke();
//}
public void Send(WebsocketPacket packet)
{
lock (sendLock)
if (packet.Compose())
sock.Send(packet.Data);
}
public void Send(byte[] message)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message);
}
else
{
totalSent += message.Length;
//Console.WriteLine("TX " + message.Length +"/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size));
pkt_send.Message = message;
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}
}
public void Send(byte[] message, int offset, int size)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message, (uint)offset, (uint)size);
}
else
{
totalSent += size;
//Console.WriteLine("TX " + size + "/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size));
pkt_send.Message = new byte[size];
Buffer.BlockCopy(message, offset, pkt_send.Message, 0, size);
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}
}
public void Close()
{
sock?.Close();
}
public AsyncReply<bool> Connect(string hostname, ushort port)
{
throw new NotImplementedException();
}
public bool Begin()
{
return sock.Begin();
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
//OnClose = null;
//OnConnect = null;
//OnReceive = null;
receiveNetworkBuffer = null;
//sock.OnReceive -= Sock_OnReceive;
//sock.OnClose -= Sock_OnClose;
//sock.OnConnect -= Sock_OnConnect;
sock.Receiver = null;
sock = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public AsyncReply<ISocket> AcceptAsync()
{
throw new NotImplementedException();
}
public void Hold()
{
//Console.WriteLine("WS Hold ");
held = true;
}
public void Unhold()
{
lock (sendLock)
{
held = false;
var message = sendNetworkBuffer.Read();
//Console.WriteLine("WS Unhold {0}", message == null ? 0 : message.Length);
if (message == null)
return;
totalSent += message.Length;
pkt_send.Message = message;
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
throw new NotImplementedException();
}
public ISocket Accept()
{
throw new NotImplementedException();
}
public AsyncReply<bool> BeginAsync()
{
return sock.BeginAsync();
}
public void NetworkClose(ISocket sender)
{
Receiver?.NetworkClose(sender);
}
public void NetworkReceive(ISocket sender, NetworkBuffer buffer)
{
if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated)
return;
if (buffer.Protected)
return;
if (processing)
return;
var msg = buffer.Read();
if (msg == null)
return;
var wsPacketLength = pkt_receive.Parse(msg, 0, (uint)msg.Length);
//Console.WriteLine("WSP: " + wsPacketLength);
if (wsPacketLength < 0)
{
buffer.Protect(msg, 0, (uint)msg.Length + (uint)-wsPacketLength);
return;
}
uint offset = 0;
while (wsPacketLength > 0)
{
if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.ConnectionClose)
{
Close();
return;
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Ping)
{
var pkt_pong = new WebsocketPacket();
pkt_pong.FIN = true;
pkt_pong.Mask = false;
pkt_pong.Opcode = WebsocketPacket.WSOpcode.Pong;
pkt_pong.Message = pkt_receive.Message;
offset += (uint)wsPacketLength;
Send(pkt_pong);
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Pong)
{
offset += (uint)wsPacketLength;
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.BinaryFrame
|| pkt_receive.Opcode == WebsocketPacket.WSOpcode.TextFrame
|| pkt_receive.Opcode == WebsocketPacket.WSOpcode.ContinuationFrame)
{
totalReceived += pkt_receive.Message.Length;
//Console.WriteLine("RX " + pkt_receive.Message.Length + "/" + totalReceived);// + " " + DC.ToHex(message, 0, (uint)size));
receiveNetworkBuffer.Write(pkt_receive.Message);
offset += (uint)wsPacketLength;
//Console.WriteLine("WS IN: " + pkt_receive.Opcode.ToString() + " " + pkt_receive.Message.Length + " | " + offset + " " + string.Join(" ", pkt_receive.Message));// DC.ToHex(pkt_receive.Message));
}
else
Console.WriteLine("Unknown WS opcode:" + pkt_receive.Opcode);
if (offset == msg.Length)
{
//OnReceive?.Invoke(receiveNetworkBuffer);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
return;
}
wsPacketLength = pkt_receive.Parse(msg, offset, (uint)msg.Length);
}
if (wsPacketLength < 0)//(offset < msg.Length) && (offset > 0))
{
//receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)msg.Length + (uint)-wsPacketLength);
// save the incomplete packet to the heldBuffer queue
buffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength);
}
//Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available);
//OnReceive?.Invoke(receiveNetworkBuffer);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
processing = false;
if (buffer.Available > 0 && !buffer.Protected)
Receiver?.NetworkReceive(this, buffer);
//Sock_OnReceive(buffer);
}
public void NetworkConnect(ISocket sender)
{
Receiver?.NetworkConnect(this);
}
}
}

View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Net.Sockets;
using System.Net;
using System.Collections;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.TCP
{
public class TCPConnection:NetworkConnection {
private KeyList<string, object> variables = new KeyList<string, object>();
public TCPServer Server { get; internal set; }
public KeyList<string, object> Variables
{
get
{
return variables;
}
}
protected override void Connected()
{
// do nothing
}
protected override void DataReceived(NetworkBuffer buffer)
{
Server?.Execute(this, buffer);
}
protected override void Disconencted()
{
// do nothing
}
}
}

View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.TCP
{
public abstract class TCPFilter: IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public virtual bool Connected(TCPConnection sender)
{
return false;
}
public virtual bool Disconnected(TCPConnection sender)
{
return false;
}
public abstract bool Execute(byte[] msg, NetworkBuffer data, TCPConnection sender);
public void Destroy()
{
throw new NotImplementedException();
}
}
}

156
Esiur/Net/TCP/TCPServer.cs Normal file
View File

@ -0,0 +1,156 @@
/*
Copyright (c) 2017-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.Linq;
using System.Text;
using Esiur.Net.Sockets;
using Esiur.Misc;
using System.Threading;
using Esiur.Data;
using Esiur.Core;
using System.Net;
using Esiur.Resource;
namespace Esiur.Net.TCP
{
public class TCPServer : NetworkServer<TCPConnection>, IResource
{
[Attribute]
public string IP
{
get;
set;
}
[Attribute]
public ushort Port
{
get;
set;
}
//[Storable]
//public uint Timeout
//{
// get;
// set;
//}
//[Attribute]
//public uint Clock
//{
// get;
// set;
//}
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);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
Instance.Children<TCPFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(true);
}
internal bool Execute(TCPConnection sender, NetworkBuffer data)
{
var msg = data.Read();
foreach (var filter in filters)
{
if (filter.Execute(msg, data, sender))
return true;
}
return false;
}
private void SessionModified(TCPConnection session, string key, object newValue)
{
}
protected override void ClientDisconnected(TCPConnection connection)
{
foreach (var filter in filters)
{
filter.Disconnected(connection);
}
}
public override void Add(TCPConnection connection)
{
connection.Server = this;
base.Add(connection);
}
public override void Remove(TCPConnection connection)
{
connection.Server = null;
base.Remove(connection);
}
protected override void ClientConnected(TCPConnection connection)
{
foreach (var filter in filters)
{
filter.Connected(connection);
}
}
}
}

View File

@ -0,0 +1,37 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.TCP
{
public class TCPSession : NetworkSession
{
}
}

View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Net;
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.UDP
{
public abstract class UDPFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(byte[] data, IPEndPoint sender);
public void Destroy()
{
throw new NotImplementedException();
}
}
}

204
Esiur/Net/UDP/UDPServer.cs Normal file
View File

@ -0,0 +1,204 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Resource;
using Esiur.Core;
namespace Esiur.Net.UDP
{
/* public class IIPConnection
{
public EndPoint SenderPoint;
public
}*/
public class UDPServer : IResource
{
Thread receiver;
UdpClient udp;
UDPFilter[] filters = new UDPFilter[0];
public event DestroyedEvent OnDestroy;
public Instance Instance
{
get;
set;
}
[Attribute]
string IP
{
get;
set;
}
[Attribute]
ushort Port
{
get;
set;
}
private void Receiving()
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] b = udp.Receive(ref ep);
foreach (var child in filters)
{
var f = child as UDPFilter;
try
{
if (f.Execute(b, ep))
{
break;
}
}
catch (Exception ex)
{
Global.Log("UDPServer", LogType.Error, ex.ToString());
//Console.WriteLine(ex.ToString());
}
}
}
}
public bool Send(byte[] Data, int Count, IPEndPoint EP)
{
try
{
udp.Send(Data, Count, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, IPEndPoint EP)
{
try
{
udp.Send(Data, Data.Length, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, int Count, string Host, int Port)
{
try
{
udp.Send(Data, Count, Host, Port);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, string Host, int Port)
{
try
{
udp.Send(Data, Data.Length, Host, Port);
return true;
}
catch
{
return false;
}
}
public bool Send(string Data, IPEndPoint EP)
{
try
{
udp.Send(Encoding.Default.GetBytes(Data), Data.Length, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(string Data, string Host, int Port)
{
try
{
udp.Send(Encoding.Default.GetBytes(Data), Data.Length, Host, Port);
return true;
}
catch
{
return false;
}
}
public void Destroy()
{
udp.Close();
OnDestroy?.Invoke(this);
}
async AsyncReply<bool> IResource.Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
var address = IP == null ? IPAddress.Any : IPAddress.Parse(IP);
udp = new UdpClient(new IPEndPoint(address, Port));
receiver = new Thread(Receiving);
receiver.Start();
}
else if (trigger == ResourceTrigger.Terminate)
{
if (receiver != null)
receiver.Abort();
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
filters = await Instance.Children<UDPFilter>();
}
return true;
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-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>Debug</Configuration>
<TargetFramework>netstandard2.0</TargetFramework>
<PublishDir>M:\opt\Esiur</PublishDir>
<Platform>Any CPU</Platform>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,242 @@
using Esiur.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
namespace Esiur.Proxy
{
public static class ResourceProxy
{
static Dictionary<Type, Type> cache = new Dictionary<Type, Type>();
#if NETSTANDARD
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetTypeInfo().GetProperty("Instance").GetGetMethod();
#else
static MethodInfo modifyMethod = typeof(Instance).GetMethod("Modified");
static MethodInfo instanceGet = typeof(IResource).GetProperty("Instance").GetGetMethod();
#endif
public static Type GetBaseType(object resource)
{
return GetBaseType(resource.GetType());
}
public static Type GetBaseType(Type type)
{
if (type.Assembly.IsDynamic)
return type.GetTypeInfo().BaseType;
else
return type;
if (type.FullName.Contains("Esiur.Proxy.T"))
#if NETSTANDARD
return type.GetTypeInfo().BaseType;
#else
return type.BaseType;
#endif
else
return type;
}
public static Type GetProxy(Type type)
{
if (cache.ContainsKey(type))
return cache[type];
#if NETSTANDARD
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsSealed || typeInfo.IsAbstract)
throw new Exception("Sealed/Abastract classes can't be proxied.");
var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public)
where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal &&
p.GetCustomAttribute<PublicAttribute>(false) != null
select p;
#else
if (type.IsSealed)
throw new Exception("Sealed class can't be proxied.");
var props = from p in type.GetProperties()
where p.CanWrite && p.GetSetMethod().IsVirtual &&
p.GetCustomAttributes(typeof(ResourceProperty), false).Count() > 0
select p;
#endif
var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace);
assemblyName.Version = type.Assembly.GetName().Version;
assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo;
//assemblyName.SetPublicKeyToken(null);
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName);
var typeBuilder = moduleBuilder.DefineType(typeName,
TypeAttributes.Public | TypeAttributes.Class, type);
foreach (PropertyInfo propertyInfo in props)
CreateProperty(propertyInfo, typeBuilder, type);
#if NETSTANDARD
var t = typeBuilder.CreateTypeInfo().AsType();
cache.Add(type, t);
return t;
#else
var t = typeBuilder.CreateType();
cache.Add(type, t);
return t;
#endif
}
public static Type GetProxy<T>()
where T : IResource
{
return GetProxy(typeof(T));
}
//private static void C
private static void CreateProperty(PropertyInfo pi, TypeBuilder typeBuilder, Type resourceType)
{
var propertyBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.None, pi.PropertyType, null);
// Create set method
MethodBuilder builder = typeBuilder.DefineMethod("set_" + pi.Name,
MethodAttributes.Public | MethodAttributes.Virtual, null, new Type[] { pi.PropertyType });
builder.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator g = builder.GetILGenerator();
var getInstance = resourceType.GetTypeInfo().GetProperty("Instance").GetGetMethod();
//g.Emit(OpCodes.Ldarg_0);
//g.Emit(OpCodes.Ldarg_1);
//g.Emit(OpCodes.Call, pi.GetSetMethod());
//g.Emit(OpCodes.Nop);
//g.Emit(OpCodes.Ldarg_0);
//g.Emit(OpCodes.Call, getInstance);
//g.Emit(OpCodes.Ldstr, pi.Name);
//g.Emit(OpCodes.Call, modifyMethod);
//g.Emit(OpCodes.Nop);
//g.Emit(OpCodes.Ret);
Label exitMethod = g.DefineLabel();
Label callModified = g.DefineLabel();
g.Emit(OpCodes.Nop);
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Ldarg_1);
g.Emit(OpCodes.Call, pi.GetSetMethod());
g.Emit(OpCodes.Nop);
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Call, getInstance);
g.Emit(OpCodes.Dup);
g.Emit(OpCodes.Brtrue_S, callModified);
g.Emit(OpCodes.Pop);
g.Emit(OpCodes.Br_S, exitMethod);
g.MarkLabel(callModified);
g.Emit(OpCodes.Ldstr, pi.Name);
g.Emit(OpCodes.Call, modifyMethod);
g.Emit(OpCodes.Nop);
g.MarkLabel(exitMethod);
g.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(builder);
builder = typeBuilder.DefineMethod("get_" + pi.Name, MethodAttributes.Public | MethodAttributes.Virtual, pi.PropertyType, null);
g = builder.GetILGenerator();
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Call, pi.GetGetMethod());
g.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(builder);
// g.Emit(OpCodes.Ldarg_0);
// g.Emit(OpCodes.Call, pi.GetGetMethod());
// g.Emit(OpCodes.Ret);
// propertyBuilder.SetGetMethod(builder);
/*
Label callModified = g.DefineLabel();
Label exitMethod = g.DefineLabel();
// IL_0000: ldarg.0
//IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance()
//// (no C# code)
//IL_0006: dup
//IL_0007: brtrue.s IL_000c
//IL_0009: pop
//// }
//IL_000a: br.s IL_0017
//// (no C# code)
//IL_000c: ldstr "Level3"
//IL_0011: call instance void [Esiur]Esiur.Resource.Instance::Modified(string)
//IL_0016: nop
//IL_0017: ret
// Add IL code for set method
g.Emit(OpCodes.Nop);
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Ldarg_1);
g.Emit(OpCodes.Call, pi.GetSetMethod());
// IL_0000: ldarg.0
// IL_0001: call instance class [Esiur]Esiur.Resource.Instance [Esiur]Esiur.Resource.Resource::get_Instance()
// IL_0006: ldstr "Level3"
//IL_000b: callvirt instance void [Esiur]Esiur.Resource.Instance::Modified(string)
//IL_0010: ret
// Call property changed for object
g.Emit(OpCodes.Nop);
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Call, instanceGet);
g.Emit(OpCodes.Dup);
g.Emit(OpCodes.Brtrue_S, callModified);
g.Emit(OpCodes.Pop);
g.Emit(OpCodes.Br_S, exitMethod);
g.MarkLabel(callModified);
g.Emit(OpCodes.Ldstr, pi.Name);
g.Emit(OpCodes.Callvirt, modifyMethod);
g.Emit(OpCodes.Nop);
g.MarkLabel(exitMethod);
g.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(builder);
// create get method
*/
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
public class AnnotationAttribute : Attribute
{
public string Annotation { get; set; }
public AnnotationAttribute(string annotation)
{
this.Annotation = annotation;
}
}
}

View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2020 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property)]
public class AttributeAttribute : System.Attribute
{
public AttributeAttribute()
{
}
}
}

View File

@ -0,0 +1,50 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Data;
using Esiur.Core;
using System.ComponentModel;
namespace Esiur.Resource
{
public delegate bool QueryFilter<T>(T value);
public interface IResource : IDestructible///, INotifyPropertyChanged
{
AsyncReply<bool> Trigger(ResourceTrigger trigger);
Instance Instance
{
get;
set;
}
}
}

76
Esiur/Resource/IStore.cs Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource.Template;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Security.Permissions;
using Esiur.Security.Authority;
namespace Esiur.Resource
{
public interface IStore:IResource
{
AsyncReply<IResource> Get(string path);//, Func<IResource, bool> filter = null);
//AsyncReply<IResource> Retrieve(uint iid);
AsyncReply<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);
//bool RemoveAttributes(IResource resource, string[] attributes = null);
//Structure GetAttributes(IResource resource, string[] attributes = null);
//bool SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false);
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);
//AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, ulong fromAge, ulong toAge);
// AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecordByDate(IResource resource, DateTime fromDate, DateTime toDate);
AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate);
}
}

992
Esiur/Resource/Instance.cs Normal file
View File

@ -0,0 +1,992 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Data;
using System.Runtime.CompilerServices;
using System.Reflection;
using Esiur.Net.IIP;
using Esiur.Misc;
using Esiur.Security.Permissions;
using Esiur.Resource.Template;
using Esiur.Security.Authority;
using Esiur.Proxy;
using Esiur.Core;
namespace Esiur.Resource
{
public class Instance
{
string name;
// public int IntVal { get; set; }
WeakReference<IResource> resource;
IStore store;
ResourceTemplate template;
AutoList<IPermissionsManager, Instance> managers;
public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue);
public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, object[] args);
public delegate void CustomResourceEventOccurredEvent(IResource resource, object issuer, Func<Session, bool> receivers, string eventName, object[] args);
public delegate void ResourceDestroyedEvent(IResource resource);
public event ResourceModifiedEvent ResourceModified;
public event ResourceEventOccurredEvent ResourceEventOccurred;
public event CustomResourceEventOccurredEvent CustomResourceEventOccurred;
public event ResourceDestroyedEvent ResourceDestroyed;
bool loading = false;
//KeyList<string, object> attributes;
List<ulong> ages = new List<ulong>();
List<DateTime> modificationDates = new List<DateTime>();
private ulong instanceAge;
private DateTime instanceModificationDate;
uint id;
public KeyList<string, object> Variables { get; } = new KeyList<string, object>();
/// <summary>
/// Instance attributes are custom properties associated with the instance, a place to store information by IStore.
/// </summary>
//public KeyList<string, object> Attributes
//{
// get
// {
// return attributes;
// }
//}
public override string ToString()
{
return name + " (" + Link + ")";
}
public bool RemoveAttributes(string[] attributes = null)
{
return false;
/*
IResource res;
if (!resource.TryGetTarget(out res))
return false;
return store.RemoveAttributes(res, attributes);
*/
/*
if (attributes == null)
this.attributes.Clear();
else
{
foreach (var attr in attributes)
this.attributes.Remove(attr);
}
return true;
*/
}
public Structure GetAttributes(string[] attributes = null)
{
// @TODO
Structure rt = new Structure();
if (attributes != null)
{
for (var i = 0; i < attributes.Length; i++)
{
var at = template.GetAttributeTemplate(attributes[i]);
if (at != null)
{
}
}
}
return rt;
/*
var st = new Structure();
if (attributes == null)
{
var clone = this.attributes.Keys.ToList();
clone.Add("managers");
attributes = clone.ToArray();// this.attributes.Keys.ToList().Add("managers");
}
foreach (var attr in attributes)
{
if (attr == "name")
st["name"] = this.name;
else if (attr == "managers")
{
var mngrs = new List<Structure>();
foreach (var manager in this.managers)
mngrs.Add(new Structure()
{
["type"] = manager.GetType().FullName + "," + manager.GetType().GetTypeInfo().Assembly.GetName().Name,
["settings"] = manager.Settings
});
st["managers"] = mngrs.ToArray();
}
else if (attr == "parents")
{
//st["parents"] = parents.ToArray();
}
else if (attr == "children")
{
//st["children"] = children.ToArray();
}
else if (attr == "childrenCount")
{
//st["childrenCount"] = children.Count;
}
else if (attr == "type")
{
st["type"] = resource.GetType().FullName;
}
else
st[attr] = this.attributes[attr];
}
return st;
*/
}
public bool SetAttributes(Structure attributes, bool clearAttributes = false)
{
// @ TODO
IResource res;
if (resource.TryGetTarget(out res))
{
foreach (var kv in attributes)
{
var at = template.GetAttributeTemplate(kv.Key);
if (at != null)
if (at.Info.CanWrite)
at.Info.SetValue(res, DC.CastConvert(kv.Value, at.Info.PropertyType));
}
}
return true;
/*
try
{
if (clearAttributes)
this.attributes.Clear();
foreach (var attr in attributes)
if (attr.Key == "name")
this.name = attr.Value as string;
else if (attr.Key == "managers")
{
this.managers.Clear();
var mngrs = attr.Value as object[];
foreach (var mngr in mngrs)
{
var m = mngr as Structure;
var type = Type.GetType(m["type"] as string);
if (Codec.ImplementsInterface(type, typeof(IPermissionsManager)))
{
var settings = m["settings"] as Structure;
var manager = Activator.CreateInstance(type) as IPermissionsManager;
IResource res;
if (this.resource.TryGetTarget(out res))
{
manager.Initialize(settings, res);
this.managers.Add(manager);
}
}
else
return false;
}
}
else
{
this.attributes[attr.Key] = attr.Value;
}
}
catch
{
return false;
}
return true;
*/
}
/*
public Structure GetAttributes()
{
var st = new Structure();
foreach (var a in attributes.Keys)
st[a] = attributes[a];
st["name"] = name;
var mngrs = new List<Structure>();
foreach (var manager in managers)
{
var mngr = new Structure();
mngr["settings"] = manager.Settings;
mngr["type"] = manager.GetType().FullName;
mngrs.Add(mngr);
}
st["managers"] = mngrs;
return st;
}*/
/// <summary>
/// Get the age of a given property index.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Age.</returns>
public ulong GetAge(byte index)
{
if (index < ages.Count)
return ages[index];
else
return 0;
}
/// <summary>
/// Set the age of a property.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Age.</param>
public void SetAge(byte index, ulong value)
{
if (index < ages.Count)
{
ages[index] = value;
if (value > instanceAge)
instanceAge = value;
}
}
/// <summary>
/// Set the modification date of a property.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Modification date.</param>
public void SetModificationDate(byte index, DateTime value)
{
if (index < modificationDates.Count)
{
modificationDates[index] = value;
if (value > instanceModificationDate)
instanceModificationDate = value;
}
}
/// <summary>
/// Get modification date of a specific property.
/// </summary>
/// <param name="index">Zero-based property index</param>
/// <returns>Modification date.</returns>
public DateTime GetModificationDate(byte index)
{
if (index < modificationDates.Count)
return modificationDates[index];
else
return DateTime.MinValue;
}
/// <summary>
/// Load property value (used by stores)
/// </summary>
/// <param name="name">Property name</param>
/// <param name="age">Property age</param>
/// <param name="value">Property value</param>
/// <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 NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(name, new[] { resource.GetType() });
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
*/
if (pt.Info.PropertyType == typeof(DistributedPropertyContext))
return false;
if (pt.Info.CanWrite)
{
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);
return true;
}
/// <summary>
/// Age of the instance, incremented by 1 in every modification.
/// </summary>
public ulong Age
{
get { return instanceAge; }
internal set { instanceAge = value; }
}
/// <summary>
/// Last modification date.
/// </summary>
public DateTime ModificationDate
{
get
{
return instanceModificationDate;
}
}
/// <summary>
/// Instance Id.
/// </summary>
public uint Id
{
get { return id; }
}
/// <summary>
/// Import properties from bytes array.
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
public bool Deserialize(PropertyValue[] properties)
{
for (byte i = 0; i < properties.Length; i++)
{
var pt = this.template.GetPropertyTemplateByIndex(i);
if (pt != null)
{
var pv = properties[i];
LoadProperty(pt.Name, pv.Age, pv.Date, pv.Value);
}
}
return true;
}
/// <summary>
/// Export all properties with ResourceProperty attributed as bytes array.
/// </summary>
/// <returns></returns>
public PropertyValue[] Serialize()
{
List<PropertyValue> props = new List<PropertyValue>();
foreach (var pt in template.Properties)
{
/*
#if NETSTANDARD
var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = resource.GetType().GetProperty(pt.Name);
#endif
*/
//if (pt.Serilize)
//{
IResource res;
if (resource.TryGetTarget(out res))
{
var rt = pt.Info.GetValue(res, null);// pt.Serilize ? pt.Info.GetValue(res, null) : null;
props.Add(new PropertyValue(rt, ages[pt.Index], modificationDates[pt.Index]));
}
//}
}
return props.ToArray();
}
/*
public bool Deserialize(byte[] data, uint offset, uint length)
{
var props = Codec.ParseValues(data, offset, length);
Deserialize(props);
return true;
}
*/
/*
public byte[] Serialize(bool includeLength = false, DistributedConnection sender = null)
{
//var bl = new BinaryList();
List<object> props = new List<object>();
foreach (var pt in template.Properties)
{
var pi = resource.GetType().GetProperty(pt.Name);
var rt = pi.GetValue(resource, null);
// this is a cool hack to let the property know the sender
if (rt is Func<DistributedConnection, object>)
rt = (rt as Func<DistributedConnection, object>)(sender);
props.Add(rt);
}
if (includeLength)
{
return Codec.Compose(props.ToArray(), false);
}
else
{
var rt = Codec.Compose(props.ToArray(), false);
return DC.Clip(rt, 4, (uint)(rt.Length - 4));
}
}
public byte[] StorageSerialize()
{
var props = new List<object>();
foreach(var pt in template.Properties)
{
if (!pt.Storable)
continue;
var pi = resource.GetType().GetProperty(pt.Name);
if (!pi.CanWrite)
continue;
var rt = pi.GetValue(resource, null);
props.Add(rt);
}
return Codec.Compose(props.ToArray(), false);
}
*/
/// <summary>
/// If True, the instance can be stored to disk.
/// </summary>
/// <returns></returns>
public bool IsStorable()
{
#if NETSTANDARD
var attrs = resource.GetType().GetTypeInfo().GetCustomAttributes(typeof(Storable), true).ToArray();
#else
var attrs = resource.GetType().GetCustomAttributes(typeof(Storable), true);
#endif
return attrs.Length > 0;
}
internal void EmitModification(PropertyTemplate pt, object value)
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
instanceAge++;
var now = DateTime.UtcNow;
ages[pt.Index] = instanceAge;
modificationDates[pt.Index] = now;
if (pt.Recordable)
{
store.Record(res, pt.Name, value, ages[pt.Index], now);
}
else //if (pt.Storage == StorageMode.Recordable)
{
store.Modify(res, pt.Name, value, ages[pt.Index], now);
}
ResourceModified?.Invoke(res, pt.Name, value);
}
}
/// <summary>
/// Notify listeners that a property was modified.
/// </summary>
/// <param name="propertyName"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
public void Modified([CallerMemberName] string propertyName = "")
{
if (loading)
return;
object value;
if (GetPropertyValue(propertyName, out value))
{
var pt = template.GetPropertyTemplateByName(propertyName);
EmitModification(pt, value);
}
}
// internal void EmitResourceEvent(string name, string[] users, DistributedConnection[] connections, object[] args)
internal void EmitCustomResourceEvent(object issuer, Func<Session, bool> receivers, string name, object[] args)
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
CustomResourceEventOccurred?.Invoke(res, issuer, receivers, name, args);
}
}
internal void EmitResourceEvent(string name, object[] args)
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
ResourceEventOccurred?.Invoke(res, name, args);
}
}
/// <summary>
/// Get the value of a given property by name.
/// </summary>
/// <param name="name">Property name</param>
/// <param name="value">Output value</param>
/// <returns>True, if the resource has the property.</returns>
public bool GetPropertyValue(string name, out object value)
{
/*
#if NETSTANDARD
PropertyInfo pi = resource.GetType().GetTypeInfo().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#else
PropertyInfo pi = resource.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
#endif
*/
var pt = template.GetPropertyTemplateByName(name);
if (pt != null && pt.Info != null)
{
/*
#if NETSTANDARD
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false).ToArray();
#else
object[] ca = pi.GetCustomAttributes(typeof(ResourceProperty), false);
#endif
if (ca.Length > 0)
{
value = pi.GetValue(resource, null);
//if (value is Func<IManager, object>)
// value = (value as Func<IManager, object>)(sender);
return true;
}
*/
IResource res;
if (resource.TryGetTarget(out res))
value = pt.Info.GetValue(res, null);
else
{
value = null;
return false;
}
return true;
}
value = null;
return false;
}
/*
public bool Inherit
{
get { return inherit; }
}*/
/// <summary>
/// List of parents.
/// </summary>
//public AutoList<IResource, Instance> Parents => parents;
/// <summary>
/// Store responsible for creating and keeping the resource.
/// </summary>
public IStore Store
{
get { return store; }
}
/// <summary>
/// List of children.
/// </summary>
// 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
{
if (this.store != null)
return this.store.Link(this.resource);
else
{
var l = new List<string>();
//l.Add(name);
var p = this.resource; // parents.First();
while (true)
{
l.Insert(0, p.Instance.name);
if (p.Instance.parents.Count == 0)
break;
p = p.Instance.parents.First();
}
return String.Join("/", l.ToArray());
}
}
}
*
*/
/// <summary>
/// Instance name.
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
/// <summary>
/// Resource managed by this instance.
/// </summary>
public IResource Resource
{
get
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
return res;
}
else
return null;
}
}
/// <summary>
/// Resource template describes the properties, functions and events of the resource.
/// </summary>
public ResourceTemplate Template
{
get { return template; }
/*
internal set
{
template = Warehouse.GetTemplate(resource.GetType());
// set ages
for (byte i = 0; i < template.Properties.Length; i++)
{
ages.Add(0);
modificationDates.Add(DateTime.MinValue);
}
}
*/
}
/// <summary>
/// Check for permission.
/// </summary>
/// <param name="session">Caller sessions.</param>
/// <param name="action">Action type</param>
/// <param name="member">Function, property or event to check for permission.</param>
/// <param name="inquirer">Permission inquirer.</param>
/// <returns>Ruling.</returns>
public Ruling Applicable(Session session, ActionType action, MemberTemplate member, object inquirer = null)
{
IResource res;
if (this.resource.TryGetTarget(out res))
{
//return store.Applicable(res, session, action, member, inquirer);
foreach (IPermissionsManager manager in managers)
{
var r = manager.Applicable(res, session, action, member, inquirer);
if (r != Ruling.DontCare)
return r;
}
}
return Ruling.DontCare;
}
/// <summary>
/// Execution managers.
/// </summary>
public AutoList<IPermissionsManager, Instance> Managers => managers;
/// <summary>
/// Create new instance.
/// </summary>
/// <param name="id">Instance Id.</param>
/// <param name="name">Name of the instance.</param>
/// <param name="resource">Resource to manage.</param>
/// <param name="store">Store responsible for the resource.</param>
public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0)
{
this.store = store;
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);
managers = new AutoList<IPermissionsManager, Instance>(this);
//children.OnAdd += Children_OnAdd;
//children.OnRemoved += Children_OnRemoved;
//parents.OnAdd += Parents_OnAdd;
//parents.OnRemoved += Parents_OnRemoved;
resource.OnDestroy += Resource_OnDestroy;
if (customTemplate != null)
this.template = customTemplate;
else
this.template = Warehouse.GetTemplate(resource.GetType());
// set ages
for (byte i = 0; i < template.Properties.Length; i++)
{
ages.Add(0);
modificationDates.Add(DateTime.MinValue);
}
// connect events
Type t = ResourceProxy.GetBaseType(resource);
#if NETSTANDARD
var events = t.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
#else
var events = t.GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
#endif
foreach (var evt in template.Events)
{
//if (evt.EventHandlerType != typeof(ResourceEventHanlder))
// continue;
if (evt.Info == null)
continue;
if (evt.Info.EventHandlerType == typeof(ResourceEventHanlder))
{
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
// if (ca.Length == 0)
// continue;
ResourceEventHanlder proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate);
}
else if (evt.Info.EventHandlerType == typeof(CustomResourceEventHanlder))
{
//var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
//if (ca.Length == 0)
// continue;
CustomResourceEventHanlder proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
evt.Info.AddEventHandler(resource, proxyDelegate);
}
/*
else if (evt.EventHandlerType == typeof(CustomUsersEventHanlder))
{
var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
if (ca.Length == 0)
continue;
CustomUsersEventHanlder proxyDelegate = (users, args) => EmitResourceEvent(evt.Name, users, null, args);
evt.AddEventHandler(resource, proxyDelegate);
}
else if (evt.EventHandlerType == typeof(CustomConnectionsEventHanlder))
{
var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
if (ca.Length == 0)
continue;
CustomConnectionsEventHanlder proxyDelegate = (connections, args) => EmitResourceEvent(evt.Name, null, connections, args);
evt.AddEventHandler(resource, proxyDelegate);
}
else if (evt.EventHandlerType == typeof(CustomReceiversEventHanlder))
{
var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
if (ca.Length == 0)
continue;
CustomReceiversEventHanlder proxyDelegate = (users, connections, args) => EmitResourceEvent(evt.Name, users, connections, args);
evt.AddEventHandler(resource, proxyDelegate);
}
*/
}
}
//IQueryable<IResource> Children => store.GetChildren(this);
/*
* private void Children_OnRemoved(Instance parent, IResource value)
{
value.Instance.parents.Remove(resource);
}
private void Children_OnAdd(Instance parent, IResource value)
{
if (!value.Instance.parents.Contains(resource))
value.Instance.parents.Add(resource);
}
private void Parents_OnRemoved(Instance parent, IResource value)
{
value.Instance.children.Remove(resource);
}
private void Parents_OnAdd(Instance parent, IResource value)
{
if (!value.Instance.children.Contains(resource))
value.Instance.children.Add(resource);
}
*/
private void Resource_OnDestroy(object sender)
{
ResourceDestroyed?.Invoke((IResource)sender);
}
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
public class PrivateAttribute:Attribute
{
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Class)]
public class PublicAttribute : Attribute
{
// public StorageMode Storage { get; set; }
//public bool Serialize { get; set; }
public PublicAttribute()//StorageMode storage = StorageMode.NonVolatile, bool serialize = true)
{
// Storage = storage;
//Serialize = serialize;
}
}
}

View File

@ -0,0 +1,60 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Esiur.Core;
namespace Esiur.Resource
{
public class Resource : IResource
{
public Instance Instance { get; set; }
public event DestroyedEvent OnDestroy;
public virtual void Destroy()
{
OnDestroy?.Invoke(this);
}
public virtual AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
return new AsyncReply<bool>(this.Create());
else
return new AsyncReply<bool>(true);
}
protected virtual bool Create()
{
return true;
}
~Resource()
{
Destroy();
}
}
}

View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Event)]
public class ResourceEvent : System.Attribute
{
string expansion;
public string Expansion
{
get
{
return expansion;
}
}
public ResourceEvent(string expansion = null)
{
this.expansion = expansion;
}
}
}

View File

@ -0,0 +1,45 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Data;
using Esiur.Core;
using Esiur.Net.IIP;
using Esiur.Security.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
public delegate void ResourceEventHanlder(params object[] args);
// public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args);
//public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args);
//public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args);
public delegate void CustomResourceEventHanlder(object issuer, Func<Session, bool> receivers, params object[] args);// object issuer, Session[] receivers, params object[] args);
// public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args);
}

View File

@ -0,0 +1,52 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Method)]
public class ResourceFunction : System.Attribute
{
private string expansion = null;
public string Expansion
{
get
{
return expansion;
}
}
public ResourceFunction(string expansion = null)
{
this.expansion = expansion;
}
}
}

View File

@ -0,0 +1,77 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Resource.Template;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property)]
public class ResourceProperty : System.Attribute
{
bool serialize;
string readExpansion;
string writeExpansion;
// bool recordable;
//bool storable;
//public bool Recordable => recordable;
//public bool Storable => storable;
StorageMode storage;
public StorageMode Storage => storage;
public bool Serialize => serialize;
public string ReadExpansion
{
get
{
return readExpansion;
}
}
public string WriteExpansion
{
get
{
return writeExpansion;
}
}
public ResourceProperty(StorageMode storage = StorageMode.NonVolatile, bool serialize = true, string readExpansion = null, string writeExpansion = null)
{
this.readExpansion = readExpansion;
this.writeExpansion = writeExpansion;
this.storage = storage;
this.serialize = serialize;
}
}
}

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

@ -0,0 +1,43 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
public enum ResourceTrigger : int
{
Open = 0,
Initialize,
Terminate,
Configure,
SystemInitialized,
SystemTerminated,
SystemReload,
}
}

View File

@ -0,0 +1,72 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using Esiur.Data;
using Esiur.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.All)]
public class Storable : global::System.Attribute
{
public delegate object SerializerFunction(object value);
public delegate object DeserializerFunction(object data);
SerializerFunction serializer;
DeserializerFunction deserializer;
DataType type;
public Storable()
{
type = DataType.Void;
}
public DeserializerFunction Deserializer
{
get { return deserializer; }
}
public SerializerFunction Serializer
{
get { return serializer; }
}
public Storable(DataType type)
{
this.type = type;
}
public Storable(DataType type, SerializerFunction serializer, DeserializerFunction deserializer)
{
this.type = type;
this.serializer = serializer;
this.deserializer = deserializer;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
[AttributeUsage(AttributeTargets.Property)]
public class StorageAttribute:Attribute
{
public StorageMode Mode { get; set; }
public StorageAttribute(StorageMode mode)
{
Mode = mode;
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
public enum StorageMode : byte
{
NonVolatile,
Volatile,
Recordable
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Text;
using Esiur.Core;
using Esiur.Data;
using Esiur.Resource.Template;
namespace Esiur.Resource
{
public abstract class Store<T> : IStore where T:IResource
{
public Instance Instance { get; set; }
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> AddChild(IResource parent, IResource child);
public abstract AsyncReply<bool> AddParent(IResource child, IResource parent);
public abstract AsyncBag<T1> Children<T1>(IResource resource, string name) where T1 : IResource;
public virtual void Destroy()
{
OnDestroy?.Invoke(this);
}
public abstract AsyncReply<IResource> Get(string path);
public abstract AsyncReply<KeyList<PropertyTemplate, PropertyValue[]>> GetRecord(IResource resource, DateTime fromDate, DateTime toDate);
public abstract string Link(IResource resource);
public abstract bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
public abstract AsyncBag<T1> Parents<T1>(IResource resource, string name) where T1 : IResource;
public abstract AsyncReply<bool> Put(IResource resource);
public abstract bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime);
public abstract bool Remove(IResource resource);
public abstract AsyncReply<bool> RemoveChild(IResource parent, IResource child);
public abstract AsyncReply<bool> RemoveParent(IResource child, IResource parent);
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public T New(string name = null, object attributes = null, object properties = null)
{
var resource = Warehouse.New<T>(name, this, null, null, attributes, properties);
resource.Instance.Managers.AddRange(this.Instance.Managers.ToArray());
return resource;
}
}
}

View File

@ -0,0 +1,26 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class AttributeTemplate : MemberTemplate
{
public PropertyInfo Info
{
get;
set;
}
public AttributeTemplate(ResourceTemplate template, byte index, string name)
: base(template, MemberType.Attribute, index, name)
{
}
}
}

View File

@ -0,0 +1,51 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class EventTemplate : MemberTemplate
{
public string Expansion
{
get;
set;
}
public EventInfo Info { get; set; }
public override byte[] Compose()
{
var name = base.Compose();
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return new BinaryList()
.AddUInt8(0x50)
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
}
else
return new BinaryList()
.AddUInt8(0x40)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
}
public EventTemplate(ResourceTemplate template, byte index, string name, string expansion = null)
:base(template, MemberType.Property, index, name)
{
this.Expansion = expansion;
}
}
}

View File

@ -0,0 +1,55 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class FunctionTemplate : MemberTemplate
{
public string Expansion
{
get;
set;
}
public bool IsVoid
{
get;
set;
}
public override byte[] Compose()
{
var name = base.Compose();
if (Expansion != null)
{
var exp = DC.ToBytes(Expansion);
return new BinaryList().AddUInt8((byte)(0x10 | (IsVoid ? 0x8 : 0x0)))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.ToArray();
}
else
return new BinaryList().AddUInt8((byte)(IsVoid ? 0x8 : 0x0))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
}
public FunctionTemplate(ResourceTemplate template, byte index, string name,bool isVoid, string expansion = null)
:base(template, MemberType.Property, index, name)
{
this.IsVoid = isVoid;
this.Expansion = expansion;
}
}
}

View File

@ -0,0 +1,47 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class MemberTemplate
{
public enum MemberType
{
Function = 0,
Property = 1,
Event = 2,
Attribute = 3
}
public byte Index => index;
public string Name => name;
public MemberType Type => type;
ResourceTemplate template;
string name;
MemberType type;
byte index;
public ResourceTemplate Template => template;
public MemberTemplate(ResourceTemplate template, MemberType type, byte index, string name)
{
this.template = template;
this.type = type;
this.index = index;
this.name = name;
}
public string Fullname => template.ClassName + "." + Name;
public virtual byte[] Compose()
{
return DC.ToBytes(Name);
}
}
}

View File

@ -0,0 +1,132 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Resource.Template
{
public class PropertyTemplate : MemberTemplate
{
public enum PropertyPermission:byte
{
Read = 1,
Write,
ReadWrite
}
public PropertyInfo Info
{
get;
set;
}
/*
public bool Serilize
{
get;set;
}
*/
//bool ReadOnly;
//IIPTypes::DataType ReturnType;
public PropertyPermission Permission {
get;
set;
}
public bool Recordable
{
get;
set;
}
/*
public PropertyType Mode
{
get;
set;
}*/
public string ReadExpansion
{
get;
set;
}
public string WriteExpansion
{
get;
set;
}
/*
public bool Storable
{
get;
set;
}*/
public override byte[] Compose()
{
var name = base.Compose();
var pv = ((byte)(Permission) << 1) | (Recordable ? 1 : 0);
if (WriteExpansion != null && ReadExpansion != null)
{
var rexp = DC.ToBytes(ReadExpansion);
var wexp = DC.ToBytes(WriteExpansion);
return new BinaryList()
.AddUInt8((byte)(0x38 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.AddInt32(rexp.Length)
.AddUInt8Array(rexp)
.ToArray();
}
else if (WriteExpansion != null)
{
var wexp = DC.ToBytes(WriteExpansion);
return new BinaryList()
.AddUInt8((byte)(0x30 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(wexp.Length)
.AddUInt8Array(wexp)
.ToArray();
}
else if (ReadExpansion != null)
{
var rexp = DC.ToBytes(ReadExpansion);
return new BinaryList()
.AddUInt8((byte)(0x28 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddInt32(rexp.Length)
.AddUInt8Array(rexp)
.ToArray();
}
else
return new BinaryList()
.AddUInt8((byte)(0x20 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.ToArray();
}
public PropertyTemplate(ResourceTemplate template, byte index, string name, string read = null, string write = null, bool recordable = false)
:base(template, MemberType.Property, index, name)
{
this.Recordable = recordable;
//this.Storage = storage;
this.ReadExpansion = read;
this.WriteExpansion = write;
}
}
}

Some files were not shown because too many files have changed in this diff Show More