mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-06-26 21:13:13 +00:00
Rename
This commit is contained in:
53
Esiur/Core/AsyncAwaiter.cs
Normal file
53
Esiur/Core/AsyncAwaiter.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
53
Esiur/Core/AsyncAwaiterGeneric.cs
Normal file
53
Esiur/Core/AsyncAwaiterGeneric.cs
Normal 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
119
Esiur/Core/AsyncBag.cs
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
53
Esiur/Core/AsyncBagAwaiter.cs
Normal file
53
Esiur/Core/AsyncBagAwaiter.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
53
Esiur/Core/AsyncBagAwaiterGeneric.cs
Normal file
53
Esiur/Core/AsyncBagAwaiterGeneric.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
75
Esiur/Core/AsyncBagGeneric.cs
Normal file
75
Esiur/Core/AsyncBagGeneric.cs
Normal 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())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
57
Esiur/Core/AsyncException.cs
Normal file
57
Esiur/Core/AsyncException.cs
Normal 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
84
Esiur/Core/AsyncQueue.cs
Normal 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
351
Esiur/Core/AsyncReply.cs
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
68
Esiur/Core/AsyncReplyBuilder.cs
Normal file
68
Esiur/Core/AsyncReplyBuilder.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
67
Esiur/Core/AsyncReplyBuilderGeneric.cs
Normal file
67
Esiur/Core/AsyncReplyBuilderGeneric.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
379
Esiur/Core/AsyncReplyGeneric.cs
Normal file
379
Esiur/Core/AsyncReplyGeneric.cs
Normal 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
185
Esiur/Core/AsyncReplyNon.cs
Normal 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
12
Esiur/Core/ErrorType.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Core
|
||||
{
|
||||
public enum ErrorType
|
||||
{
|
||||
Management,
|
||||
Exception
|
||||
}
|
||||
}
|
40
Esiur/Core/ExceptionCode.cs
Normal file
40
Esiur/Core/ExceptionCode.cs
Normal 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
21
Esiur/Core/IAsyncReply.cs
Normal 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();
|
||||
}
|
||||
}
|
39
Esiur/Core/IDestructible.cs
Normal file
39
Esiur/Core/IDestructible.cs
Normal 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
40
Esiur/Core/LogType.cs
Normal 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,
|
||||
}
|
||||
}
|
12
Esiur/Core/ProgressType.cs
Normal file
12
Esiur/Core/ProgressType.cs
Normal 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
311
Esiur/Data/AutoList.cs
Normal 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
714
Esiur/Data/BinaryList.cs
Normal 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
1297
Esiur/Data/Codec.cs
Normal file
File diff suppressed because it is too large
Load Diff
985
Esiur/Data/DataConverter.cs
Normal file
985
Esiur/Data/DataConverter.cs
Normal 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
119
Esiur/Data/DataType.cs
Normal 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
12
Esiur/Data/IUserType.cs
Normal 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
244
Esiur/Data/KeyList.cs
Normal 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
37
Esiur/Data/NotModified.cs
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
35
Esiur/Data/PropertyValue.cs
Normal file
35
Esiur/Data/PropertyValue.cs
Normal 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
274
Esiur/Data/ResourceList.cs
Normal 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
220
Esiur/Data/StringKeyList.cs
Normal 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
166
Esiur/Data/Structure.cs
Normal 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
63
Esiur/Esiur.csproj
Normal 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
463
Esiur/Misc/Global.cs
Normal 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(
|
||||
//}
|
||||
}
|
||||
}
|
56
Esiur/Net/DataLink/PacketFilter.cs
Normal file
56
Esiur/Net/DataLink/PacketFilter.cs
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
123
Esiur/Net/DataLink/PacketServer.cs
Normal file
123
Esiur/Net/DataLink/PacketServer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
Esiur/Net/DataLink/PacketSource.cs
Normal file
95
Esiur/Net/DataLink/PacketSource.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
437
Esiur/Net/HTTP/HTTPConnection.cs
Normal file
437
Esiur/Net/HTTP/HTTPConnection.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
82
Esiur/Net/HTTP/HTTPFilter.cs
Normal file
82
Esiur/Net/HTTP/HTTPFilter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
300
Esiur/Net/HTTP/HTTPServer.cs
Normal file
300
Esiur/Net/HTTP/HTTPServer.cs
Normal 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();
|
||||
//}
|
||||
}
|
||||
}
|
130
Esiur/Net/HTTP/HTTPSession.cs
Normal file
130
Esiur/Net/HTTP/HTTPSession.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
39
Esiur/Net/HTTP/IIPoHTTP.cs
Normal file
39
Esiur/Net/HTTP/IIPoHTTP.cs
Normal 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
125
Esiur/Net/HTTP/IIPoWS.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
1171
Esiur/Net/IIP/DistributedConnection.cs
Normal file
1171
Esiur/Net/IIP/DistributedConnection.cs
Normal file
File diff suppressed because it is too large
Load Diff
2258
Esiur/Net/IIP/DistributedConnectionProtocol.cs
Normal file
2258
Esiur/Net/IIP/DistributedConnectionProtocol.cs
Normal file
File diff suppressed because it is too large
Load Diff
27
Esiur/Net/IIP/DistributedPropertyContext.cs
Normal file
27
Esiur/Net/IIP/DistributedPropertyContext.cs
Normal 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);
|
||||
}
|
||||
}
|
464
Esiur/Net/IIP/DistributedResource.cs
Normal file
464
Esiur/Net/IIP/DistributedResource.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
34
Esiur/Net/IIP/DistributedResourceEvent.cs
Normal file
34
Esiur/Net/IIP/DistributedResourceEvent.cs
Normal 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);
|
||||
}
|
73
Esiur/Net/IIP/DistributedResourceQueueItem.cs
Normal file
73
Esiur/Net/IIP/DistributedResourceQueueItem.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
169
Esiur/Net/IIP/DistributedServer.cs
Normal file
169
Esiur/Net/IIP/DistributedServer.cs
Normal 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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
38
Esiur/Net/IIP/DistributedSession.cs
Normal file
38
Esiur/Net/IIP/DistributedSession.cs
Normal 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;
|
||||
}
|
||||
}
|
40
Esiur/Net/IIP/EntryPoint.cs
Normal file
40
Esiur/Net/IIP/EntryPoint.cs
Normal 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();
|
||||
}
|
||||
}
|
15
Esiur/Net/INetworkReceiver.cs
Normal file
15
Esiur/Net/INetworkReceiver.cs
Normal 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
208
Esiur/Net/NetworkBuffer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
367
Esiur/Net/NetworkConnection.cs
Normal file
367
Esiur/Net/NetworkConnection.cs
Normal 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
311
Esiur/Net/NetworkServer.cs
Normal 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
130
Esiur/Net/NetworkSession.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
313
Esiur/Net/Packets/HTTPRequestPacket.cs
Normal file
313
Esiur/Net/Packets/HTTPRequestPacket.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
304
Esiur/Net/Packets/HTTPResponsePacket.cs
Normal file
304
Esiur/Net/Packets/HTTPResponsePacket.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
412
Esiur/Net/Packets/IIPAuthPacket.cs
Normal file
412
Esiur/Net/Packets/IIPAuthPacket.cs
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
823
Esiur/Net/Packets/IIPPacket.cs
Normal file
823
Esiur/Net/Packets/IIPPacket.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
22
Esiur/Net/Packets/IIPPacketAttachInfo.cs
Normal file
22
Esiur/Net/Packets/IIPPacketAttachInfo.cs
Normal 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
369
Esiur/Net/Packets/Packet.cs
Normal 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 *************************************/
|
||||
|
||||
|
217
Esiur/Net/Packets/WebsocketPacket.cs
Normal file
217
Esiur/Net/Packets/WebsocketPacket.cs
Normal 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
26
Esiur/Net/SendList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
74
Esiur/Net/Sockets/ISocket.cs
Normal file
74
Esiur/Net/Sockets/ISocket.cs
Normal 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();
|
||||
}
|
||||
}
|
555
Esiur/Net/Sockets/SSLSocket.cs
Normal file
555
Esiur/Net/Sockets/SSLSocket.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
Esiur/Net/Sockets/SocketState.cs
Normal file
42
Esiur/Net/Sockets/SocketState.cs
Normal 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
|
||||
}
|
||||
}
|
659
Esiur/Net/Sockets/TCPSocket.cs
Normal file
659
Esiur/Net/Sockets/TCPSocket.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
363
Esiur/Net/Sockets/WSSocket.cs
Normal file
363
Esiur/Net/Sockets/WSSocket.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
66
Esiur/Net/TCP/TCPConnection.cs
Normal file
66
Esiur/Net/TCP/TCPConnection.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
66
Esiur/Net/TCP/TCPFilter.cs
Normal file
66
Esiur/Net/TCP/TCPFilter.cs
Normal 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
156
Esiur/Net/TCP/TCPServer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
37
Esiur/Net/TCP/TCPSession.cs
Normal file
37
Esiur/Net/TCP/TCPSession.cs
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
57
Esiur/Net/UDP/UDPFilter.cs
Normal file
57
Esiur/Net/UDP/UDPFilter.cs
Normal 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
204
Esiur/Net/UDP/UDPServer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
13
Esiur/Properties/PublishProfiles/FolderProfile.pubxml
Normal file
13
Esiur/Properties/PublishProfiles/FolderProfile.pubxml
Normal 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>
|
242
Esiur/Proxy/ResourceProxy.cs
Normal file
242
Esiur/Proxy/ResourceProxy.cs
Normal 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
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
18
Esiur/Resource/AnnotationAttribute.cs
Normal file
18
Esiur/Resource/AnnotationAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
42
Esiur/Resource/AttributeAttribute.cs
Normal file
42
Esiur/Resource/AttributeAttribute.cs
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
50
Esiur/Resource/IResource.cs
Normal file
50
Esiur/Resource/IResource.cs
Normal 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
76
Esiur/Resource/IStore.cs
Normal 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
992
Esiur/Resource/Instance.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
11
Esiur/Resource/PrivateAttribute.cs
Normal file
11
Esiur/Resource/PrivateAttribute.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
public class PrivateAttribute:Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
22
Esiur/Resource/PublicAttribute.cs
Normal file
22
Esiur/Resource/PublicAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
60
Esiur/Resource/Resource.cs
Normal file
60
Esiur/Resource/Resource.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
53
Esiur/Resource/ResourceEvent.cs
Normal file
53
Esiur/Resource/ResourceEvent.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
45
Esiur/Resource/ResourceEventHandler.cs
Normal file
45
Esiur/Resource/ResourceEventHandler.cs
Normal 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);
|
||||
|
||||
}
|
52
Esiur/Resource/ResourceFunction.cs
Normal file
52
Esiur/Resource/ResourceFunction.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
77
Esiur/Resource/ResourceProperty.cs
Normal file
77
Esiur/Resource/ResourceProperty.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
28
Esiur/Resource/ResourceQuery.cs
Normal file
28
Esiur/Resource/ResourceQuery.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
43
Esiur/Resource/ResourceTrigger.cs
Normal file
43
Esiur/Resource/ResourceTrigger.cs
Normal 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,
|
||||
}
|
||||
}
|
72
Esiur/Resource/Storable.cs
Normal file
72
Esiur/Resource/Storable.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
16
Esiur/Resource/StorageAttribute.cs
Normal file
16
Esiur/Resource/StorageAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
13
Esiur/Resource/StorageMode.cs
Normal file
13
Esiur/Resource/StorageMode.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
public enum StorageMode : byte
|
||||
{
|
||||
NonVolatile,
|
||||
Volatile,
|
||||
Recordable
|
||||
}
|
||||
}
|
57
Esiur/Resource/StoreGeneric.cs
Normal file
57
Esiur/Resource/StoreGeneric.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
26
Esiur/Resource/Template/AttributeTemplate.cs
Normal file
26
Esiur/Resource/Template/AttributeTemplate.cs
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
51
Esiur/Resource/Template/EventTemplate.cs
Normal file
51
Esiur/Resource/Template/EventTemplate.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
55
Esiur/Resource/Template/FunctionTemplate.cs
Normal file
55
Esiur/Resource/Template/FunctionTemplate.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
47
Esiur/Resource/Template/MemberTemplate.cs
Normal file
47
Esiur/Resource/Template/MemberTemplate.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
132
Esiur/Resource/Template/PropertyTemplate.cs
Normal file
132
Esiur/Resource/Template/PropertyTemplate.cs
Normal 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
Reference in New Issue
Block a user