mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-06-13 22:48:42 +00:00
Ver 3
This commit is contained in:
@@ -91,7 +91,7 @@ public class AsyncReply
|
|||||||
}
|
}
|
||||||
|
|
||||||
//int timeoutMilliseconds = 0;
|
//int timeoutMilliseconds = 0;
|
||||||
public AsyncReply Timeout(int milliseconds, Action callback = null)
|
public void Timeout(int milliseconds, Action callback = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
//timeoutMilliseconds = milliseconds;
|
//timeoutMilliseconds = milliseconds;
|
||||||
@@ -107,7 +107,6 @@ public class AsyncReply
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Wait(int millisecondsTimeout)
|
public object Wait(int millisecondsTimeout)
|
||||||
@@ -236,7 +235,7 @@ public class AsyncReply
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncReply Trigger(object result)
|
public void Trigger(object result)
|
||||||
{
|
{
|
||||||
lock (asyncLock)
|
lock (asyncLock)
|
||||||
{
|
{
|
||||||
@@ -245,13 +244,13 @@ public class AsyncReply
|
|||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
|
|
||||||
if (exception != null)
|
if (exception != null)
|
||||||
return this;
|
return;
|
||||||
|
|
||||||
//if (Debug)
|
//if (Debug)
|
||||||
// Console.WriteLine($"AsyncReply: {Id} Trigger");
|
// Console.WriteLine($"AsyncReply: {Id} Trigger");
|
||||||
|
|
||||||
if (resultReady)
|
if (resultReady)
|
||||||
return this;
|
return;
|
||||||
|
|
||||||
this.result = result;
|
this.result = result;
|
||||||
|
|
||||||
@@ -269,15 +268,15 @@ public class AsyncReply
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncReply TriggerError(Exception exception)
|
public void TriggerError(Exception exception)
|
||||||
{
|
{
|
||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
|
|
||||||
if (resultReady)
|
if (resultReady)
|
||||||
return this;
|
return;
|
||||||
|
|
||||||
if (exception is AsyncException)
|
if (exception is AsyncException)
|
||||||
this.exception = exception as AsyncException;
|
this.exception = exception as AsyncException;
|
||||||
@@ -297,10 +296,9 @@ public class AsyncReply
|
|||||||
|
|
||||||
mutex?.Set();
|
mutex?.Set();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncReply TriggerProgress(ProgressType type, uint value, uint max)
|
public void TriggerProgress(ProgressType type, uint value, uint max)
|
||||||
{
|
{
|
||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
|
|
||||||
@@ -308,10 +306,10 @@ public class AsyncReply
|
|||||||
foreach (var cb in progressCallbacks)
|
foreach (var cb in progressCallbacks)
|
||||||
cb(type, value, max);
|
cb(type, value, max);
|
||||||
|
|
||||||
return this;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncReply TriggerWarning(byte level, string message)
|
public void TriggerWarning(byte level, string message)
|
||||||
{
|
{
|
||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
|
|
||||||
@@ -319,11 +317,11 @@ public class AsyncReply
|
|||||||
foreach (var cb in warningCallbacks)
|
foreach (var cb in warningCallbacks)
|
||||||
cb(level, message);
|
cb(level, message);
|
||||||
|
|
||||||
return this;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public AsyncReply TriggerPropagation(object value)
|
public void TriggerPropagation(object value)
|
||||||
{
|
{
|
||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
|
|
||||||
@@ -331,12 +329,12 @@ public class AsyncReply
|
|||||||
foreach (var cb in propagationCallbacks)
|
foreach (var cb in propagationCallbacks)
|
||||||
cb(value);
|
cb(value);
|
||||||
|
|
||||||
return this;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public AsyncReply TriggerChunk(object value)
|
public void TriggerChunk(object value)
|
||||||
{
|
{
|
||||||
|
|
||||||
//timeout?.Dispose();
|
//timeout?.Dispose();
|
||||||
@@ -347,7 +345,6 @@ public class AsyncReply
|
|||||||
cb(value);
|
cb(value);
|
||||||
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncAwaiter GetAwaiter()
|
public AsyncAwaiter GetAwaiter()
|
||||||
|
|||||||
+152
-37
@@ -100,12 +100,7 @@ public static class Codec
|
|||||||
|
|
||||||
static AsyncParser[] TypedAsyncParsers = new AsyncParser[]
|
static AsyncParser[] TypedAsyncParsers = new AsyncParser[]
|
||||||
{
|
{
|
||||||
DataDeserializer.RecordParserAsync,
|
DataDeserializer.TypedParserAsync,
|
||||||
DataDeserializer.TypedListParserAsync,
|
|
||||||
DataDeserializer.TypedMapParserAsync,
|
|
||||||
DataDeserializer.TupleParserAsync,
|
|
||||||
DataDeserializer.EnumParserAsync,
|
|
||||||
DataDeserializer.ConstantParserAsync,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static AsyncParser[] ExtendedAsyncParsers = new AsyncParser[]
|
static AsyncParser[] ExtendedAsyncParsers = new AsyncParser[]
|
||||||
@@ -170,12 +165,13 @@ public static class Codec
|
|||||||
|
|
||||||
static SyncParser[] TypedParsers = new SyncParser[]
|
static SyncParser[] TypedParsers = new SyncParser[]
|
||||||
{
|
{
|
||||||
DataDeserializer.RecordParser,
|
DataDeserializer.TypedParser,
|
||||||
DataDeserializer.TypedListParser,
|
//DataDeserializer.RecordParser,
|
||||||
DataDeserializer.TypedMapParser,
|
//DataDeserializer.TypedListParser,
|
||||||
DataDeserializer.TupleParser,
|
//DataDeserializer.TypedMapParser,
|
||||||
DataDeserializer.EnumParser,
|
//DataDeserializer.TupleParser,
|
||||||
DataDeserializer.ConstantParser,
|
//DataDeserializer.EnumParser,
|
||||||
|
//DataDeserializer.ConstantParser,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SyncParser[] ExtendedParsers = new SyncParser[]
|
static SyncParser[] ExtendedParsers = new SyncParser[]
|
||||||
@@ -192,81 +188,197 @@ public static class Codec
|
|||||||
/// <param name="connection">EpConnection is required in case a structure in the array holds items at the other end.</param>
|
/// <param name="connection">EpConnection is required in case a structure in the array holds items at the other end.</param>
|
||||||
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
|
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
|
||||||
/// <returns>Value</returns>
|
/// <returns>Value</returns>
|
||||||
public static (uint, object) ParseAsync(byte[] data, uint offset, EpConnection connection, uint[] requestSequence)
|
public static AsyncReply<ParseResult<object>> ParseAsync(byte[] data, uint offset, EpConnection connection, uint[] requestSequence)
|
||||||
{
|
{
|
||||||
|
var rt = new AsyncReply<ParseResult<object>>();
|
||||||
|
|
||||||
var tdu = ParsedTdu.Parse(data, offset, (uint)data.Length);
|
ParsedTdu.ParseAsync(data, offset, (uint)data.Length, connection).Then(tdu =>
|
||||||
|
{
|
||||||
if (tdu.Class == TduClass.Invalid)
|
if (tdu.Class == TduClass.Invalid)
|
||||||
throw new NullReferenceException("DataType can't be parsed.");
|
throw new NullReferenceException("DataType can't be parsed.");
|
||||||
|
|
||||||
|
object result;
|
||||||
|
|
||||||
if (tdu.Class == TduClass.Fixed)
|
if (tdu.Class == TduClass.Fixed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
|
result = FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Dynamic)
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
result = DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Typed)
|
else if (tdu.Class == TduClass.Typed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
result = TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else // if (tt.Class == TDUClass.Extension)
|
else // if (tt.Class == TDUClass.Extension)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
result = ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (uint, object) ParseAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence)
|
if (result is AsyncReply asyncReply)
|
||||||
|
{
|
||||||
|
asyncReply.Then(value =>
|
||||||
|
{
|
||||||
|
rt.Trigger(new ParseResult<object>(value, (uint)tdu.TotalLength));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt.Trigger(new ParseResult<object>(result, (uint)tdu.TotalLength));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object ParseAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence)
|
||||||
{
|
{
|
||||||
if (tdu.Class == TduClass.Invalid)
|
if (tdu.Class == TduClass.Invalid)
|
||||||
throw new NullReferenceException("DataType can't be parsed.");
|
throw new NullReferenceException("DataType can't be parsed.");
|
||||||
|
|
||||||
if (tdu.Class == TduClass.Fixed)
|
if (tdu.Class == TduClass.Fixed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
|
return FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Dynamic)
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
return DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Typed)
|
else if (tdu.Class == TduClass.Typed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
return TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else // if (tt.Class == TDUClass.Extension)
|
else // if (tt.Class == TDUClass.Extension)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
return ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (uint, object) ParseSync(ParsedTdu tdu, Warehouse warehouse)
|
public static object Parse(PlainTdu plainTdu, EpConnection connection, uint[] requestSequence)
|
||||||
{
|
{
|
||||||
|
var parsedTdu = ParsedTdu.Parse(plainTdu.Data, plainTdu.TduOffset, (uint)plainTdu.Ends, connection);
|
||||||
|
|
||||||
|
if (parsedTdu is ParsedTdu tdu)
|
||||||
|
{
|
||||||
|
if (tdu.Class == TduClass.Invalid)
|
||||||
|
throw new NullReferenceException("TDU can't be parsed.");
|
||||||
|
|
||||||
if (tdu.Class == TduClass.Fixed)
|
if (tdu.Class == TduClass.Fixed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse));
|
return FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Dynamic)
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, DynamicParsers[tdu.Index](tdu, warehouse));
|
return DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
}
|
}
|
||||||
else if (tdu.Class == TduClass.Typed)
|
else if (tdu.Class == TduClass.Typed)
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, TypedParsers[tdu.Index](tdu, warehouse));
|
return TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
else // if (tt.Class == TDUClass.Extension)
|
||||||
|
{
|
||||||
|
return ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parsedTdu is AsyncReply<ParsedTdu> asyncReply)
|
||||||
|
{
|
||||||
|
var rt = new AsyncReply();
|
||||||
|
asyncReply.Then(tdu =>
|
||||||
|
{
|
||||||
|
if (tdu.Class == TduClass.Invalid)
|
||||||
|
throw new NullReferenceException("TDU can't be parsed.");
|
||||||
|
|
||||||
|
object result;
|
||||||
|
|
||||||
|
if (tdu.Class == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
result = FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
|
{
|
||||||
|
result = DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Typed)
|
||||||
|
{
|
||||||
|
result = TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
else // if (tt.Class == TDUClass.Extension)
|
||||||
|
{
|
||||||
|
result = ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result is AsyncReply resultReply)
|
||||||
|
{
|
||||||
|
resultReply.Then(rt.Trigger)
|
||||||
|
.Error(rt.TriggerError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt.Trigger(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object ParseSync(PlainTdu plainTdu, Warehouse warehouse)
|
||||||
|
{
|
||||||
|
var tdu = ParsedTdu.ParseSync(plainTdu.Data, plainTdu.TduOffset, plainTdu.Ends, warehouse);
|
||||||
|
|
||||||
|
if (tdu.Class == TduClass.Invalid)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid TDU.");
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
return FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
|
{
|
||||||
|
return DynamicParsers[tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Typed)
|
||||||
|
{
|
||||||
|
return TypedParsers[tdu.Index](tdu, warehouse);
|
||||||
}
|
}
|
||||||
else // Extension
|
else // Extension
|
||||||
{
|
{
|
||||||
return ((uint)tdu.TotalLength, ExtendedParsers[tdu.Index](tdu, warehouse));
|
return ExtendedParsers[tdu.Index](tdu, warehouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static object ParseSync(ParsedTdu tdu, Warehouse warehouse)
|
||||||
|
{
|
||||||
|
if (tdu.Class == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
return FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Dynamic)
|
||||||
|
{
|
||||||
|
return DynamicParsers[tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
else if (tdu.Class == TduClass.Typed)
|
||||||
|
{
|
||||||
|
return TypedParsers[tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
else // Extension
|
||||||
|
{
|
||||||
|
return ExtendedParsers[tdu.Index](tdu, warehouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse)
|
public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse)
|
||||||
{
|
{
|
||||||
var tdu = ParsedTdu.Parse(data, offset, (uint)data.Length);
|
var tdu = ParsedTdu.ParseSync(data, offset, (uint)data.Length, warehouse);
|
||||||
|
|
||||||
if (tdu.Class == TduClass.Invalid)
|
if (tdu.Class == TduClass.Invalid)
|
||||||
throw new NullReferenceException("DataType can't be parsed.");
|
throw new NullReferenceException("DataType can't be parsed.");
|
||||||
@@ -301,7 +413,7 @@ public static class Codec
|
|||||||
throw new NullReferenceException("Resource is null.");
|
throw new NullReferenceException("Resource is null.");
|
||||||
|
|
||||||
if (resource is EpResource)
|
if (resource is EpResource)
|
||||||
if (((EpResource)(resource)).DistributedResourceConnection == connection)
|
if (((EpResource)(resource)).ResourceConnection == connection)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -385,7 +497,7 @@ public static class Codec
|
|||||||
ComposeInternal(object valueOrSource, Warehouse warehouse, EpConnection connection)
|
ComposeInternal(object valueOrSource, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (valueOrSource == null)
|
if (valueOrSource == null)
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
|
|
||||||
var type = valueOrSource.GetType();
|
var type = valueOrSource.GetType();
|
||||||
|
|
||||||
@@ -412,7 +524,7 @@ public static class Codec
|
|||||||
valueOrSource = ((IUserType)valueOrSource).Get();
|
valueOrSource = ((IUserType)valueOrSource).Get();
|
||||||
|
|
||||||
if (valueOrSource == null)
|
if (valueOrSource == null)
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
|
|
||||||
|
|
||||||
type = valueOrSource.GetType();
|
type = valueOrSource.GetType();
|
||||||
@@ -488,7 +600,7 @@ public static class Codec
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,6 +653,9 @@ public static class Codec
|
|||||||
{
|
{
|
||||||
while (type != null)
|
while (type != null)
|
||||||
{
|
{
|
||||||
|
if (type == typeof(object))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (type == iface)
|
if (type == iface)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ public static class DataSerializer
|
|||||||
|
|
||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else if (v >= short.MinValue && v <= short.MaxValue)
|
else if (v >= short.MinValue && v <= short.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((short*)ptr) = (short)v;
|
*((short*)ptr) = (short)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int16, rt, 2);
|
return new Tdu(TduIdentifier.Int16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -40,7 +40,7 @@ public static class DataSerializer
|
|||||||
var rt = new byte[4];
|
var rt = new byte[4];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((int*)ptr) = v;
|
*((int*)ptr) = v;
|
||||||
return new Tdu(TduIdentifier.Int32, rt, 4);
|
return new Tdu(TduIdentifier.Int32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ public static class DataSerializer
|
|||||||
if (v <= byte.MaxValue)
|
if (v <= byte.MaxValue)
|
||||||
{
|
{
|
||||||
// Fits in 1 byte
|
// Fits in 1 byte
|
||||||
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else if (v <= ushort.MaxValue)
|
else if (v <= ushort.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ushort*)ptr) = (ushort)v;
|
*((ushort*)ptr) = (ushort)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt16, rt, 2);
|
return new Tdu(TduIdentifier.UInt16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -69,7 +69,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((uint*)ptr) = v;
|
*((uint*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt32, rt, 4);
|
return new Tdu(TduIdentifier.UInt32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ public static class DataSerializer
|
|||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
{
|
{
|
||||||
// Fits in 1 byte
|
// Fits in 1 byte
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((short*)ptr) = v;
|
*((short*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int16, rt, 2);
|
return new Tdu(TduIdentifier.Int16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ public static class DataSerializer
|
|||||||
if (v <= byte.MaxValue)
|
if (v <= byte.MaxValue)
|
||||||
{
|
{
|
||||||
// Fits in 1 byte
|
// Fits in 1 byte
|
||||||
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -109,7 +109,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ushort*)ptr) = v;
|
*((ushort*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt16, rt, 2);
|
return new Tdu(TduIdentifier.UInt16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ public static class DataSerializer
|
|||||||
// Special IEEE-754 values
|
// Special IEEE-754 values
|
||||||
if (float.IsNaN(v) || float.IsInfinity(v))
|
if (float.IsNaN(v) || float.IsInfinity(v))
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Infinity, new byte[0], 0);
|
return new Tdu(TduIdentifier.Infinity, new byte[0], 0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If v is an exact integer, prefer smallest signed width up to Int32
|
// If v is an exact integer, prefer smallest signed width up to Int32
|
||||||
@@ -130,7 +130,7 @@ public static class DataSerializer
|
|||||||
// Note: casts are safe because we check bounds first.
|
// Note: casts are safe because we check bounds first.
|
||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v >= short.MinValue && v <= short.MaxValue)
|
if (v >= short.MinValue && v <= short.MaxValue)
|
||||||
@@ -138,7 +138,7 @@ public static class DataSerializer
|
|||||||
var rt = new byte[2];
|
var rt = new byte[2];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((short*)ptr) = (short)v;
|
*((short*)ptr) = (short)v;
|
||||||
return new Tdu(TduIdentifier.Int16, rt, 2);
|
return new Tdu(TduIdentifier.Int16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ public static class DataSerializer
|
|||||||
var rt = new byte[4];
|
var rt = new byte[4];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((float*)ptr) = v;
|
*((float*)ptr) = v;
|
||||||
return new Tdu(TduIdentifier.Float32, rt, 4);
|
return new Tdu(TduIdentifier.Float32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +159,14 @@ public static class DataSerializer
|
|||||||
// Special IEEE-754 values
|
// Special IEEE-754 values
|
||||||
if (double.IsNaN(v) || double.IsInfinity(v))
|
if (double.IsNaN(v) || double.IsInfinity(v))
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Infinity, new byte[0], 0);
|
return new Tdu(TduIdentifier.Infinity, new byte[0], 0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If v is an exact integer, choose the smallest signed width
|
// If v is an exact integer, choose the smallest signed width
|
||||||
if (v == Math.Truncate(v))
|
if (v == Math.Truncate(v))
|
||||||
{
|
{
|
||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
|
|
||||||
if (v >= short.MinValue && v <= short.MaxValue)
|
if (v >= short.MinValue && v <= short.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -175,7 +175,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((short*)ptr) = (short)v;
|
*((short*)ptr) = (short)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int16, rt, 2);
|
return new Tdu(TduIdentifier.Int16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v >= int.MinValue && v <= int.MaxValue)
|
if (v >= int.MinValue && v <= int.MaxValue)
|
||||||
@@ -185,7 +185,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((int*)ptr) = (int)v;
|
*((int*)ptr) = (int)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int32, rt, 4);
|
return new Tdu(TduIdentifier.Int32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's integral but outside Int64 range, fall through to Float64.
|
// If it's integral but outside Int64 range, fall through to Float64.
|
||||||
@@ -200,7 +200,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((float*)ptr) = f;
|
*((float*)ptr) = f;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Float32, rt, 4);
|
return new Tdu(TduIdentifier.Float32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default: Float64
|
// Default: Float64
|
||||||
@@ -208,7 +208,7 @@ public static class DataSerializer
|
|||||||
var rt = new byte[8];
|
var rt = new byte[8];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((double*)ptr) = v;
|
*((double*)ptr) = v;
|
||||||
return new Tdu(TduIdentifier.Float64, rt, 8);
|
return new Tdu(TduIdentifier.Float64, rt, 8, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static unsafe Tdu Int64Composer(object value, Warehouse warehouse, EpConnection connection)
|
public static unsafe Tdu Int64Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
@@ -218,7 +218,7 @@ public static class DataSerializer
|
|||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
{
|
{
|
||||||
// Fits in 1 byte
|
// Fits in 1 byte
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else if (v >= short.MinValue && v <= short.MaxValue)
|
else if (v >= short.MinValue && v <= short.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -227,7 +227,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((short*)ptr) = (short)v;
|
*((short*)ptr) = (short)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int16, rt, 2);
|
return new Tdu(TduIdentifier.Int16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else if (v >= int.MinValue && v <= int.MaxValue)
|
else if (v >= int.MinValue && v <= int.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -236,7 +236,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((int*)ptr) = (int)v;
|
*((int*)ptr) = (int)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int32, rt, 4);
|
return new Tdu(TduIdentifier.Int32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -245,7 +245,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((long*)ptr) = v;
|
*((long*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Int64, rt, 8);
|
return new Tdu(TduIdentifier.Int64, rt, 8, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ public static class DataSerializer
|
|||||||
if (v <= byte.MaxValue)
|
if (v <= byte.MaxValue)
|
||||||
{
|
{
|
||||||
// Fits in 1 byte
|
// Fits in 1 byte
|
||||||
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
return new Tdu(TduIdentifier.UInt8, new byte[] { (byte)v }, 1, null, null);
|
||||||
}
|
}
|
||||||
else if (v <= ushort.MaxValue)
|
else if (v <= ushort.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -265,7 +265,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ushort*)ptr) = (ushort)v;
|
*((ushort*)ptr) = (ushort)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt16, rt, 2);
|
return new Tdu(TduIdentifier.UInt16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else if (v <= uint.MaxValue)
|
else if (v <= uint.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -274,7 +274,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((uint*)ptr) = (uint)v;
|
*((uint*)ptr) = (uint)v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt32, rt, 4);
|
return new Tdu(TduIdentifier.UInt32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -283,7 +283,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ulong*)ptr) = v;
|
*((ulong*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.UInt64, rt, 8);
|
return new Tdu(TduIdentifier.UInt64, rt, 8, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((long*)ptr) = v;
|
*((long*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.DateTime, rt, 8);
|
return new Tdu(TduIdentifier.DateTime, rt, 8, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, EpConnection connection)
|
//public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
@@ -320,27 +320,27 @@ public static class DataSerializer
|
|||||||
if (scale == 0)
|
if (scale == 0)
|
||||||
{
|
{
|
||||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||||
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
return new Tdu(TduIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1, null, null);
|
||||||
|
|
||||||
if (v >= short.MinValue && v <= short.MaxValue)
|
if (v >= short.MinValue && v <= short.MaxValue)
|
||||||
{
|
{
|
||||||
var b = new byte[2];
|
var b = new byte[2];
|
||||||
BinaryPrimitives.WriteInt16LittleEndian(b, (short)v);
|
BinaryPrimitives.WriteInt16LittleEndian(b, (short)v);
|
||||||
return new Tdu(TduIdentifier.Int16, b, 2);
|
return new Tdu(TduIdentifier.Int16, b, 2, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v >= int.MinValue && v <= int.MaxValue)
|
if (v >= int.MinValue && v <= int.MaxValue)
|
||||||
{
|
{
|
||||||
var b = new byte[4];
|
var b = new byte[4];
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(b, (int)v);
|
BinaryPrimitives.WriteInt32LittleEndian(b, (int)v);
|
||||||
return new Tdu(TduIdentifier.Int32, b, 4);
|
return new Tdu(TduIdentifier.Int32, b, 4, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v >= long.MinValue && v <= long.MaxValue)
|
if (v >= long.MinValue && v <= long.MaxValue)
|
||||||
{
|
{
|
||||||
var b = new byte[8];
|
var b = new byte[8];
|
||||||
BinaryPrimitives.WriteInt64LittleEndian(b, (long)v);
|
BinaryPrimitives.WriteInt64LittleEndian(b, (long)v);
|
||||||
return new Tdu(TduIdentifier.Int64, b, 8);
|
return new Tdu(TduIdentifier.Int64, b, 8, null, null);
|
||||||
}
|
}
|
||||||
// else fall through (needs 96+ bits)
|
// else fall through (needs 96+ bits)
|
||||||
}
|
}
|
||||||
@@ -355,7 +355,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((float*)ptr) = f;
|
*((float*)ptr) = f;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Float32, rt, 4);
|
return new Tdu(TduIdentifier.Float32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try exact Float64 (8 bytes)
|
// Try exact Float64 (8 bytes)
|
||||||
@@ -367,7 +367,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((double*)ptr) = d;
|
*((double*)ptr) = d;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Float64, rt, 8);
|
return new Tdu(TduIdentifier.Float64, rt, 8, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -377,7 +377,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((decimal*)ptr) = v;
|
*((decimal*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Decimal128, rt, 16);
|
return new Tdu(TduIdentifier.Decimal128, rt, 16, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,58 +385,55 @@ public static class DataSerializer
|
|||||||
{
|
{
|
||||||
var b = Encoding.UTF8.GetBytes((string)value);
|
var b = Encoding.UTF8.GetBytes((string)value);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.String, b, (uint)b.Length);
|
return new Tdu(TduIdentifier.String, b, (uint)b.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu ResourceLinkComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu ResourceLinkComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
var b = Encoding.UTF8.GetBytes((ResourceLink)value);
|
var b = Encoding.UTF8.GetBytes((ResourceLink)value);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.ResourceLink, b, (uint)b.Length);
|
return new Tdu(TduIdentifier.ResourceLink, b, (uint)b.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Tdu EnumComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu EnumComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
|
|
||||||
|
var valueType = value.GetType();
|
||||||
|
|
||||||
//var warehouse = connection?.Instance?.Warehouse ?? connection?.Server?.Instance?.Warehouse;
|
var typeDef = warehouse.GetLocalTypeDefByType(valueType);
|
||||||
//if (warehouse == null)
|
|
||||||
// throw new Exception("Warehouse not set.");
|
|
||||||
|
|
||||||
var typeDef = warehouse.GetTypeDefByType(value.GetType());
|
|
||||||
|
|
||||||
var intVal = Convert.ChangeType(value, (value as Enum).GetTypeCode());
|
var intVal = Convert.ChangeType(value, (value as Enum).GetTypeCode());
|
||||||
|
|
||||||
var ct = typeDef.Constants.FirstOrDefault(x => x.Value.Equals(intVal));
|
var ct = typeDef.Constants.FirstOrDefault(x => x.Value.Equals(intVal));
|
||||||
|
|
||||||
if (ct == null)
|
if (ct == null)
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
|
|
||||||
//return Codec.ComposeInternal(intVal, warehouse, connection);
|
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.TypedEnum,
|
return new Tdu(TduIdentifier.Typed, new byte[] { ct.Index }, 1,
|
||||||
new byte[] { ct.Index }, 1, typeDef.Id.Data);
|
Tru.FromType(valueType, warehouse), connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu UInt8Composer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu UInt8Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.UInt8,
|
return new Tdu(TduIdentifier.UInt8,
|
||||||
new byte[] { (byte)value }, 1);
|
new byte[] { (byte)value }, 1, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu Int8Composer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu Int8Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Int8,
|
return new Tdu(TduIdentifier.Int8,
|
||||||
new byte[] { (byte)(sbyte)value }, 1);
|
new byte[] { (byte)(sbyte)value }, 1, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu Char8Composer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu Char8Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Int8,
|
return new Tdu(TduIdentifier.Int8,
|
||||||
new byte[] { (byte)(char)value }, 1);
|
new byte[] { (byte)(char)value }, 1, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe Tdu Char16Composer(object value, Warehouse warehouse, EpConnection connection)
|
public static unsafe Tdu Char16Composer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
@@ -446,7 +443,7 @@ public static class DataSerializer
|
|||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((char*)ptr) = v;
|
*((char*)ptr) = v;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Char16, rt, 2);
|
return new Tdu(TduIdentifier.Char16, rt, 2, null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,30 +451,30 @@ public static class DataSerializer
|
|||||||
{
|
{
|
||||||
if ((bool)value)
|
if ((bool)value)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.True, null, 0);
|
return new Tdu(TduIdentifier.True, null, 0, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.False, null, 0);
|
return new Tdu(TduIdentifier.False, null, 0, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Tdu NotModifiedComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu NotModifiedComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.NotModified, null, 0);
|
return new Tdu(TduIdentifier.NotModified, null, 0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu RawDataComposerFromArray(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu RawDataComposerFromArray(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
var b = (byte[])value;
|
var b = (byte[])value;
|
||||||
return new Tdu(TduIdentifier.RawData, b, (uint)b.Length);
|
return new Tdu(TduIdentifier.RawData, b, (uint)b.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu RawDataComposerFromList(dynamic value, Warehouse warehouse, EpConnection connection)
|
public static Tdu RawDataComposerFromList(dynamic value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
var b = value as List<byte>;
|
var b = value as List<byte>;
|
||||||
return new Tdu(TduIdentifier.RawData, b.ToArray(), (uint)b.Count);
|
return new Tdu(TduIdentifier.RawData, b.ToArray(), (uint)b.Count, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public static (TDUIdentifier, byte[]) ListComposerFromArray(dynamic value, EpConnection connection)
|
//public static (TDUIdentifier, byte[]) ListComposerFromArray(dynamic value, EpConnection connection)
|
||||||
@@ -497,10 +494,10 @@ public static class DataSerializer
|
|||||||
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
||||||
|
|
||||||
if (composed == null)
|
if (composed == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.List, composed, (uint)composed.Length);
|
return new Tdu(TduIdentifier.List, composed, (uint)composed.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (value == null)
|
//if (value == null)
|
||||||
@@ -541,7 +538,6 @@ public static class DataSerializer
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
||||||
if (tru.Identifier == TruIdentifier.Int32)
|
if (tru.Identifier == TruIdentifier.Int32)
|
||||||
{
|
{
|
||||||
composed = GroupInt32Codec.Encode((IList<int>)value);
|
composed = GroupInt32Codec.Encode((IList<int>)value);
|
||||||
@@ -566,52 +562,49 @@ public static class DataSerializer
|
|||||||
{
|
{
|
||||||
composed = GroupUInt16Codec.Encode((IList<ushort>)value);
|
composed = GroupUInt16Codec.Encode((IList<ushort>)value);
|
||||||
}
|
}
|
||||||
else if (tru.Identifier == TruIdentifier.Enum)
|
//else if (tru.Identifier == TruIdentifier.Enum)
|
||||||
{
|
//{
|
||||||
|
// var rt = new List<byte>();
|
||||||
|
// var typeDef = warehouse.GetTypeDefByType(tru.GetRuntimeType(warehouse));
|
||||||
|
|
||||||
var rt = new List<byte>();
|
// foreach (var v in value)
|
||||||
var typeDef = warehouse.GetTypeDefByType(tru.GetRuntimeType(warehouse));
|
// {
|
||||||
|
// var intVal = Convert.ChangeType(v, (v as Enum).GetTypeCode());
|
||||||
|
// var ct = typeDef.Constants.FirstOrDefault(x => x.Value.Equals(intVal));
|
||||||
|
// if (ct == null)
|
||||||
|
// throw new Exception("Unknown Enum.");
|
||||||
|
// rt.Add(ct.Index);
|
||||||
|
// }
|
||||||
|
|
||||||
foreach (var v in value)
|
// composed = rt.ToArray();
|
||||||
{
|
//}
|
||||||
var intVal = Convert.ChangeType(v, (v as Enum).GetTypeCode());
|
|
||||||
var ct = typeDef.Constants.FirstOrDefault(x => x.Value.Equals(intVal));
|
|
||||||
if (ct == null)
|
|
||||||
throw new Exception("Unknown Enum.");
|
|
||||||
rt.Add(ct.Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
composed = rt.ToArray();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var rt = new List<byte>();
|
var rt = new List<byte>();
|
||||||
|
|
||||||
Tdu? previous = null;
|
Tdu? previous = null;
|
||||||
var isTyped = tru.IsTyped();
|
//var isTyped = tru.TypeDefId != null;// tru.IsTyped();
|
||||||
|
|
||||||
foreach (var i in value)
|
foreach (var i in value)
|
||||||
{
|
{
|
||||||
var tdu = Codec.ComposeInternal(i, warehouse, connection);
|
var tdu = Codec.ComposeInternal(i, warehouse, connection);
|
||||||
|
|
||||||
var currentTru = Tru.FromType(i?.GetType());
|
var currentTru = Tru.FromType(i?.GetType(), warehouse);
|
||||||
|
|
||||||
if (isTyped && tru.Match(currentTru))
|
if (tdu.Class == TduClass.Typed && tru.Match(currentTru))
|
||||||
{
|
{
|
||||||
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
||||||
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
||||||
|
|
||||||
var ntd = new Tdu(TduIdentifier.TypeOfTarget, d, (ulong)d.Length);
|
var ntd = new Tdu(TduIdentifier.TypeOfTarget, d, (ulong)d.Length, null, null);
|
||||||
rt.AddRange(ntd.Composed);
|
rt.AddRange(ntd.Composed);
|
||||||
}
|
}
|
||||||
else
|
else if (previous != null && tdu.MatchType(previous.Value))
|
||||||
|
|
||||||
if (previous != null && tdu.MatchType(previous.Value))
|
|
||||||
{
|
{
|
||||||
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
||||||
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
||||||
|
|
||||||
var ntd = new Tdu(TduIdentifier.TypeContinuation, d, (ulong)d.Length);
|
var ntd = new Tdu(TduIdentifier.TypeContinuation, d, (ulong)d.Length, null, null);
|
||||||
rt.AddRange(ntd.Composed);
|
rt.AddRange(ntd.Composed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -632,33 +625,24 @@ public static class DataSerializer
|
|||||||
|
|
||||||
public static Tdu TypedListComposer(IEnumerable value, Type type, Warehouse warehouse, EpConnection connection)
|
public static Tdu TypedListComposer(IEnumerable value, Type type, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
var tru = Tru.FromType(type);
|
var elementTru = Tru.FromType(type, warehouse);
|
||||||
|
|
||||||
byte[] composed = TypedArrayComposer(value, tru, warehouse, connection);
|
byte[] composed = TypedArrayComposer(value, elementTru, warehouse, connection);
|
||||||
|
|
||||||
if (composed == null)
|
if (composed == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var metadata = tru.Compose();
|
var metadata = new TruComposite(TruIdentifier.TypedList, false,
|
||||||
|
new Tru[] { elementTru }, value.GetType());
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.TypedList, composed, (uint)composed.Length, metadata);
|
return new Tdu(TduIdentifier.Typed, composed, (uint)composed.Length, metadata, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public static byte[] PropertyValueComposer(PropertyValue propertyValue, EpConnection connection)//, bool includeAge = true)
|
|
||||||
//{
|
|
||||||
// var rt = new BinaryList();
|
|
||||||
|
|
||||||
// return
|
|
||||||
// .AddUInt64(propertyValue.Age)
|
|
||||||
// .AddDateTime(propertyValue.Date)
|
|
||||||
// .AddUInt8Array(Codec.Compose(propertyValue.Value, connection))
|
|
||||||
// .ToArray();
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static Tdu PropertyValueArrayComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu PropertyValueArrayComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var rt = new List<byte>();
|
var rt = new List<byte>();
|
||||||
var ar = value as PropertyValue[];
|
var ar = value as PropertyValue[];
|
||||||
@@ -671,16 +655,16 @@ public static class DataSerializer
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.RawData, rt.ToArray(),
|
return new Tdu(TduIdentifier.RawData, rt.ToArray(),
|
||||||
(uint)rt.Count);
|
(uint)rt.Count, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu TypedMapComposer(object value, Type keyType, Type valueType, Warehouse warehouse, EpConnection connection)
|
public static Tdu TypedMapComposer(object value, Type keyType, Type valueType, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var kt = Tru.FromType(keyType);
|
var kt = Tru.FromType(keyType, warehouse);
|
||||||
var vt = Tru.FromType(valueType);
|
var vt = Tru.FromType(valueType, warehouse);
|
||||||
|
|
||||||
//var rt = new List<byte>();
|
//var rt = new List<byte>();
|
||||||
|
|
||||||
@@ -692,34 +676,33 @@ public static class DataSerializer
|
|||||||
var compsedKeys = TypedArrayComposer(keys, kt, warehouse, connection);
|
var compsedKeys = TypedArrayComposer(keys, kt, warehouse, connection);
|
||||||
var compsedValues = TypedArrayComposer(values, vt, warehouse, connection);
|
var compsedValues = TypedArrayComposer(values, vt, warehouse, connection);
|
||||||
|
|
||||||
var ktb = kt.Compose();
|
//var ktb = kt.Compose();
|
||||||
var vtb = vt.Compose();
|
//var vtb = vt.Compose();
|
||||||
|
|
||||||
var metadata = DC.Combine(ktb, 0, (uint)ktb.Length, vtb, 0, (uint)vtb.Length);
|
//var metadata = DC.Combine(ktb, 0, (uint)ktb.Length, vtb, 0, (uint)vtb.Length);
|
||||||
|
|
||||||
//foreach (var el in map.Serialize())
|
|
||||||
// rt.AddRange(Codec.Compose(el, warehouse, connection));
|
|
||||||
|
|
||||||
var keysTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedKeys, (uint)compsedKeys.Length).Composed;
|
var keysTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedKeys, (uint)compsedKeys.Length, null, null).Composed;
|
||||||
var valuesTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedValues, (uint)compsedValues.Length).Composed;
|
var valuesTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedValues, (uint)compsedValues.Length, null, null).Composed;
|
||||||
|
|
||||||
var all = DC.Combine(keysTdu, 0, (uint)keysTdu.Length, valuesTdu, 0, (uint)valuesTdu.Length);
|
var all = DC.Combine(keysTdu, 0, (uint)keysTdu.Length, valuesTdu, 0, (uint)valuesTdu.Length);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.TypedMap, all, (uint)all.Length, metadata);
|
return new Tdu(TduIdentifier.Typed, all, (uint)all.Length,
|
||||||
|
new TruComposite(TruIdentifier.TypedMap, false, new Tru[] { kt, vt }, value.GetType()), connection);
|
||||||
|
|
||||||
|
//return new Tdu(TduIdentifier.TypedMap, all, (uint)all.Length, metadata);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//return new TDU(TDUIdentifier.TypedMap, rt.ToArray(), (uint)rt.Count,
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
public static Tdu TypedDictionaryComposer(object value, Type keyType, Type valueType, Warehouse warehouse, EpConnection connection)
|
public static Tdu TypedDictionaryComposer(object value, Type keyType, Type valueType, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var kt = Tru.FromType(keyType);
|
var kt = Tru.FromType(keyType, warehouse);
|
||||||
var vt = Tru.FromType(valueType);
|
var vt = Tru.FromType(valueType, warehouse);
|
||||||
|
|
||||||
//var rt = new List<byte>();
|
//var rt = new List<byte>();
|
||||||
|
|
||||||
@@ -731,48 +714,18 @@ public static class DataSerializer
|
|||||||
var compsedKeys = TypedArrayComposer(keys, kt, warehouse, connection);
|
var compsedKeys = TypedArrayComposer(keys, kt, warehouse, connection);
|
||||||
var compsedValues = TypedArrayComposer(values, vt, warehouse, connection);
|
var compsedValues = TypedArrayComposer(values, vt, warehouse, connection);
|
||||||
|
|
||||||
var ktb = kt.Compose();
|
|
||||||
var vtb = vt.Compose();
|
|
||||||
|
|
||||||
var metadata = DC.Combine(ktb, 0, (uint)ktb.Length, vtb, 0, (uint)vtb.Length);
|
var keysTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedKeys, (uint)compsedKeys.Length, null, null).Composed;
|
||||||
|
var valuesTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedValues, (uint)compsedValues.Length, null, null).Composed;
|
||||||
//foreach (var el in map.Serialize())
|
|
||||||
// rt.AddRange(Codec.Compose(el, warehouse, connection));
|
|
||||||
|
|
||||||
var keysTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedKeys, (uint)compsedKeys.Length).Composed;
|
|
||||||
var valuesTdu = new Tdu(TduIdentifier.TypeOfTarget, compsedValues, (uint)compsedValues.Length).Composed;
|
|
||||||
|
|
||||||
var all = DC.Combine(keysTdu, 0, (uint)keysTdu.Length, valuesTdu, 0, (uint)valuesTdu.Length);
|
var all = DC.Combine(keysTdu, 0, (uint)keysTdu.Length, valuesTdu, 0, (uint)valuesTdu.Length);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.TypedMap, all, (uint)all.Length, metadata);
|
return new Tdu(TduIdentifier.Typed, all, (uint)all.Length,
|
||||||
|
new TruComposite(TruIdentifier.TypedMap, false, new Tru[] { kt, vt },
|
||||||
|
value.GetType()),
|
||||||
|
connection);
|
||||||
|
|
||||||
|
|
||||||
//if (value == null)
|
|
||||||
// return new TDU(TDUIdentifier.Null, null, 0);
|
|
||||||
|
|
||||||
//var kt = TRU.FromType(keyType).Compose();
|
|
||||||
//var vt = TRU.FromType(valueType).Compose();
|
|
||||||
|
|
||||||
//var rt = new List<byte>();
|
|
||||||
|
|
||||||
////rt.AddRange(kt);
|
|
||||||
////rt.AddRange(vt);
|
|
||||||
|
|
||||||
//var dic = (IDictionary)value;
|
|
||||||
|
|
||||||
//var ar = new List<object>();
|
|
||||||
//foreach (var k in dic.Keys)
|
|
||||||
//{
|
|
||||||
// ar.Add(k);
|
|
||||||
// ar.Add(dic[k]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//foreach (var el in ar)
|
|
||||||
// rt.AddRange(Codec.Compose(el, warehouse, connection));
|
|
||||||
|
|
||||||
|
|
||||||
//return new TDU(TDUIdentifier.TypedMap, rt.ToArray(), (uint)rt.Count,
|
|
||||||
// DC.Combine(kt, 0, (uint)kt.Length, vt, 0, (uint)vt.Length));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] DynamicArrayComposer(IEnumerable value, Warehouse warehouse, EpConnection connection)
|
public static byte[] DynamicArrayComposer(IEnumerable value, Warehouse warehouse, EpConnection connection)
|
||||||
@@ -792,7 +745,7 @@ public static class DataSerializer
|
|||||||
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
||||||
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
||||||
|
|
||||||
var ntd = new Tdu(TduIdentifier.TypeContinuation, d, (ulong)d.Length);
|
var ntd = new Tdu(TduIdentifier.TypeContinuation, d, (ulong)d.Length, null, null);
|
||||||
rt.AddRange(ntd.Composed);
|
rt.AddRange(ntd.Composed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -809,23 +762,23 @@ public static class DataSerializer
|
|||||||
public static Tdu ResourceListComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu ResourceListComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.ResourceList, composed,
|
return new Tdu(TduIdentifier.ResourceList, composed,
|
||||||
(uint)composed.Length);
|
(uint)composed.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tdu RecordListComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu RecordListComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
var composed = DynamicArrayComposer((IEnumerable)value, warehouse, connection);
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.RecordList,
|
return new Tdu(TduIdentifier.RecordList,
|
||||||
composed, (uint)composed.Length);
|
composed, (uint)composed.Length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -835,54 +788,54 @@ public static class DataSerializer
|
|||||||
|
|
||||||
if (resource.Instance == null || resource.Instance.IsDestroyed)
|
if (resource.Instance == null || resource.Instance.IsDestroyed)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.Null, null, 0);
|
return new Tdu(TduIdentifier.Null, null, 0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Codec.IsLocalResource(resource, connection))
|
if (Codec.IsLocalResource(resource, connection))
|
||||||
{
|
{
|
||||||
var rid = (resource as EpResource).DistributedResourceInstanceId;
|
var rid = (resource as EpResource).ResourceInstanceId;
|
||||||
|
|
||||||
if (rid <= 0xFF)
|
if (rid <= 0xFF)
|
||||||
return new Tdu(TduIdentifier.LocalResource8, new byte[] { (byte)rid }, 1);
|
return new Tdu(TduIdentifier.LocalResource8, new byte[] { (byte)rid }, 1, null, null);
|
||||||
else if (rid <= 0xFFFF)
|
else if (rid <= 0xFFFF)
|
||||||
{
|
{
|
||||||
var rt = new byte[2];
|
var rt = new byte[2];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ushort*)ptr) = (ushort)rid;
|
*((ushort*)ptr) = (ushort)rid;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.LocalResource16, rt, 2);
|
return new Tdu(TduIdentifier.LocalResource16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var rt = new byte[4];
|
var rt = new byte[4];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((uint*)ptr) = rid;
|
*((uint*)ptr) = rid;
|
||||||
return new Tdu(TduIdentifier.LocalResource32, rt, 4);
|
return new Tdu(TduIdentifier.LocalResource32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
connection.cache.Add(value as IResource, DateTime.UtcNow);
|
connection._cache.Add(value as IResource, DateTime.UtcNow);
|
||||||
|
|
||||||
var rid = resource.Instance.Id;
|
var rid = resource.Instance.Id;
|
||||||
|
|
||||||
if (rid <= 0xFF)
|
if (rid <= 0xFF)
|
||||||
return new Tdu(TduIdentifier.RemoteResource8, new byte[] { (byte)rid }, 1);
|
return new Tdu(TduIdentifier.RemoteResource8, new byte[] { (byte)rid }, 1, null, null);
|
||||||
else if (rid <= 0xFFFF)
|
else if (rid <= 0xFFFF)
|
||||||
{
|
{
|
||||||
var rt = new byte[2];
|
var rt = new byte[2];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((ushort*)ptr) = (ushort)rid;
|
*((ushort*)ptr) = (ushort)rid;
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.RemoteResource16, rt, 2);
|
return new Tdu(TduIdentifier.RemoteResource16, rt, 2, null, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var rt = new byte[4];
|
var rt = new byte[4];
|
||||||
fixed (byte* ptr = rt)
|
fixed (byte* ptr = rt)
|
||||||
*((uint*)ptr) = rid;
|
*((uint*)ptr) = rid;
|
||||||
return new Tdu(TduIdentifier.RemoteResource32, rt, 4);
|
return new Tdu(TduIdentifier.RemoteResource32, rt, 4, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -890,7 +843,7 @@ public static class DataSerializer
|
|||||||
public static unsafe Tdu MapComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static unsafe Tdu MapComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 1);
|
return new Tdu(TduIdentifier.Null, new byte[0], 1, null, null);
|
||||||
|
|
||||||
var rt = new List<byte>();
|
var rt = new List<byte>();
|
||||||
var map = (IMap)value;
|
var map = (IMap)value;
|
||||||
@@ -898,12 +851,12 @@ public static class DataSerializer
|
|||||||
foreach (var el in map.Serialize())
|
foreach (var el in map.Serialize())
|
||||||
rt.AddRange(Codec.Compose(el, warehouse, connection));
|
rt.AddRange(Codec.Compose(el, warehouse, connection));
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Map, rt.ToArray(), (uint)rt.Count);
|
return new Tdu(TduIdentifier.Map, rt.ToArray(), (uint)rt.Count, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe Tdu UUIDComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static unsafe Tdu UUIDComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
return new Tdu(TduIdentifier.UUID, ((Uuid)value).Data, 16);
|
return new Tdu(TduIdentifier.UUID, ((Uuid)value).Data, 16, null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,34 +865,47 @@ public static class DataSerializer
|
|||||||
var rt = new List<byte>();
|
var rt = new List<byte>();
|
||||||
var record = (IRecord)value;
|
var record = (IRecord)value;
|
||||||
|
|
||||||
var typeDef = warehouse.GetTypeDefByType(record.GetType());
|
var recordTru = Tru.FromType(value.GetType(), warehouse) ;
|
||||||
|
|
||||||
|
TypeDef typeDef = null;
|
||||||
|
|
||||||
|
if (value is Record typedRecord)
|
||||||
|
{
|
||||||
|
typeDef = typedRecord.TypeDef;
|
||||||
|
}
|
||||||
|
else if (recordTru is TruTypeDef recordTypeDefTru)
|
||||||
|
{
|
||||||
|
// @TODO need to enhance performance, maybe cache this in the connection or something
|
||||||
|
typeDef = recordTypeDefTru.TypeDef;// recordTru.type;// .GetTypeDef(warehouse, connection.RemoteDomain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unsupported.");
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var pt in typeDef.Properties)
|
foreach (var pt in typeDef.Properties)
|
||||||
{
|
{
|
||||||
var propValue = pt.PropertyInfo.GetValue(record, null);
|
var propValue = pt.PropertyInfo.GetValue(record, null);
|
||||||
|
|
||||||
//if (propValue == null)
|
var tru = Tru.FromType(propValue?.GetType(), warehouse);
|
||||||
// return TDU(TDUIdentifier.Null, null, 0);
|
|
||||||
var tru = Tru.FromType(propValue?.GetType());
|
|
||||||
var tdu = Codec.ComposeInternal(propValue, warehouse, connection);
|
var tdu = Codec.ComposeInternal(propValue, warehouse, connection);
|
||||||
|
|
||||||
|
|
||||||
if (pt.ValueType.IsTyped() &&
|
if (tdu.Class == TduClass.Typed && // pt.ValueType.IsTyped() &&
|
||||||
pt.ValueType.Match(tru))
|
pt.ValueType.Match(tru))
|
||||||
{
|
{
|
||||||
// strip metadata
|
// strip metadata
|
||||||
var len = (uint)tdu.Composed.Length - tdu.ContentOffset;
|
var len = (uint)tdu.Composed.Length - tdu.ContentOffset;
|
||||||
tdu = new Tdu(TduIdentifier.TypeOfTarget,
|
tdu = new Tdu(TduIdentifier.TypeOfTarget,
|
||||||
tdu.Composed.Clip(tdu.ContentOffset, len), len);
|
tdu.Composed.Clip(tdu.ContentOffset, len), len, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.AddRange(tdu.Composed);
|
rt.AddRange(tdu.Composed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.Record, rt.ToArray(),
|
// @TODO: serialize metadata type Id to byte, ushort or uint depending on size.
|
||||||
(uint)rt.Count,
|
return new Tdu(TduIdentifier.Typed, rt.ToArray(), (uint)rt.Count, recordTru, connection);
|
||||||
typeDef.Id.Data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] HistoryComposer(KeyList<PropertyDef, PropertyValue[]> history, Warehouse warehouse,
|
public static byte[] HistoryComposer(KeyList<PropertyDef, PropertyValue[]> history, Warehouse warehouse,
|
||||||
@@ -961,18 +927,13 @@ public static class DataSerializer
|
|||||||
public static Tdu TupleComposer(object value, Warehouse warehouse, EpConnection connection)
|
public static Tdu TupleComposer(object value, Warehouse warehouse, EpConnection connection)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return new Tdu(TduIdentifier.Null, new byte[0], 0);
|
return new Tdu(TduIdentifier.Null, new byte[0], 0, null, null);
|
||||||
|
|
||||||
var fields = value.GetType().GetFields();
|
var fields = value.GetType().GetFields();
|
||||||
var list = fields.Select(x => x.GetValue(value)).ToArray();
|
var list = fields.Select(x => x.GetValue(value)).ToArray();
|
||||||
var trus = fields.Select(x => Tru.FromType(x.FieldType)).ToArray();
|
var trus = fields.Select(x => Tru.FromType(x.FieldType, warehouse)).ToArray();
|
||||||
|
|
||||||
|
|
||||||
var metadata = new List<byte>();
|
|
||||||
|
|
||||||
foreach (var t in trus)
|
|
||||||
metadata.AddRange(t.Compose());
|
|
||||||
|
|
||||||
var rt = new List<byte>();
|
var rt = new List<byte>();
|
||||||
|
|
||||||
for (var i = 0; i < fields.Length; i++)
|
for (var i = 0; i < fields.Length; i++)
|
||||||
@@ -982,22 +943,36 @@ public static class DataSerializer
|
|||||||
|
|
||||||
var tdu = Codec.ComposeInternal(tupleValue, warehouse, connection);
|
var tdu = Codec.ComposeInternal(tupleValue, warehouse, connection);
|
||||||
|
|
||||||
var valueTru = Tru.FromType(tupleValue?.GetType());
|
var valueTru = Tru.FromType(tupleValue?.GetType(), warehouse);
|
||||||
|
|
||||||
if (targetTru.IsTyped() &&
|
if (tdu.Class == TduClass.Typed && // targetTru.IsTyped() &&
|
||||||
targetTru.Match(valueTru))
|
targetTru.Match(valueTru))
|
||||||
{
|
{
|
||||||
// strip metadata
|
// strip metadata
|
||||||
var len = (uint)tdu.Composed.Length - tdu.ContentOffset;
|
var len = (uint)tdu.Composed.Length - tdu.ContentOffset;
|
||||||
tdu = new Tdu(TduIdentifier.TypeOfTarget,
|
tdu = new Tdu(TduIdentifier.TypeOfTarget,
|
||||||
tdu.Composed.Clip(tdu.ContentOffset, len), len);
|
tdu.Composed.Clip(tdu.ContentOffset, len), len, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.AddRange(tdu.Composed);
|
rt.AddRange(tdu.Composed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tdu(TduIdentifier.TypedTuple, rt.ToArray(),
|
//return new Tdu(TduIdentifier.TypedTuple, rt.ToArray(),
|
||||||
(uint)rt.Count, metadata.ToArray());
|
// (uint)rt.Count, metadata.ToArray());
|
||||||
|
|
||||||
|
var truIdentifier = trus.Length switch
|
||||||
|
{
|
||||||
|
2 => TruIdentifier.Tuple2,
|
||||||
|
3 => TruIdentifier.Tuple3,
|
||||||
|
4 => TruIdentifier.Tuple4,
|
||||||
|
5 => TruIdentifier.Tuple5,
|
||||||
|
6 => TruIdentifier.Tuple6,
|
||||||
|
7 => TruIdentifier.Tuple7,
|
||||||
|
_ => throw new NotSupportedException("Tuples with more than 7 or less than 2 elements are not supported.")
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Tdu(TduIdentifier.Typed, rt.ToArray(),
|
||||||
|
(uint)rt.Count, new TruComposite(truIdentifier, false, trus, value.GetType()), connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public interface IParseResult<out T>
|
||||||
|
{
|
||||||
|
public T Value { get; }
|
||||||
|
public uint Size { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Esiur.Data.Types;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public interface IRemoteRecord: IRecord
|
||||||
|
{
|
||||||
|
public RemoteTypeDef TypeDef { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,11 +96,7 @@ public class Map<KT, VT> : Dictionary<KT, VT>, IMap // IEnumerable<KeyValuePair<
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var rt = "";
|
return "{" + string.Join(", ", this.Select(x => $"{x.Key}: {x.Value}")) + "}";
|
||||||
foreach (var kv in this)
|
|
||||||
rt += kv.Key + ": " + kv.Value.ToString() + " \r\n";
|
|
||||||
|
|
||||||
return rt.TrimEnd('\r', '\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//public Map(Map<KT,VT> source)
|
//public Map(Map<KT,VT> source)
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public readonly struct ParseResult<T>: IParseResult<T>
|
||||||
|
{
|
||||||
|
public T Value { get; }
|
||||||
|
public uint Size { get; }
|
||||||
|
|
||||||
|
public ParseResult(T value, uint size)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
using System;
|
using Esiur.Core;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using Esiur.Resource;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -9,16 +12,22 @@ namespace Esiur.Data
|
|||||||
public TduIdentifier Identifier;
|
public TduIdentifier Identifier;
|
||||||
public int Index;
|
public int Index;
|
||||||
public TduClass Class;
|
public TduClass Class;
|
||||||
public uint Offset;
|
public uint PayloadOffset;
|
||||||
public ulong ContentLength;
|
public ulong PayloadLength;
|
||||||
public byte[] Data;
|
public byte[] Data;
|
||||||
public byte Exponent;
|
public byte Exponent;
|
||||||
public ulong TotalLength;
|
public ulong TotalLength;
|
||||||
public byte[] Metadata;
|
public Tru Metadata;
|
||||||
public uint Ends;
|
public uint Ends;
|
||||||
|
|
||||||
public static ParsedTdu Parse(byte[] data, uint offset, uint ends)
|
public static AsyncReply<ParsedTdu> ParseAsync(byte[] data, EpConnection connection)
|
||||||
{
|
{
|
||||||
|
return ParseAsync(data, (uint)0, (uint)data.Length, connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async AsyncReply<ParsedTdu> ParseAsync(byte[] data, uint offset, uint ends, EpConnection connection)
|
||||||
|
{
|
||||||
|
// @TODO: add protection against memory allocation attacks by checking the length of the data before parsing it.
|
||||||
|
|
||||||
var h = data[offset++];
|
var h = data[offset++];
|
||||||
|
|
||||||
@@ -33,11 +42,11 @@ namespace Esiur.Data
|
|||||||
{
|
{
|
||||||
Identifier = (TduIdentifier)h,
|
Identifier = (TduIdentifier)h,
|
||||||
Data = data,
|
Data = data,
|
||||||
Offset = offset,
|
PayloadOffset = offset,
|
||||||
Class = cls,
|
Class = cls,
|
||||||
Exponent = (byte)exp,
|
Exponent = (byte)exp,
|
||||||
Index = (byte)h & 0x7,
|
Index = (byte)h & 0x7,
|
||||||
ContentLength = 0,
|
PayloadLength = 0,
|
||||||
TotalLength = 1,
|
TotalLength = 1,
|
||||||
Ends = ends
|
Ends = ends
|
||||||
};
|
};
|
||||||
@@ -57,9 +66,9 @@ namespace Esiur.Data
|
|||||||
{
|
{
|
||||||
Identifier = (TduIdentifier)h,
|
Identifier = (TduIdentifier)h,
|
||||||
Data = data,
|
Data = data,
|
||||||
Offset = offset,
|
PayloadOffset = offset,
|
||||||
Class = cls,
|
Class = cls,
|
||||||
ContentLength = cl,
|
PayloadLength = cl,
|
||||||
TotalLength = 1 + cl,
|
TotalLength = 1 + cl,
|
||||||
Exponent = (byte)exp,
|
Exponent = (byte)exp,
|
||||||
Index = (byte)h & 0x7,
|
Index = (byte)h & 0x7,
|
||||||
@@ -89,20 +98,22 @@ namespace Esiur.Data
|
|||||||
Class = TduClass.Invalid,
|
Class = TduClass.Invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
var metaData = DC.Clip(data, offset + 1, data[offset]);
|
//var metaData = DC.Clip(data, offset + 1, data[offset]);
|
||||||
offset += data[offset] + (uint)1;
|
//offset += data[offset] + (uint)1;
|
||||||
|
|
||||||
|
var metaDataTru = await Tru.ParseAsync(data, offset, connection, null);
|
||||||
|
offset += metaDataTru.Size;
|
||||||
|
|
||||||
return new ParsedTdu()
|
return new ParsedTdu()
|
||||||
{
|
{
|
||||||
Identifier = (TduIdentifier)(h & 0xC7),
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
Data = data,
|
Data = data,
|
||||||
Offset = offset,
|
PayloadOffset = offset,
|
||||||
Class = cls,
|
Class = cls,
|
||||||
ContentLength = cl - 1 - (uint)metaData.Length,
|
PayloadLength = cl - metaDataTru.Size,
|
||||||
TotalLength = 1 + cl + cll,
|
TotalLength = 1 + cl + cll,
|
||||||
Index = (byte)h & 0x7,
|
Index = (byte)h & 0x7,
|
||||||
Metadata = metaData,
|
Metadata = metaDataTru.Value,
|
||||||
Ends = ends
|
Ends = ends
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -135,9 +146,9 @@ namespace Esiur.Data
|
|||||||
{
|
{
|
||||||
Identifier = (TduIdentifier)(h & 0xC7),
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
Data = data,
|
Data = data,
|
||||||
Offset = offset,
|
PayloadOffset = offset,
|
||||||
Class = cls,
|
Class = cls,
|
||||||
ContentLength = cl,
|
PayloadLength = cl,
|
||||||
TotalLength = 1 + cl + cll,
|
TotalLength = 1 + cl + cll,
|
||||||
Index = (byte)h & 0x7,
|
Index = (byte)h & 0x7,
|
||||||
Ends = ends
|
Ends = ends
|
||||||
@@ -145,5 +156,324 @@ namespace Esiur.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static object Parse(byte[] data, uint offset, uint ends, EpConnection connection)
|
||||||
|
{
|
||||||
|
// @TODO: add protection against memory allocation attacks by checking the length of the data before parsing it.
|
||||||
|
|
||||||
|
var h = data[offset++];
|
||||||
|
|
||||||
|
var cls = (TduClass)(h >> 6);
|
||||||
|
|
||||||
|
if (cls == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
var exp = (h & 0x38) >> 3;
|
||||||
|
|
||||||
|
if (exp == 0)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
PayloadLength = 0,
|
||||||
|
TotalLength = 1,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = (ulong)(1 << (exp - 1));
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
//offset += (uint)cl;
|
||||||
|
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (cls == TduClass.Typed)
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
TotalLength = (cl - (ends - offset)),
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
//var metaData = DC.Clip(data, offset + 1, data[offset]);
|
||||||
|
//offset += data[offset] + (uint)1;
|
||||||
|
var rt = new AsyncReply<ParsedTdu>();
|
||||||
|
|
||||||
|
Tru.ParseAsync(data, offset, connection, null).Then(metaDataTru =>
|
||||||
|
{
|
||||||
|
offset += metaDataTru.Size;
|
||||||
|
|
||||||
|
rt.Trigger(new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl - metaDataTru.Size,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Metadata = metaDataTru.Value,
|
||||||
|
Ends = ends
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ClipTduData(byte[] data, uint offset, uint ends)
|
||||||
|
{
|
||||||
|
var oOffset = (int)offset;
|
||||||
|
|
||||||
|
var h = data[offset++];
|
||||||
|
|
||||||
|
var cls = (TduClass)(h >> 6);
|
||||||
|
|
||||||
|
if (cls == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
var exp = (h & 0x38) >> 3;
|
||||||
|
|
||||||
|
if (exp == 0)
|
||||||
|
{
|
||||||
|
return new byte[] { h };
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong cl = (ulong)(1 << (exp - 1));
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
{
|
||||||
|
return null; // failded
|
||||||
|
}
|
||||||
|
|
||||||
|
var rt = new byte[1 + cl];
|
||||||
|
Buffer.BlockCopy(data, oOffset, rt, 0, (int)cl);
|
||||||
|
return rt;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var rt = new byte[1 + cll + cl];
|
||||||
|
|
||||||
|
Buffer.BlockCopy(data, oOffset, rt, 0, rt.Length);
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ParsedTdu ParseSync(byte[] data, uint offset, uint ends, Warehouse warehouse)
|
||||||
|
{
|
||||||
|
// @TODO: add protection against memory allocation attacks by checking the length of the data before parsing it.
|
||||||
|
|
||||||
|
var h = data[offset++];
|
||||||
|
|
||||||
|
var cls = (TduClass)(h >> 6);
|
||||||
|
|
||||||
|
if (cls == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
var exp = (h & 0x38) >> 3;
|
||||||
|
|
||||||
|
if (exp == 0)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
PayloadLength = 0,
|
||||||
|
TotalLength = 1,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = (ulong)(1 << (exp - 1));
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
//offset += (uint)cl;
|
||||||
|
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (cls == TduClass.Typed)
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
TotalLength = (cl - (ends - offset)),
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
//var metaData = DC.Clip(data, offset + 1, data[offset]);
|
||||||
|
//offset += data[offset] + (uint)1;
|
||||||
|
|
||||||
|
var metaDataTru = Tru.Parse(data, offset, warehouse);
|
||||||
|
offset += metaDataTru.Size;
|
||||||
|
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl - metaDataTru.Size,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Metadata = metaDataTru.Value,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new ParsedTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
new ParsedTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
using Esiur.Core;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public struct PlainTdu
|
||||||
|
{
|
||||||
|
public TduIdentifier Identifier;
|
||||||
|
public int Index;
|
||||||
|
public TduClass Class;
|
||||||
|
public uint TduOffset;
|
||||||
|
public uint PayloadOffset;
|
||||||
|
public ulong PayloadLength;
|
||||||
|
public byte[] Data;
|
||||||
|
public byte Exponent;
|
||||||
|
public ulong TotalLength;
|
||||||
|
public uint Ends;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static PlainTdu Parse(byte[] data, uint offset, uint ends)
|
||||||
|
{
|
||||||
|
var oOffset = offset;
|
||||||
|
|
||||||
|
// @TODO: add protection against memory allocation attacks by checking the length of the data before parsing it.
|
||||||
|
|
||||||
|
var h = data[offset++];
|
||||||
|
|
||||||
|
var cls = (TduClass)(h >> 6);
|
||||||
|
|
||||||
|
if (cls == TduClass.Fixed)
|
||||||
|
{
|
||||||
|
var exp = (h & 0x38) >> 3;
|
||||||
|
|
||||||
|
if (exp == 0)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
TduOffset = oOffset,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
PayloadLength = 0,
|
||||||
|
TotalLength = 1,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = (ulong)(1 << (exp - 1));
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
//offset += (uint)cl;
|
||||||
|
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)h,
|
||||||
|
Data = data,
|
||||||
|
TduOffset= oOffset,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl,
|
||||||
|
Exponent = (byte)exp,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (cls == TduClass.Typed)
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
TotalLength = (cl - (ends - offset)),
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
TduOffset = oOffset,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||||
|
|
||||||
|
if (ends - offset < cll)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cll - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
ulong cl = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < cll; i++)
|
||||||
|
cl = cl << 8 | data[offset++];
|
||||||
|
|
||||||
|
if (ends - offset < cl)
|
||||||
|
return new PlainTdu()
|
||||||
|
{
|
||||||
|
Class = TduClass.Invalid,
|
||||||
|
TotalLength = (cl - (ends - offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
new PlainTdu()
|
||||||
|
{
|
||||||
|
Identifier = (TduIdentifier)(h & 0xC7),
|
||||||
|
Data = data,
|
||||||
|
TduOffset = oOffset,
|
||||||
|
PayloadOffset = offset,
|
||||||
|
Class = cls,
|
||||||
|
PayloadLength = cl,
|
||||||
|
TotalLength = 1 + cl + cll,
|
||||||
|
Index = (byte)h & 0x7,
|
||||||
|
Ends = ends
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
using System;
|
using Esiur.Data.Types;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Esiur.Data;
|
namespace Esiur.Data;
|
||||||
|
|
||||||
public class Record : KeyList<string, object>, IRecord
|
public class Record : KeyList<string, object>, IRecord
|
||||||
{
|
{
|
||||||
|
public TypeDef TypeDef { get; private set; }
|
||||||
|
|
||||||
|
public Record(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
TypeDef = typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Record<{TypeDef.Name}> {{{string.Join(", ", this.Select(x=>x.Key + ": " + x.Value))}}}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-49
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Esiur.Protocol;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
@@ -18,7 +19,7 @@ public struct Tdu
|
|||||||
public byte[] Composed;
|
public byte[] Composed;
|
||||||
//public uint Offset;
|
//public uint Offset;
|
||||||
|
|
||||||
public byte[] Metadata;
|
public Tru Metadata;
|
||||||
|
|
||||||
public uint ContentOffset;
|
public uint ContentOffset;
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ public struct Tdu
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Tdu(TduIdentifier identifier,
|
public Tdu(TduIdentifier identifier,
|
||||||
byte[] data, ulong length, byte[] metadata = null)
|
byte[] data, ulong length, Tru metadata, EpConnection connection)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
//Index = (byte)identifier & 0x7;
|
//Index = (byte)identifier & 0x7;
|
||||||
@@ -174,34 +175,20 @@ public struct Tdu
|
|||||||
if (metadata == null)
|
if (metadata == null)
|
||||||
throw new Exception("Metadata must be provided for types.");
|
throw new Exception("Metadata must be provided for types.");
|
||||||
|
|
||||||
|
var metadataData = metadata.Compose(connection);
|
||||||
if (metadata.Length > 0xFF)
|
|
||||||
throw new Exception("Metadata can't exceed 255 bytes in length.");
|
|
||||||
|
|
||||||
var metaLen = (byte)metadata.Length;
|
|
||||||
|
|
||||||
var len = 1 + (ulong)metaLen + length;
|
|
||||||
|
|
||||||
|
|
||||||
if (length == 0 && (metadata == null || metadata.Length == 0))
|
var len = (ulong)metadataData.Length + length;
|
||||||
{
|
|
||||||
Composed = new byte[1] { (byte)Identifier };
|
if (len <= 0xFF)
|
||||||
throw new Exception("Need check");
|
|
||||||
}
|
|
||||||
else if (metadata.Length > 0xFF)
|
|
||||||
{
|
|
||||||
throw new Exception("Metadata can't exceed 255 bytes in length.");
|
|
||||||
}
|
|
||||||
else if (length <= 0xFF)
|
|
||||||
{
|
{
|
||||||
Composed = new byte[2 + len];
|
Composed = new byte[2 + len];
|
||||||
Composed[0] = (byte)((byte)Identifier | 0x8);
|
Composed[0] = (byte)((byte)Identifier | 0x8);
|
||||||
Composed[1] = (byte)len;
|
Composed[1] = (byte)len;
|
||||||
Composed[2] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)2;
|
||||||
ContentOffset = metaLen + (uint)3;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 3, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 2, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 3 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 2 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
else if (len <= 0xFF_FF)
|
else if (len <= 0xFF_FF)
|
||||||
{
|
{
|
||||||
@@ -209,11 +196,10 @@ public struct Tdu
|
|||||||
Composed[0] = (byte)((byte)identifier | 0x10);
|
Composed[0] = (byte)((byte)identifier | 0x10);
|
||||||
Composed[1] = (byte)((len >> 8) & 0xFF);
|
Composed[1] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[2] = (byte)(len & 0xFF);
|
Composed[2] = (byte)(len & 0xFF);
|
||||||
Composed[3] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)3;
|
||||||
ContentOffset = metaLen + (uint)4;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 4, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 3, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 4 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 3 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
else if (len <= 0xFF_FF_FF)
|
else if (len <= 0xFF_FF_FF)
|
||||||
{
|
{
|
||||||
@@ -222,11 +208,10 @@ public struct Tdu
|
|||||||
Composed[1] = (byte)((len >> 16) & 0xFF);
|
Composed[1] = (byte)((len >> 16) & 0xFF);
|
||||||
Composed[2] = (byte)((len >> 8) & 0xFF);
|
Composed[2] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[3] = (byte)(len & 0xFF);
|
Composed[3] = (byte)(len & 0xFF);
|
||||||
Composed[4] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)4;
|
||||||
ContentOffset = metaLen + (uint)5;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 5, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 4, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 5 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 4 + metadataData.Length, (int)length);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (len <= 0xFF_FF_FF_FF)
|
else if (len <= 0xFF_FF_FF_FF)
|
||||||
@@ -237,11 +222,10 @@ public struct Tdu
|
|||||||
Composed[2] = (byte)((len >> 16) & 0xFF);
|
Composed[2] = (byte)((len >> 16) & 0xFF);
|
||||||
Composed[3] = (byte)((len >> 8) & 0xFF);
|
Composed[3] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[4] = (byte)(len & 0xFF);
|
Composed[4] = (byte)(len & 0xFF);
|
||||||
Composed[5] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)5;
|
||||||
ContentOffset = metaLen + (uint)6;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 6, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 5, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 6 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 5 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
else if (len <= 0xFF_FF_FF_FF_FF)
|
else if (len <= 0xFF_FF_FF_FF_FF)
|
||||||
{
|
{
|
||||||
@@ -252,11 +236,10 @@ public struct Tdu
|
|||||||
Composed[3] = (byte)((len >> 16) & 0xFF);
|
Composed[3] = (byte)((len >> 16) & 0xFF);
|
||||||
Composed[4] = (byte)((len >> 8) & 0xFF);
|
Composed[4] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[5] = (byte)(len & 0xFF);
|
Composed[5] = (byte)(len & 0xFF);
|
||||||
Composed[6] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)6;
|
||||||
ContentOffset = metaLen + (uint)7;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 7, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 6, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 7 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 6 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
else if (len <= 0xFF_FF_FF_FF_FF_FF)
|
else if (len <= 0xFF_FF_FF_FF_FF_FF)
|
||||||
{
|
{
|
||||||
@@ -268,11 +251,10 @@ public struct Tdu
|
|||||||
Composed[4] = (byte)((len >> 16) & 0xFF);
|
Composed[4] = (byte)((len >> 16) & 0xFF);
|
||||||
Composed[5] = (byte)((len >> 8) & 0xFF);
|
Composed[5] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[6] = (byte)(len & 0xFF);
|
Composed[6] = (byte)(len & 0xFF);
|
||||||
Composed[7] = metaLen;
|
ContentOffset = (uint)metadataData.Length + (uint)7;
|
||||||
ContentOffset = metaLen + (uint)8;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 8, metaLen);
|
Buffer.BlockCopy(metadataData, 0, Composed, 7, metadataData.Length);
|
||||||
Buffer.BlockCopy(data, 0, Composed, 8 + metaLen, (int)length);
|
Buffer.BlockCopy(data, 0, Composed, 7 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
else //if (len <= 0xFF_FF_FF_FF_FF_FF_FF)
|
else //if (len <= 0xFF_FF_FF_FF_FF_FF_FF)
|
||||||
{
|
{
|
||||||
@@ -285,11 +267,11 @@ public struct Tdu
|
|||||||
Composed[5] = (byte)((len >> 16) & 0xFF);
|
Composed[5] = (byte)((len >> 16) & 0xFF);
|
||||||
Composed[6] = (byte)((len >> 8) & 0xFF);
|
Composed[6] = (byte)((len >> 8) & 0xFF);
|
||||||
Composed[7] = (byte)(len & 0xFF);
|
Composed[7] = (byte)(len & 0xFF);
|
||||||
Composed[8] = metaLen;
|
|
||||||
ContentOffset = metaLen + (uint)9;
|
|
||||||
|
|
||||||
Buffer.BlockCopy(metadata, 0, Composed, 9, metaLen);
|
ContentOffset = (uint)metadataData.Length + (uint)8;
|
||||||
Buffer.BlockCopy(data, 0, Composed, 9 + metaLen, (int)length);
|
|
||||||
|
Buffer.BlockCopy(metadataData, 0, Composed, 8, metadataData.Length);
|
||||||
|
Buffer.BlockCopy(data, 0, Composed, 8 + metadataData.Length, (int)length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +287,7 @@ public struct Tdu
|
|||||||
if (Class != TduClass.Typed || with.Class != TduClass.Typed)
|
if (Class != TduClass.Typed || with.Class != TduClass.Typed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Metadata.SequenceEqual(with.Metadata))
|
if (!Metadata.Match(with.Metadata))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -50,12 +50,14 @@ namespace Esiur.Data
|
|||||||
Map = 0x46,
|
Map = 0x46,
|
||||||
MapList = 0x47,
|
MapList = 0x47,
|
||||||
|
|
||||||
Record = 0x80,
|
Typed = 0x80,
|
||||||
TypedList = 0x81,
|
|
||||||
TypedMap = 0x82,
|
//Record = 0x80,
|
||||||
TypedTuple = 0x83,
|
//TypedList = 0x81,
|
||||||
TypedEnum = 0x84,
|
//TypedMap = 0x82,
|
||||||
TypedConstant = 0x85,
|
//TypedTuple = 0x83,
|
||||||
|
//TypedEnum = 0x84,
|
||||||
|
//TypedConstant = 0x85,
|
||||||
|
|
||||||
TypeContinuation = 0xC0,
|
TypeContinuation = 0xC0,
|
||||||
TypeOfTarget = 0xC1,
|
TypeOfTarget = 0xC1,
|
||||||
|
|||||||
+584
-294
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
|||||||
|
using Esiur.Data.Types;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using Esiur.Resource;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
internal class TruComposite : Tru
|
||||||
|
{
|
||||||
|
public Tru[] SubTypes;
|
||||||
|
|
||||||
|
Type _runtimeType;
|
||||||
|
|
||||||
|
public override Type RuntimeType { get; protected set; }
|
||||||
|
|
||||||
|
public TruComposite(TruIdentifier identifier, bool nullable, Tru[] subTypes, Type type)
|
||||||
|
{
|
||||||
|
Identifier = identifier;
|
||||||
|
Nullable = nullable;
|
||||||
|
SubTypes = subTypes;
|
||||||
|
RuntimeType = type;
|
||||||
|
//_runtimeType = typeof(Tuple).MakeGenericType(subTypes.Select(x => x.RuntimeType).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() == 2);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var st in SubTypes)
|
||||||
|
st.SetNull(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void SetNull(byte flag)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flag == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var st in SubTypes)
|
||||||
|
st.SetNull(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() != 1);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var st in SubTypes)
|
||||||
|
st.SetNotNull(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(byte flag)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flag != 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SubTypes != null)
|
||||||
|
foreach (var st in SubTypes)
|
||||||
|
st.SetNotNull(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Match(Tru other)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (other is TruComposite otherComposite)
|
||||||
|
{
|
||||||
|
if (other.Identifier != Identifier)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
if (otherComposite.SubTypes.Length != (SubTypes?.Length ?? -1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < SubTypes?.Length; i++)
|
||||||
|
if (!SubTypes[i].Match(otherComposite.SubTypes[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Identifier.ToString() + "<" + String.Join(",", SubTypes.Select(x => x.ToString())) + ">" + (Nullable ? "?" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] Compose(EpConnection connection)
|
||||||
|
{
|
||||||
|
var rt = new BinaryList();
|
||||||
|
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8((byte)(0x80 | (byte)Identifier));
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)Identifier);
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < SubTypes.Length; i++)
|
||||||
|
rt.AddUInt8Array(SubTypes[i].Compose(connection));
|
||||||
|
|
||||||
|
return rt.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Tru ToNullable()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,10 +30,20 @@ namespace Esiur.Data
|
|||||||
Record,
|
Record,
|
||||||
List,
|
List,
|
||||||
Map,
|
Map,
|
||||||
Enum = 0x44,
|
//Enum = 0x44,
|
||||||
TypedResource = 0x45, // Followed by UUID
|
//TypedResource = 0x45, // Followed by UUID
|
||||||
TypedRecord = 0x46, // Followed by UUID
|
//TypedRecord = 0x46, // Followed by UUID
|
||||||
|
LocalType8 = 0x40,
|
||||||
|
RemoteType8 = 0x41,
|
||||||
|
LocalType16 = 0x42,
|
||||||
|
RemoteType16 = 0x43,
|
||||||
|
LocalType32 = 0x44,
|
||||||
|
RemoteType32 = 0x45,
|
||||||
|
LocalType64 = 0x46,
|
||||||
|
RemoteType64 = 0x47,
|
||||||
|
|
||||||
TypedList = 0x48, // Followed by element type
|
TypedList = 0x48, // Followed by element type
|
||||||
|
|
||||||
Tuple2 = 0x50, // Followed by element type
|
Tuple2 = 0x50, // Followed by element type
|
||||||
TypedMap = 0x51, // Followed by key type and value type
|
TypedMap = 0x51, // Followed by key type and value type
|
||||||
Tuple3 = 0x58,
|
Tuple3 = 0x58,
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using Esiur.Data.Types;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public class TruPrimitive:Tru
|
||||||
|
{
|
||||||
|
public override Type RuntimeType { get; protected set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Identifier.ToString() + (Nullable ? "?" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TruPrimitive(TruIdentifier identifier, bool nullable, Type type)
|
||||||
|
{
|
||||||
|
Identifier = identifier;
|
||||||
|
Nullable = nullable;
|
||||||
|
RuntimeType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() == 2);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void SetNull(byte flag)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flag == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() != 1);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(byte flag)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flag != 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Match(Tru other)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (other is TruPrimitive otherComposite)
|
||||||
|
{
|
||||||
|
if (other.Identifier != Identifier)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] Compose(EpConnection connection)
|
||||||
|
{
|
||||||
|
var rt = new BinaryList();
|
||||||
|
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8((byte)(0x80 | (byte)Identifier));
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)Identifier);
|
||||||
|
|
||||||
|
return rt.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Tru ToNullable()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
using Esiur.Data.Types;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public class TruTypeDef : Tru
|
||||||
|
{
|
||||||
|
public TypeDef? TypeDef;
|
||||||
|
|
||||||
|
public override Type RuntimeType { get; protected set; }
|
||||||
|
|
||||||
|
public override void SetNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
if (RefTypes.Contains(Identifier))
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() == 2);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TruTypeDef(bool nullable, TypeDef typeDef)
|
||||||
|
{
|
||||||
|
Nullable = nullable;
|
||||||
|
TypeDef = typeDef;
|
||||||
|
|
||||||
|
if (typeDef is LocalTypeDef localTypeDef)
|
||||||
|
RuntimeType = localTypeDef.DefinedType;
|
||||||
|
else if (typeDef is RemoteTypeDef remoteTypeDef)
|
||||||
|
RuntimeType = remoteTypeDef.ProxyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNull(byte flag)
|
||||||
|
{
|
||||||
|
Nullable = (flag == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(List<byte> flags)
|
||||||
|
{
|
||||||
|
Nullable = (flags.FirstOrDefault() != 1);
|
||||||
|
if (flags.Count > 0)
|
||||||
|
flags.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetNotNull(byte flag)
|
||||||
|
{
|
||||||
|
Nullable = (flag != 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Match(Tru other)
|
||||||
|
{
|
||||||
|
if (other is TruTypeDef otherComposite)
|
||||||
|
{
|
||||||
|
if (otherComposite.TypeDef != TypeDef)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Identifier.ToString() + (Nullable ? "?" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] Compose(EpConnection connection)
|
||||||
|
{
|
||||||
|
var rt = new BinaryList();
|
||||||
|
|
||||||
|
if (TypeDef is RemoteTypeDef remoteTypeDef)
|
||||||
|
{
|
||||||
|
if (connection.RemoteDomain == remoteTypeDef.Domain)
|
||||||
|
{
|
||||||
|
// this is local in respect to the connection, send the remote typdef id.
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8(0x80 | (byte)TruIdentifier.LocalType8);
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)TruIdentifier.LocalType8);
|
||||||
|
|
||||||
|
rt.AddUInt8((byte)remoteTypeDef.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this is remote in respect to the connection and the local typedef id is used.
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8(0x80 | (byte)TruIdentifier.RemoteType8);
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)TruIdentifier.RemoteType8);
|
||||||
|
|
||||||
|
rt.AddUInt8((byte)remoteTypeDef.LocalTypeDefId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (TypeDef is LocalTypeDef localTypeDef)
|
||||||
|
{
|
||||||
|
if (connection == null)
|
||||||
|
{
|
||||||
|
// if there is no connection, we assume it's local.
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8(0x80 | (byte)TruIdentifier.LocalType8);
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)TruIdentifier.LocalType8);
|
||||||
|
|
||||||
|
rt.AddUInt8((byte)localTypeDef.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this is remote, unless the connection is to self @TODO: solve for this state.
|
||||||
|
if (Nullable)
|
||||||
|
rt.AddUInt8(0x80 | (byte)TruIdentifier.RemoteType8);
|
||||||
|
else
|
||||||
|
rt.AddUInt8((byte)TruIdentifier.RemoteType8);
|
||||||
|
|
||||||
|
rt.AddUInt8((byte)localTypeDef.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
return rt.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Tru ToNullable()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data
|
||||||
|
{
|
||||||
|
public struct TypeDefId
|
||||||
|
{
|
||||||
|
public ulong Value;
|
||||||
|
public bool Remote;
|
||||||
|
|
||||||
|
public TypeDefId(ulong value, bool remote)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override int GetHashCode()
|
||||||
|
{
|
||||||
|
// Fallback implementation when System.HashCode is not available.
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hash = ((int)Value) ^ ((int)(Value >> 32));
|
||||||
|
hash = (hash * 397) ^ (Remote ? 1 : 0);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()=> $"{(Remote ? "Remote" : "Local")}TypeDef{Value}";
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is TypeDefId b)
|
||||||
|
return Value == b.Value && Remote == b.Remote;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator == (TypeDefId a, TypeDefId b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(TypeDefId a, TypeDefId b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
using Esiur.Data;
|
using Esiur.Core;
|
||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Protocol;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Drawing;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Esiur.Data.Types;
|
namespace Esiur.Data.Types;
|
||||||
|
|
||||||
@@ -20,7 +23,7 @@ public class ArgumentDef
|
|||||||
|
|
||||||
public Map<string, string> Annotations { get; set; }
|
public Map<string, string> Annotations { get; set; }
|
||||||
|
|
||||||
public static (uint, ArgumentDef) Parse(byte[] data, uint offset, int index)
|
public static async AsyncReply<ParseResult<ArgumentDef>> ParseAsync(byte[] data, uint offset, int index, EpConnection connection, ulong[] requestSequence)
|
||||||
{
|
{
|
||||||
var optional = (data[offset] & 0x1) == 0x1;
|
var optional = (data[offset] & 0x1) == 0x1;
|
||||||
var hasAnnotations = (data[offset++] & 0x2) == 0x2;
|
var hasAnnotations = (data[offset++] & 0x2) == 0x2;
|
||||||
@@ -28,9 +31,9 @@ public class ArgumentDef
|
|||||||
var cs = (uint)data[offset++];
|
var cs = (uint)data[offset++];
|
||||||
var name = data.GetString(offset, cs);
|
var name = data.GetString(offset, cs);
|
||||||
offset += cs;
|
offset += cs;
|
||||||
var (size, type) = Tru.Parse(data, offset);
|
var type = await Tru.ParseAsync(data, offset, connection, requestSequence);
|
||||||
|
|
||||||
offset += size;
|
offset += type.Size;
|
||||||
|
|
||||||
Map<string, string> annotations = null;
|
Map<string, string> annotations = null;
|
||||||
|
|
||||||
@@ -46,14 +49,14 @@ public class ArgumentDef
|
|||||||
cs += l;
|
cs += l;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (cs + 2 + size, new ArgumentDef()
|
return new ParseResult<ArgumentDef>(new ArgumentDef()
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
Index = index,
|
Index = index,
|
||||||
Type = type,
|
Type = type.Value,
|
||||||
Optional = optional,
|
Optional = optional,
|
||||||
Annotations = annotations
|
Annotations = annotations
|
||||||
});
|
}, cs + 2 + type.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArgumentDef()
|
public ArgumentDef()
|
||||||
@@ -70,7 +73,7 @@ public class ArgumentDef
|
|||||||
return $"{Name}: {Type} ";
|
return $"{Name}: {Type} ";
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Compose()
|
public byte[] Compose(EpConnection connection)
|
||||||
{
|
{
|
||||||
var name = DC.ToBytes(Name);
|
var name = DC.ToBytes(Name);
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ public class ArgumentDef
|
|||||||
.AddUInt8(Optional ? (byte)1 : (byte)0)
|
.AddUInt8(Optional ? (byte)1 : (byte)0)
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(Type.Compose())
|
.AddUInt8Array(Type.Compose(connection))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -91,7 +94,7 @@ public class ArgumentDef
|
|||||||
.AddUInt8((byte)(0x2 | (Optional ? 1 : 0)))
|
.AddUInt8((byte)(0x2 | (Optional ? 1 : 0)))
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(Type.Compose())
|
.AddUInt8Array(Type.Compose(connection))
|
||||||
.AddUInt8Array(exp)
|
.AddUInt8Array(exp)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Esiur.Core;
|
||||||
using Esiur.Data;
|
using Esiur.Data;
|
||||||
|
using Esiur.Protocol;
|
||||||
using Esiur.Resource;
|
using Esiur.Resource;
|
||||||
|
|
||||||
namespace Esiur.Data.Types;
|
namespace Esiur.Data.Types;
|
||||||
@@ -18,7 +20,7 @@ public class ConstantDef : MemberDef
|
|||||||
public FieldInfo FieldInfo { get; set; }
|
public FieldInfo FieldInfo { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public static (uint, ConstantDef) Parse(byte[] data, uint offset, byte index, bool inherited)
|
public static async AsyncReply< ParseResult<ConstantDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
|
||||||
{
|
{
|
||||||
var oOffset = offset;
|
var oOffset = offset;
|
||||||
|
|
||||||
@@ -27,11 +29,16 @@ public class ConstantDef : MemberDef
|
|||||||
var name = data.GetString(offset + 1, data[offset]);
|
var name = data.GetString(offset + 1, data[offset]);
|
||||||
offset += (uint)data[offset] + 1;
|
offset += (uint)data[offset] + 1;
|
||||||
|
|
||||||
var (dts, valueType) = Tru.Parse(data, offset);
|
//Console.WriteLine("Parsing constantDef " + name);
|
||||||
|
|
||||||
offset += dts;
|
//var (dts, valueType)
|
||||||
|
var valueType = await Tru.ParseAsync(data, offset, connection, requestSequence);
|
||||||
|
|
||||||
(dts, var value) = Codec.ParseSync(data, offset, Warehouse.Default);
|
//Console.WriteLine("Parsing constantDef 2 " + name);
|
||||||
|
|
||||||
|
offset += valueType.Size;
|
||||||
|
|
||||||
|
(var dts, var value) = Codec.ParseSync(data, offset, Warehouse.Default);
|
||||||
|
|
||||||
offset += dts;
|
offset += dts;
|
||||||
|
|
||||||
@@ -48,19 +55,19 @@ public class ConstantDef : MemberDef
|
|||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offset - oOffset, new ConstantDef()
|
return new ParseResult<ConstantDef>( new ConstantDef()
|
||||||
{
|
{
|
||||||
Index = index,
|
Index = index,
|
||||||
Name = name,
|
Name = name,
|
||||||
Inherited = inherited,
|
Inherited = inherited,
|
||||||
ValueType = valueType,
|
ValueType = valueType.Value,
|
||||||
Value = value,
|
Value = value,
|
||||||
Annotations = annotations
|
Annotations = annotations
|
||||||
});
|
}, offset - oOffset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Compose()
|
public byte[] Compose(EpConnection connection)
|
||||||
{
|
{
|
||||||
var name = DC.ToBytes(Name);
|
var name = DC.ToBytes(Name);
|
||||||
|
|
||||||
@@ -75,7 +82,7 @@ public class ConstantDef : MemberDef
|
|||||||
.AddUInt8(hdr)
|
.AddUInt8(hdr)
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ValueType.Compose())
|
.AddUInt8Array(ValueType.Compose(connection))
|
||||||
.AddUInt8Array(Codec.Compose(Value, null, null))
|
.AddUInt8Array(Codec.Compose(Value, null, null))
|
||||||
.AddInt32(exp.Length)
|
.AddInt32(exp.Length)
|
||||||
.AddUInt8Array(exp)
|
.AddUInt8Array(exp)
|
||||||
@@ -89,18 +96,18 @@ public class ConstantDef : MemberDef
|
|||||||
.AddUInt8(hdr)
|
.AddUInt8(hdr)
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ValueType.Compose())
|
.AddUInt8Array(ValueType.Compose(connection))
|
||||||
.AddUInt8Array(Codec.Compose(Value, null, null))
|
.AddUInt8Array(Codec.Compose(Value, null, null))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static ConstantDef MakeConstantDef(Type type, FieldInfo ci, byte index = 0, string customName = null, TypeDef typeDef = null)
|
public static ConstantDef MakeConstantDef(Warehouse warehouse, Type type, FieldInfo ci, byte index = 0, string customName = null, TypeDef typeDef = null)
|
||||||
{
|
{
|
||||||
var annotationAttrs = ci.GetCustomAttributes<AnnotationAttribute>(true);
|
var annotationAttrs = ci.GetCustomAttributes<AnnotationAttribute>(true);
|
||||||
|
|
||||||
var valueType = Tru.FromType(ci.FieldType);
|
var valueType = Tru.FromType(ci.FieldType, warehouse);
|
||||||
|
|
||||||
if (valueType == null)
|
if (valueType == null)
|
||||||
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Esiur.Core;
|
using Esiur.Core;
|
||||||
using Esiur.Data;
|
using Esiur.Data;
|
||||||
|
using Esiur.Protocol;
|
||||||
using Esiur.Resource;
|
using Esiur.Resource;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -32,7 +33,7 @@ public class EventDef : MemberDef
|
|||||||
public Tru ArgumentType { get; set; }
|
public Tru ArgumentType { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public static (uint, EventDef) Parse(byte[] data, uint offset, byte index, bool inherited)
|
public static async AsyncReply<ParseResult<EventDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
|
||||||
{
|
{
|
||||||
var oOffset = offset;
|
var oOffset = offset;
|
||||||
|
|
||||||
@@ -42,9 +43,9 @@ public class EventDef : MemberDef
|
|||||||
var name = data.GetString(offset + 1, data[offset]);
|
var name = data.GetString(offset + 1, data[offset]);
|
||||||
offset += (uint)data[offset] + 1;
|
offset += (uint)data[offset] + 1;
|
||||||
|
|
||||||
var (dts, argType) = Tru.Parse(data, offset);
|
var argType = await Tru.ParseAsync(data, offset, connection, requestSequence);
|
||||||
|
|
||||||
offset += dts;
|
offset += argType.Size;
|
||||||
|
|
||||||
// Annotation ?
|
// Annotation ?
|
||||||
Map<string, string> annotations = null;
|
Map<string, string> annotations = null;
|
||||||
@@ -59,18 +60,18 @@ public class EventDef : MemberDef
|
|||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offset - oOffset, new EventDef()
|
return new ParseResult<EventDef>(new EventDef()
|
||||||
{
|
{
|
||||||
Index = index,
|
Index = index,
|
||||||
Name = name,
|
Name = name,
|
||||||
Inherited = inherited,
|
Inherited = inherited,
|
||||||
ArgumentType = argType,
|
ArgumentType = argType.Value,
|
||||||
Subscribable = subscribable,
|
Subscribable = subscribable,
|
||||||
Annotations = annotations
|
Annotations = annotations
|
||||||
});
|
}, offset - oOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Compose()
|
public byte[] Compose(EpConnection connection)
|
||||||
{
|
{
|
||||||
var name = Name.ToBytes();
|
var name = Name.ToBytes();
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ public class EventDef : MemberDef
|
|||||||
.AddUInt8(hdr)
|
.AddUInt8(hdr)
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ArgumentType.Compose())
|
.AddUInt8Array(ArgumentType.Compose(connection))
|
||||||
.AddInt32(exp.Length)
|
.AddInt32(exp.Length)
|
||||||
.AddUInt8Array(exp)
|
.AddUInt8Array(exp)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@@ -99,12 +100,12 @@ public class EventDef : MemberDef
|
|||||||
.AddUInt8(hdr)
|
.AddUInt8(hdr)
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ArgumentType.Compose())
|
.AddUInt8Array(ArgumentType.Compose(connection))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static EventDef MakeEventDef(Type type, EventInfo ei, byte index, string name, TypeDef schema)
|
public static EventDef MakeEventDef(Warehouse warehouse, Type type, EventInfo ei, byte index, string name, TypeDef schema)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!ei.EventHandlerType.IsGenericType)
|
if (!ei.EventHandlerType.IsGenericType)
|
||||||
@@ -116,7 +117,8 @@ public class EventDef : MemberDef
|
|||||||
|
|
||||||
|
|
||||||
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
||||||
var evtType = Tru.FromType(argType);
|
// @TODO: need to check if the type is remote
|
||||||
|
var evtType = Tru.FromType(argType, warehouse);
|
||||||
|
|
||||||
if (evtType == null)
|
if (evtType == null)
|
||||||
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
|
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class FunctionDef : MemberDef
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static (uint, FunctionDef) Parse(byte[] data, uint offset, byte index, bool inherited)
|
public static async AsyncReply<ParseResult<FunctionDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
|
||||||
{
|
{
|
||||||
|
|
||||||
var oOffset = offset;
|
var oOffset = offset;
|
||||||
@@ -51,9 +51,11 @@ public class FunctionDef : MemberDef
|
|||||||
var name = data.GetString(offset + 1, data[offset]);
|
var name = data.GetString(offset + 1, data[offset]);
|
||||||
offset += (uint)data[offset] + 1;
|
offset += (uint)data[offset] + 1;
|
||||||
|
|
||||||
|
//Console.WriteLine("Parsing functionDef " + name);
|
||||||
|
|
||||||
// return type
|
// return type
|
||||||
var (rts, returnType) = Tru.Parse(data, offset);
|
var returnType = await Tru.ParseAsync(data, offset, connection, requestSequence);
|
||||||
offset += rts;
|
offset += returnType.Size;
|
||||||
|
|
||||||
// arguments count
|
// arguments count
|
||||||
var argsCount = data[offset++];
|
var argsCount = data[offset++];
|
||||||
@@ -61,9 +63,9 @@ public class FunctionDef : MemberDef
|
|||||||
|
|
||||||
for (var a = 0; a < argsCount; a++)
|
for (var a = 0; a < argsCount; a++)
|
||||||
{
|
{
|
||||||
var (cs, argType) = ArgumentDef.Parse(data, offset, a);
|
var argType = await ArgumentDef.ParseAsync(data, offset, a, connection, requestSequence);
|
||||||
arguments.Add(argType);
|
arguments.Add(argType.Value);
|
||||||
offset += cs;
|
offset += argType.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<string, string> annotations = null;
|
Map<string, string> annotations = null;
|
||||||
@@ -79,7 +81,7 @@ public class FunctionDef : MemberDef
|
|||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offset - oOffset, new FunctionDef()
|
return new ParseResult<FunctionDef>( new FunctionDef()
|
||||||
{
|
{
|
||||||
Index = index,
|
Index = index,
|
||||||
Name = name,
|
Name = name,
|
||||||
@@ -87,11 +89,11 @@ public class FunctionDef : MemberDef
|
|||||||
IsStatic = isStatic,
|
IsStatic = isStatic,
|
||||||
Inherited = inherited,
|
Inherited = inherited,
|
||||||
Annotations = annotations,
|
Annotations = annotations,
|
||||||
ReturnType = returnType,
|
ReturnType = returnType.Value,
|
||||||
});
|
}, offset - oOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Compose()
|
public byte[] Compose(EpConnection connection)
|
||||||
{
|
{
|
||||||
|
|
||||||
var name = DC.ToBytes(Name);
|
var name = DC.ToBytes(Name);
|
||||||
@@ -99,11 +101,11 @@ public class FunctionDef : MemberDef
|
|||||||
var bl = new BinaryList()
|
var bl = new BinaryList()
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ReturnType.Compose())
|
.AddUInt8Array(ReturnType.Compose(connection))
|
||||||
.AddUInt8((byte)Arguments.Length);
|
.AddUInt8((byte)Arguments.Length);
|
||||||
|
|
||||||
for (var i = 0; i < Arguments.Length; i++)
|
for (var i = 0; i < Arguments.Length; i++)
|
||||||
bl.AddUInt8Array(Arguments[i].Compose());
|
bl.AddUInt8Array(Arguments[i].Compose(connection));
|
||||||
|
|
||||||
|
|
||||||
if (Annotations != null)
|
if (Annotations != null)
|
||||||
@@ -119,7 +121,7 @@ public class FunctionDef : MemberDef
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static FunctionDef MakeFunctionDef(Type type, MethodInfo mi, byte index, string name, TypeDef schema)
|
public static FunctionDef MakeFunctionDef(Warehouse warehouse, Type type, MethodInfo mi, byte index, string name, TypeDef schema)
|
||||||
{
|
{
|
||||||
|
|
||||||
var genericRtType = mi.ReturnType.IsGenericType ? mi.ReturnType.GetGenericTypeDefinition() : null;
|
var genericRtType = mi.ReturnType.IsGenericType ? mi.ReturnType.GetGenericTypeDefinition() : null;
|
||||||
@@ -128,23 +130,23 @@ public class FunctionDef : MemberDef
|
|||||||
|
|
||||||
if (genericRtType == typeof(AsyncReply<>))
|
if (genericRtType == typeof(AsyncReply<>))
|
||||||
{
|
{
|
||||||
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0], warehouse);
|
||||||
}
|
}
|
||||||
else if (genericRtType == typeof(Task<>))
|
else if (genericRtType == typeof(Task<>))
|
||||||
{
|
{
|
||||||
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0], warehouse);
|
||||||
}
|
}
|
||||||
else if (genericRtType == typeof(IEnumerable<>) || genericRtType == typeof(IAsyncEnumerable<>))
|
else if (genericRtType == typeof(IEnumerable<>) || genericRtType == typeof(IAsyncEnumerable<>))
|
||||||
{
|
{
|
||||||
// get export
|
// get export
|
||||||
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
rtType = Tru.FromType(mi.ReturnType.GetGenericArguments()[0], warehouse);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mi.ReturnType == typeof(Task))
|
if (mi.ReturnType == typeof(Task))
|
||||||
rtType = Tru.FromType(null);
|
rtType = Tru.FromType(null, warehouse);
|
||||||
else
|
else
|
||||||
rtType = Tru.FromType(mi.ReturnType);
|
rtType = Tru.FromType(mi.ReturnType, warehouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtType == null)
|
if (rtType == null)
|
||||||
@@ -214,7 +216,7 @@ public class FunctionDef : MemberDef
|
|||||||
|
|
||||||
var arguments = args.Select(x =>
|
var arguments = args.Select(x =>
|
||||||
{
|
{
|
||||||
var argType = Tru.FromType(x.ParameterType);
|
var argType = Tru.FromType(x.ParameterType, warehouse);
|
||||||
|
|
||||||
if (argType == null)
|
if (argType == null)
|
||||||
throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`");
|
throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`");
|
||||||
|
|||||||
@@ -0,0 +1,579 @@
|
|||||||
|
using Esiur.Core;
|
||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Misc;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using Esiur.Proxy;
|
||||||
|
using Esiur.Resource;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data.Types;
|
||||||
|
|
||||||
|
|
||||||
|
public class LocalTypeDef:TypeDef
|
||||||
|
{
|
||||||
|
Type _definedType { get; set; }
|
||||||
|
Type _parentDefinedType { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Type DefinedType => _definedType;
|
||||||
|
public Type ParentDefinedType => _parentDefinedType;
|
||||||
|
|
||||||
|
public TypeDef ParentTypeDef { get; private set; }
|
||||||
|
|
||||||
|
public static Uuid GetTypeUUID(Type type)
|
||||||
|
{
|
||||||
|
var attr = type.GetCustomAttribute<TypeIdAttribute>();
|
||||||
|
if (attr != null)
|
||||||
|
return attr.Id;
|
||||||
|
|
||||||
|
var tn = Encoding.UTF8.GetBytes(GetTypeName(type));
|
||||||
|
var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16);
|
||||||
|
hash[6] = (byte)((hash[6] & 0xF) | 0x80);
|
||||||
|
hash[8] = (byte)((hash[8] & 0xF) | 0x80);
|
||||||
|
|
||||||
|
var rt = new Uuid(hash);
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type[] GetDistributedTypes(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsArray)
|
||||||
|
return GetDistributedTypes(type.GetElementType());
|
||||||
|
else if (type.IsEnum)
|
||||||
|
return new Type[] { type };
|
||||||
|
else if (Codec.ImplementsInterface(type, typeof(IRecord))
|
||||||
|
|| Codec.ImplementsInterface(type, typeof(IResource)))
|
||||||
|
{
|
||||||
|
return new Type[] { type };
|
||||||
|
}
|
||||||
|
else if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var genericType = type.GetGenericTypeDefinition();
|
||||||
|
var genericTypeArgs = type.GetGenericArguments();
|
||||||
|
|
||||||
|
if (genericType == typeof(List<>)
|
||||||
|
|| genericType == typeof(PropertyContext<>)
|
||||||
|
|| genericType == typeof(AsyncReply<>)
|
||||||
|
|| genericType == typeof(ResourceLink<>))
|
||||||
|
{
|
||||||
|
return GetDistributedTypes(genericTypeArgs[0]);
|
||||||
|
}
|
||||||
|
else if (genericType == typeof(Tuple<>)
|
||||||
|
|| genericType == typeof(Map<,>))
|
||||||
|
{
|
||||||
|
var rt = new List<Type>();
|
||||||
|
for (var i = 0; i < genericTypeArgs.Length; i++)
|
||||||
|
{
|
||||||
|
var depTypes = GetDistributedTypes(genericTypeArgs[i]);
|
||||||
|
foreach (var depType in depTypes)
|
||||||
|
if (!rt.Contains(depType))
|
||||||
|
rt.Add(depType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rt.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new Type[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static TypeDef[] GetDependencies(LocalTypeDef typeDef, Warehouse warehouse)
|
||||||
|
{
|
||||||
|
|
||||||
|
var list = new List<TypeDef>();
|
||||||
|
|
||||||
|
// Add self
|
||||||
|
list.Add(typeDef);
|
||||||
|
|
||||||
|
|
||||||
|
Action<LocalTypeDef> getDependenciesFunc = null;
|
||||||
|
|
||||||
|
getDependenciesFunc = (LocalTypeDef td) =>
|
||||||
|
{
|
||||||
|
if (td.DefinedType == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add parents
|
||||||
|
var parentType = td.ParentDefinedType;
|
||||||
|
|
||||||
|
// Get parents
|
||||||
|
while (parentType != null)
|
||||||
|
{
|
||||||
|
var parentTypeDef = warehouse.GetLocalTypeDefByType(parentType);
|
||||||
|
if (parentTypeDef != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(parentTypeDef))
|
||||||
|
{
|
||||||
|
list.Add(parentTypeDef);
|
||||||
|
|
||||||
|
if (parentTypeDef is LocalTypeDef pltd)
|
||||||
|
{
|
||||||
|
parentType = pltd.DefinedType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// functions
|
||||||
|
foreach (var f in td._functions)
|
||||||
|
{
|
||||||
|
var functionReturnTypes = GetDistributedTypes(f.MethodInfo.ReturnType);
|
||||||
|
|
||||||
|
foreach (var functionReturnType in functionReturnTypes)
|
||||||
|
{
|
||||||
|
var functionReturnTypeDef = warehouse.GetLocalTypeDefByType(functionReturnType);
|
||||||
|
if (functionReturnTypeDef != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(functionReturnTypeDef))
|
||||||
|
{
|
||||||
|
list.Add(functionReturnTypeDef);
|
||||||
|
if (functionReturnTypeDef is LocalTypeDef frtd)
|
||||||
|
getDependenciesFunc(frtd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = f.MethodInfo.GetParameters();
|
||||||
|
|
||||||
|
for (var i = 0; i < args.Length - 1; i++)
|
||||||
|
{
|
||||||
|
var fpTypes = GetDistributedTypes(args[i].ParameterType);
|
||||||
|
|
||||||
|
foreach (var fpType in fpTypes)
|
||||||
|
{
|
||||||
|
var fpt = warehouse.GetLocalTypeDefByType(fpType);
|
||||||
|
if (fpt != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(fpt))
|
||||||
|
{
|
||||||
|
list.Add(fpt);
|
||||||
|
if (fpt is LocalTypeDef ltd)
|
||||||
|
getDependenciesFunc(ltd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip EpConnection argument
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
var last = args.Last();
|
||||||
|
if (last.ParameterType != typeof(EpConnection))
|
||||||
|
{
|
||||||
|
|
||||||
|
var fpTypes = GetDistributedTypes(last.ParameterType);
|
||||||
|
|
||||||
|
foreach (var fpType in fpTypes)
|
||||||
|
{
|
||||||
|
var fpt = warehouse.GetLocalTypeDefByType(fpType);
|
||||||
|
if (fpt != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(fpt))
|
||||||
|
{
|
||||||
|
list.Add(fpt);
|
||||||
|
if (fpt is LocalTypeDef ltd)
|
||||||
|
getDependenciesFunc(ltd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// properties
|
||||||
|
foreach (var p in td._properties)
|
||||||
|
{
|
||||||
|
var propertyTypes = GetDistributedTypes(p.PropertyInfo.PropertyType);
|
||||||
|
|
||||||
|
foreach (var propertyType in propertyTypes)
|
||||||
|
{
|
||||||
|
var propertyTypeDef = warehouse.GetLocalTypeDefByType(propertyType);
|
||||||
|
if (propertyTypeDef != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(propertyTypeDef))
|
||||||
|
{
|
||||||
|
list.Add(propertyTypeDef);
|
||||||
|
if (propertyTypeDef is LocalTypeDef ltd)
|
||||||
|
getDependenciesFunc(ltd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// events
|
||||||
|
foreach (var e in td._events)
|
||||||
|
{
|
||||||
|
var eventTypes = GetDistributedTypes(e.EventInfo.EventHandlerType.GenericTypeArguments[0]);
|
||||||
|
|
||||||
|
foreach (var eventType in eventTypes)
|
||||||
|
{
|
||||||
|
var eventTypeDef = warehouse.GetLocalTypeDefByType(eventType);
|
||||||
|
|
||||||
|
if (eventTypeDef != null)
|
||||||
|
{
|
||||||
|
if (!list.Contains(eventTypeDef))
|
||||||
|
{
|
||||||
|
list.Add(eventTypeDef);
|
||||||
|
if (eventTypeDef is LocalTypeDef ltd)
|
||||||
|
getDependenciesFunc(ltd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getDependenciesFunc(typeDef);
|
||||||
|
return list.Distinct().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static string GetTypeName(Type type, char separator = '.')
|
||||||
|
{
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var index = type.Name.IndexOf("`");
|
||||||
|
var name = $"{type.Namespace}{separator}{((index > -1) ? type.Name.Substring(0, index) : type.Name)}Of";
|
||||||
|
foreach (var t in type.GenericTypeArguments)
|
||||||
|
name += GetTypeName(t, '_');
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return $"{type.Namespace?.Replace('.', separator) ?? "Global"}{separator}{type.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalTypeDef(Type type, Warehouse warehouse)
|
||||||
|
{
|
||||||
|
if (Codec.ImplementsInterface(type, typeof(IResource)))
|
||||||
|
_typeDefKind = TypeDefKind.Resource;
|
||||||
|
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
||||||
|
_typeDefKind = TypeDefKind.Record;
|
||||||
|
else if (type.IsEnum)
|
||||||
|
_typeDefKind = TypeDefKind.Enum;
|
||||||
|
else
|
||||||
|
throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource.");
|
||||||
|
|
||||||
|
//IsWrapper = Codec.InheritsClass(type, typeof(EpResource));
|
||||||
|
|
||||||
|
type = ResourceProxy.GetBaseType(type);
|
||||||
|
|
||||||
|
_definedType = type;
|
||||||
|
|
||||||
|
_typeName = GetTypeName(type);
|
||||||
|
|
||||||
|
|
||||||
|
warehouse.TryRegisterLocalTypeDef(this);
|
||||||
|
|
||||||
|
var hierarchy = GetHierarchy(type);
|
||||||
|
|
||||||
|
if (hierarchy.ContainsKey(MemberTypes.Field))
|
||||||
|
{
|
||||||
|
foreach (var cd in hierarchy[MemberTypes.Field])
|
||||||
|
{
|
||||||
|
_constants.Add(ConstantDef.MakeConstantDef
|
||||||
|
(warehouse, type, (FieldInfo)cd.GetMemberInfo(), cd.Index, cd.Name, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hierarchy.ContainsKey(MemberTypes.Property))
|
||||||
|
{
|
||||||
|
foreach (var pd in hierarchy[MemberTypes.Property])
|
||||||
|
{
|
||||||
|
_properties.Add(PropertyDef.MakePropertyDef
|
||||||
|
( warehouse, type, (PropertyInfo)pd.GetMemberInfo(), pd.Name, pd.Index, pd.PropertyPermission, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_typeDefKind == TypeDefKind.Resource)
|
||||||
|
{
|
||||||
|
if (hierarchy.ContainsKey(MemberTypes.Method))
|
||||||
|
{
|
||||||
|
foreach (var fd in hierarchy[MemberTypes.Method])
|
||||||
|
{
|
||||||
|
_functions.Add(FunctionDef.MakeFunctionDef
|
||||||
|
(warehouse, type, (MethodInfo)fd.GetMemberInfo(), fd.Index, fd.Name, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hierarchy.ContainsKey(MemberTypes.Event))
|
||||||
|
{
|
||||||
|
foreach (var ed in hierarchy[MemberTypes.Event])
|
||||||
|
{
|
||||||
|
_events.Add(EventDef.MakeEventDef
|
||||||
|
( warehouse, type, (EventInfo)ed.GetMemberInfo(), ed.Index, ed.Name, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// add attributes
|
||||||
|
var attrs = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.Where(x => x.GetCustomAttribute<AttributeAttribute>() != null);
|
||||||
|
|
||||||
|
foreach (var attr in attrs)
|
||||||
|
{
|
||||||
|
var attrAttr = attr.GetCustomAttribute<AttributeAttribute>();
|
||||||
|
|
||||||
|
_attributes.Add(AttributeDef
|
||||||
|
.MakeAttributeDef(type, attr, 0, attrAttr?.Name ?? attr.Name, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// find the first parent type that implements IResource
|
||||||
|
var hasParent = HasParent(type);
|
||||||
|
var classAnnotations = type.GetCustomAttributes<AnnotationAttribute>(false);
|
||||||
|
var hasClassAnnotation = (classAnnotations != null) && (classAnnotations.Count() > 0);
|
||||||
|
|
||||||
|
|
||||||
|
if (hasParent)
|
||||||
|
{
|
||||||
|
// find the first parent type that implements IResource
|
||||||
|
_parentDefinedType = ResourceProxy.GetBaseType(type.BaseType);
|
||||||
|
|
||||||
|
var parentTypeDef = warehouse.GetLocalTypeDefByType(_parentDefinedType);
|
||||||
|
|
||||||
|
if (parentTypeDef == null)
|
||||||
|
throw new Exception("Can't find parent TypeDef.");
|
||||||
|
|
||||||
|
ParentTypeDef = parentTypeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasClassAnnotation)
|
||||||
|
{
|
||||||
|
Annotations = new Map<string, string>();
|
||||||
|
|
||||||
|
foreach (var ann in classAnnotations)
|
||||||
|
Annotations.Add(ann.Key, ann.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] Compose(EpConnection connection)
|
||||||
|
{
|
||||||
|
// bake it binarily
|
||||||
|
var b = new BinaryList();
|
||||||
|
|
||||||
|
// find the first parent type that implements IResource
|
||||||
|
|
||||||
|
|
||||||
|
var hasParent = ParentTypeDef != null;
|
||||||
|
var hasClassAnnotation = Annotations != null && Annotations.Count() > 0;
|
||||||
|
|
||||||
|
var typeNameBytes = DC.ToBytes(_typeName);
|
||||||
|
|
||||||
|
b.AddUInt8((byte)((hasParent ? 0x80 : 0) | (hasClassAnnotation ? 0x40 : 0x0) | (byte)_typeDefKind))
|
||||||
|
.AddUInt64(_typeId)
|
||||||
|
.AddUInt8((byte)typeNameBytes.Length)
|
||||||
|
.AddUInt8Array(typeNameBytes);
|
||||||
|
|
||||||
|
if (hasParent)
|
||||||
|
{
|
||||||
|
b.AddUInt64(ParentTypeDef.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasClassAnnotation)
|
||||||
|
{
|
||||||
|
|
||||||
|
//foreach (var ann in Annotations)
|
||||||
|
// Annotations.Add(ann.Key, ann.Value);
|
||||||
|
|
||||||
|
var classAnnotationBytes = Codec.Compose(Annotations, null, null);
|
||||||
|
|
||||||
|
b.AddUInt8Array(classAnnotationBytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
b.AddInt32(_version)
|
||||||
|
.AddUInt16((ushort)(_functions.Count + _properties.Count + _events.Count + _constants.Count));
|
||||||
|
|
||||||
|
foreach (var ft in _functions)
|
||||||
|
b.AddUInt8Array(ft.Compose(connection ));
|
||||||
|
foreach (var pt in _properties)
|
||||||
|
b.AddUInt8Array(pt.Compose(connection));
|
||||||
|
foreach (var et in _events)
|
||||||
|
b.AddUInt8Array(et.Compose(connection));
|
||||||
|
foreach (var ct in _constants)
|
||||||
|
b.AddUInt8Array(ct.Compose(connection));
|
||||||
|
|
||||||
|
return b.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasParent(Type type)
|
||||||
|
{
|
||||||
|
var parent = type.BaseType;
|
||||||
|
|
||||||
|
|
||||||
|
while (parent != null)
|
||||||
|
{
|
||||||
|
if (parent == typeof(Esiur.Resource.Resource)
|
||||||
|
|| parent == typeof(Record)
|
||||||
|
|| parent == typeof(EntryPoint))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (parent.GetInterfaces().Contains(typeof(IResource))
|
||||||
|
|| parent.GetInterfaces().Contains(typeof(IRecord)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
parent = parent.BaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Dictionary<MemberTypes, List<MemberData>> GetHierarchy(Type type)
|
||||||
|
{
|
||||||
|
var members = new List<MemberData>();
|
||||||
|
|
||||||
|
var order = 0;
|
||||||
|
|
||||||
|
while (type != null)
|
||||||
|
{
|
||||||
|
var classIsPublic = type.IsEnum || (type.GetCustomAttribute<ExportAttribute>() != null);
|
||||||
|
|
||||||
|
if (classIsPublic)
|
||||||
|
{
|
||||||
|
// get public instance members only.
|
||||||
|
var mis = type.GetMembers(BindingFlags.Public | BindingFlags.Instance
|
||||||
|
| BindingFlags.DeclaredOnly | BindingFlags.Static)
|
||||||
|
.Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
|
||||||
|
|| x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
|
||||||
|
.Where(x => !(x is FieldInfo c && !c.IsStatic))
|
||||||
|
.Where(x => x.GetCustomAttribute<IgnoreAttribute>() == null)
|
||||||
|
.Where(x => x.Name != "Instance")
|
||||||
|
.Where(x => x.Name != "Trigger")
|
||||||
|
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
|
||||||
|
.Where(x => !(x is EventInfo e &&
|
||||||
|
!(e.EventHandlerType.IsGenericType &&
|
||||||
|
(e.EventHandlerType.GetGenericTypeDefinition() == typeof(ResourceEventHandler<>)
|
||||||
|
|| e.EventHandlerType.GetGenericTypeDefinition() == typeof(CustomResourceEventHandler<>))
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.Select(x => new MemberData(
|
||||||
|
info: x,
|
||||||
|
order: order
|
||||||
|
))
|
||||||
|
.OrderBy(x => x.Name);
|
||||||
|
|
||||||
|
members.AddRange(mis.ToArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// allow private and public members that are marked with [Export] attribute.
|
||||||
|
var mis = type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
|
| BindingFlags.DeclaredOnly | BindingFlags.Static)
|
||||||
|
.Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
|
||||||
|
|| x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
|
||||||
|
.Where(x => !(x is FieldInfo c && !c.IsStatic))
|
||||||
|
.Where(x => x.GetCustomAttribute<ExportAttribute>() != null)
|
||||||
|
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
|
||||||
|
.Select(x => new MemberData(
|
||||||
|
info: x,
|
||||||
|
order: order
|
||||||
|
))
|
||||||
|
.OrderBy(x => x.Name);
|
||||||
|
|
||||||
|
members.AddRange(mis.ToArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type = type.BaseType;
|
||||||
|
|
||||||
|
if (type == null
|
||||||
|
|| type == typeof(Esiur.Resource.Resource)
|
||||||
|
|| type == typeof(Record)
|
||||||
|
|| type == typeof(EntryPoint))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (type.GetInterfaces().Contains(typeof(IResource))
|
||||||
|
|| type.GetInterfaces().Contains(typeof(IRecord)))
|
||||||
|
{
|
||||||
|
order++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// round 2: check for duplicates
|
||||||
|
for (var i = 0; i < members.Count; i++)
|
||||||
|
{
|
||||||
|
var mi = members[i];
|
||||||
|
for (var j = i + 1; j < members.Count; j++)
|
||||||
|
{
|
||||||
|
var pi = members[j];
|
||||||
|
if (pi.Info.MemberType != mi.Info.MemberType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//if (ci.Info.Name == mi.Info.Name && ci.Order == mi.Order)
|
||||||
|
// throw new Exception($"Method overload is not supported. Method '{ci.Info.Name}'.");
|
||||||
|
|
||||||
|
if (pi.Name == mi.Name)
|
||||||
|
{
|
||||||
|
if (pi.Order == mi.Order)
|
||||||
|
throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// @TODO: check for return type and parameters they must match
|
||||||
|
if (pi.Info.Name != mi.Info.Name)
|
||||||
|
throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mi.Parent = pi;
|
||||||
|
pi.Child = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// assign indexes
|
||||||
|
var groups = members.Where(x => x.Parent == null)
|
||||||
|
.OrderBy(x => x.Name).OrderByDescending(x => x.Order)
|
||||||
|
.GroupBy(x => x.Info.MemberType);
|
||||||
|
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
byte index = 0;
|
||||||
|
foreach (var mi in group)
|
||||||
|
{
|
||||||
|
//if (mi.Parent == null)
|
||||||
|
mi.Index = index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rt = groups.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//public Map<byte, object> CastProperties(Map<string, object> properties)
|
||||||
|
//{
|
||||||
|
// var rt = new Map<byte, object>();
|
||||||
|
// foreach (var kv in properties)
|
||||||
|
// {
|
||||||
|
// var pt = GetPropertyDefByName(kv.Key);
|
||||||
|
// if (pt == null) continue;
|
||||||
|
// rt.Add(pt.Index, kv.Value);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return rt;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Esiur.Data;
|
using Esiur.Core;
|
||||||
|
using Esiur.Data;
|
||||||
using Esiur.Protocol;
|
using Esiur.Protocol;
|
||||||
using Esiur.Resource;
|
using Esiur.Resource;
|
||||||
using System;
|
using System;
|
||||||
@@ -80,7 +81,7 @@ public class PropertyDef : MemberDef
|
|||||||
return $"{Name}: {ValueType}";
|
return $"{Name}: {ValueType}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (uint, PropertyDef) Parse(byte[] data, uint offset, byte index, bool inherited)
|
public static async AsyncReply<ParseResult<PropertyDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
|
||||||
{
|
{
|
||||||
var oOffset = offset;
|
var oOffset = offset;
|
||||||
|
|
||||||
@@ -91,11 +92,13 @@ public class PropertyDef : MemberDef
|
|||||||
var permission = (PropertyPermission)((data[offset++] >> 1) & 0x3);
|
var permission = (PropertyPermission)((data[offset++] >> 1) & 0x3);
|
||||||
var name = data.GetString(offset + 1, data[offset]);
|
var name = data.GetString(offset + 1, data[offset]);
|
||||||
|
|
||||||
|
//Console.WriteLine("Parsing propdef " + name);
|
||||||
|
|
||||||
offset += (uint)data[offset] + 1;
|
offset += (uint)data[offset] + 1;
|
||||||
|
|
||||||
var (dts, valueType) = Tru.Parse(data, offset);
|
var valueType = await Tru.ParseAsync(data, offset, connection, requestSequence);
|
||||||
|
|
||||||
offset += dts;
|
offset += valueType.Size;
|
||||||
|
|
||||||
Map<string, string> annotations = null;
|
Map<string, string> annotations = null;
|
||||||
|
|
||||||
@@ -110,20 +113,20 @@ public class PropertyDef : MemberDef
|
|||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offset - oOffset, new PropertyDef()
|
return new ParseResult<PropertyDef>(new PropertyDef()
|
||||||
{
|
{
|
||||||
Index = index,
|
Index = index,
|
||||||
Name = name,
|
Name = name,
|
||||||
Inherited = inherited,
|
Inherited = inherited,
|
||||||
Permission = permission,
|
Permission = permission,
|
||||||
HasHistory = hasHistory,
|
HasHistory = hasHistory,
|
||||||
ValueType = valueType,
|
ValueType = valueType.Value,
|
||||||
Annotations = annotations
|
Annotations = annotations
|
||||||
});
|
}, offset - oOffset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Compose()
|
public byte[] Compose(EpConnection connection)
|
||||||
{
|
{
|
||||||
var name = DC.ToBytes(Name);
|
var name = DC.ToBytes(Name);
|
||||||
|
|
||||||
@@ -178,7 +181,7 @@ public class PropertyDef : MemberDef
|
|||||||
.AddUInt8((byte)(0x28 | pv))
|
.AddUInt8((byte)(0x28 | pv))
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ValueType.Compose())
|
.AddUInt8Array(ValueType.Compose(connection))
|
||||||
.AddUInt8Array(rexp)
|
.AddUInt8Array(rexp)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
@@ -188,20 +191,21 @@ public class PropertyDef : MemberDef
|
|||||||
.AddUInt8((byte)(0x20 | pv))
|
.AddUInt8((byte)(0x20 | pv))
|
||||||
.AddUInt8((byte)name.Length)
|
.AddUInt8((byte)name.Length)
|
||||||
.AddUInt8Array(name)
|
.AddUInt8Array(name)
|
||||||
.AddUInt8Array(ValueType.Compose())
|
.AddUInt8Array(ValueType.Compose(connection))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static PropertyDef MakePropertyDef(Type type, PropertyInfo pi, string name, byte index, PropertyPermission permission, TypeDef schema)
|
public static PropertyDef MakePropertyDef(Warehouse warehouse, Type type, PropertyInfo pi, string name, byte index, PropertyPermission permission, TypeDef schema)
|
||||||
{
|
{
|
||||||
var genericPropType = pi.PropertyType.IsGenericType ? pi.PropertyType.GetGenericTypeDefinition() : null;
|
var genericPropType = pi.PropertyType.IsGenericType ? pi.PropertyType.GetGenericTypeDefinition() : null;
|
||||||
|
// @TODO: need to check if the type is remote
|
||||||
|
|
||||||
var propType = genericPropType == typeof(PropertyContext<>) ?
|
var propType = genericPropType == typeof(PropertyContext<>) ?
|
||||||
Tru.FromType(pi.PropertyType.GetGenericArguments()[0]) :
|
Tru.FromType(pi.PropertyType.GetGenericArguments()[0], warehouse) :
|
||||||
Tru.FromType(pi.PropertyType);
|
Tru.FromType(pi.PropertyType, warehouse);
|
||||||
|
|
||||||
if (propType == null)
|
if (propType == null)
|
||||||
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
|
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
using Esiur.Core;
|
||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Misc;
|
||||||
|
using Esiur.Protocol;
|
||||||
|
using Esiur.Proxy;
|
||||||
|
using Esiur.Resource;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Data.Types;
|
||||||
|
|
||||||
|
|
||||||
|
public class RemoteTypeDef:TypeDef
|
||||||
|
{
|
||||||
|
Type _proxyType { get; set; }
|
||||||
|
|
||||||
|
public Type ProxyType => _proxyType;
|
||||||
|
|
||||||
|
string _domain;
|
||||||
|
|
||||||
|
public string Domain => _domain;
|
||||||
|
|
||||||
|
|
||||||
|
public uint _localTypeDefId;
|
||||||
|
|
||||||
|
public uint LocalTypeDefId
|
||||||
|
{
|
||||||
|
get => _localTypeDefId;
|
||||||
|
internal set => _localTypeDefId = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncReply<RemoteTypeDef> Parse(RemoteTypeDef od, string domain, byte[] data, EpConnection connection, ulong[] requestSequence)
|
||||||
|
{
|
||||||
|
return Parse(od, domain, data, 0, (uint)data.Length, connection, requestSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async AsyncReply<RemoteTypeDef> Parse(RemoteTypeDef od, string domain, byte[] data, uint offset, uint contentLength, EpConnection connection, ulong[] requestSequence)
|
||||||
|
{
|
||||||
|
uint ends = offset + contentLength;
|
||||||
|
|
||||||
|
uint oOffset = offset;
|
||||||
|
|
||||||
|
// start parsing...
|
||||||
|
|
||||||
|
|
||||||
|
od._domain = domain;
|
||||||
|
|
||||||
|
od._content = data.Clip(offset, contentLength);
|
||||||
|
|
||||||
|
var hasParent = (data[offset] & 0x80) > 0;
|
||||||
|
var hasClassAnnotation = (data[offset] & 0x40) > 0;
|
||||||
|
|
||||||
|
od._typeDefKind = (TypeDefKind)(data[offset++] & 0xF);
|
||||||
|
|
||||||
|
od._typeId = data.GetUInt64(offset, Endian.Little);
|
||||||
|
offset += 8;
|
||||||
|
od._typeName = data.GetString(offset + 1, data[offset]);
|
||||||
|
offset += (uint)data[offset] + 1;
|
||||||
|
|
||||||
|
|
||||||
|
if (hasParent)
|
||||||
|
{
|
||||||
|
od._parentTypeId = data.GetUInt64(offset, Endian.Little);
|
||||||
|
offset += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasClassAnnotation)
|
||||||
|
{
|
||||||
|
var (len, anns) = Codec.ParseSync(data, offset, null);
|
||||||
|
|
||||||
|
if (anns is Map<string, string> annotations)
|
||||||
|
od.Annotations = annotations;
|
||||||
|
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
od._version = data.GetInt32(offset, Endian.Little);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
ushort methodsCount = data.GetUInt16(offset, Endian.Little);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
byte functionIndex = 0;
|
||||||
|
byte propertyIndex = 0;
|
||||||
|
byte eventIndex = 0;
|
||||||
|
byte constantIndex = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < methodsCount; i++)
|
||||||
|
{
|
||||||
|
var inherited = (data[offset] & 0x80) > 0;
|
||||||
|
var type = (data[offset] >> 5) & 0x3;
|
||||||
|
|
||||||
|
if (type == 0) // function
|
||||||
|
{
|
||||||
|
var ft = await FunctionDef.ParseAsync(data, offset, functionIndex++, inherited, connection, requestSequence);
|
||||||
|
offset += ft.Size;
|
||||||
|
od._functions.Add(ft.Value);
|
||||||
|
}
|
||||||
|
else if (type == 1) // property
|
||||||
|
{
|
||||||
|
var pt = await PropertyDef.ParseAsync(data, offset, propertyIndex++, inherited, connection, requestSequence);
|
||||||
|
offset += pt.Size;
|
||||||
|
od._properties.Add(pt.Value);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (type == 2) // Event
|
||||||
|
{
|
||||||
|
var et = await EventDef.ParseAsync(data, offset, eventIndex++, inherited, connection, requestSequence);
|
||||||
|
offset += et.Size;
|
||||||
|
od._events.Add(et.Value);
|
||||||
|
}
|
||||||
|
// constant
|
||||||
|
else if (type == 3)
|
||||||
|
{
|
||||||
|
var ct = await ConstantDef.ParseAsync(data, offset, constantIndex++, inherited, connection, requestSequence);
|
||||||
|
offset += ct.Size;
|
||||||
|
od._constants.Add(ct.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return od;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -18,46 +18,51 @@ namespace Esiur.Data.Types;
|
|||||||
public class TypeDef
|
public class TypeDef
|
||||||
{
|
{
|
||||||
|
|
||||||
protected Uuid typeId;
|
protected ulong _typeId;
|
||||||
protected Uuid? parentId;
|
protected ulong? _parentTypeId;
|
||||||
|
|
||||||
public Map<string, string> Annotations { get; set; }
|
public Map<string, string> Annotations { get; set; }
|
||||||
|
|
||||||
string typeName;
|
protected string _typeName;
|
||||||
List<FunctionDef> functions = new List<FunctionDef>();
|
protected List<FunctionDef> _functions = new List<FunctionDef>();
|
||||||
List<EventDef> events = new List<EventDef>();
|
protected List<EventDef> _events = new List<EventDef>();
|
||||||
List<PropertyDef> properties = new List<PropertyDef>();
|
protected List<PropertyDef> _properties = new List<PropertyDef>();
|
||||||
List<AttributeDef> attributes = new List<AttributeDef>();
|
protected List<AttributeDef> _attributes = new List<AttributeDef>();
|
||||||
List<ConstantDef> constants = new();
|
protected List<ConstantDef> _constants = new();
|
||||||
int version;
|
protected int _version;
|
||||||
TypeDefKind typeDefKind;
|
protected TypeDefKind _typeDefKind;
|
||||||
|
|
||||||
|
//Type _definedType { get; set; }
|
||||||
|
//Type _proxyType { get; set; }
|
||||||
|
//Type _parentDefinedType { get; set; }
|
||||||
|
|
||||||
|
//bool _isLocal;
|
||||||
|
|
||||||
|
//public Type DefinedType => _definedType;
|
||||||
|
//public Type ParentDefinedType => _parentDefinedType;
|
||||||
|
|
||||||
|
//public Type ProxyType => _proxyType;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return typeName;
|
return _typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected byte[] content;
|
protected byte[] _content;
|
||||||
|
|
||||||
public Uuid? ParentId => parentId;
|
public ulong? ParentTypeId => _parentTypeId;
|
||||||
|
|
||||||
public byte[] Content
|
//public byte[] Content => _content;
|
||||||
{
|
|
||||||
get { return content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeDefKind Kind => typeDefKind;
|
public TypeDefKind Kind => _typeDefKind;
|
||||||
|
|
||||||
|
|
||||||
public Type DefinedType { get; set; }
|
|
||||||
public Type ParentDefinedType { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public EventDef GetEventDefByName(string eventName)
|
public EventDef GetEventDefByName(string eventName)
|
||||||
{
|
{
|
||||||
foreach (var i in events)
|
foreach (var i in _events)
|
||||||
if (i.Name == eventName)
|
if (i.Name == eventName)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
@@ -65,7 +70,7 @@ public class TypeDef
|
|||||||
|
|
||||||
public EventDef GetEventDefByIndex(byte index)
|
public EventDef GetEventDefByIndex(byte index)
|
||||||
{
|
{
|
||||||
foreach (var i in events)
|
foreach (var i in _events)
|
||||||
if (i.Index == index)
|
if (i.Index == index)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
@@ -73,14 +78,14 @@ public class TypeDef
|
|||||||
|
|
||||||
public FunctionDef GetFunctionDefByName(string functionName)
|
public FunctionDef GetFunctionDefByName(string functionName)
|
||||||
{
|
{
|
||||||
foreach (var i in functions)
|
foreach (var i in _functions)
|
||||||
if (i.Name == functionName)
|
if (i.Name == functionName)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public FunctionDef GetFunctionDefByIndex(byte index)
|
public FunctionDef GetFunctionDefByIndex(byte index)
|
||||||
{
|
{
|
||||||
foreach (var i in functions)
|
foreach (var i in _functions)
|
||||||
if (i.Index == index)
|
if (i.Index == index)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
@@ -88,7 +93,7 @@ public class TypeDef
|
|||||||
|
|
||||||
public PropertyDef GetPropertyDefByIndex(byte index)
|
public PropertyDef GetPropertyDefByIndex(byte index)
|
||||||
{
|
{
|
||||||
foreach (var i in properties)
|
foreach (var i in _properties)
|
||||||
if (i.Index == index)
|
if (i.Index == index)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
@@ -96,7 +101,7 @@ public class TypeDef
|
|||||||
|
|
||||||
public PropertyDef GetPropertyDefByName(string propertyName)
|
public PropertyDef GetPropertyDefByName(string propertyName)
|
||||||
{
|
{
|
||||||
foreach (var i in properties)
|
foreach (var i in _properties)
|
||||||
if (i.Name == propertyName)
|
if (i.Name == propertyName)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
@@ -104,645 +109,47 @@ public class TypeDef
|
|||||||
|
|
||||||
public AttributeDef GetAttributeDef(string attributeName)
|
public AttributeDef GetAttributeDef(string attributeName)
|
||||||
{
|
{
|
||||||
foreach (var i in attributes)
|
foreach (var i in _attributes)
|
||||||
if (i.Name == attributeName)
|
if (i.Name == attributeName)
|
||||||
return i;
|
return i;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uuid Id
|
public ulong Id
|
||||||
{
|
{
|
||||||
get { return typeId; }
|
get { return _typeId; }
|
||||||
|
internal set { _typeId = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return typeName; }
|
get { return _typeName; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public FunctionDef[] Functions
|
public FunctionDef[] Functions
|
||||||
{
|
{
|
||||||
get { return functions.ToArray(); }
|
get { return _functions.ToArray(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventDef[] Events
|
public EventDef[] Events
|
||||||
{
|
{
|
||||||
get { return events.ToArray(); }
|
get { return _events.ToArray(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyDef[] Properties
|
public PropertyDef[] Properties
|
||||||
{
|
{
|
||||||
get { return properties.ToArray(); }
|
get { return _properties.ToArray(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstantDef[] Constants => constants.ToArray();
|
public ConstantDef[] Constants => _constants.ToArray();
|
||||||
|
|
||||||
public TypeDef()
|
public TypeDef()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uuid GetTypeUUID(Type type)
|
|
||||||
{
|
|
||||||
var attr = type.GetCustomAttribute<TypeIdAttribute>();
|
|
||||||
if (attr != null)
|
|
||||||
return attr.Id;
|
|
||||||
|
|
||||||
var tn = Encoding.UTF8.GetBytes(GetTypeName(type));
|
|
||||||
var hash = SHA256.Create().ComputeHash(tn).Clip(0, 16);
|
|
||||||
hash[6] = (byte)((hash[6] & 0xF) | 0x80);
|
|
||||||
hash[8] = (byte)((hash[8] & 0xF) | 0x80);
|
|
||||||
|
|
||||||
var rt = new Uuid(hash);
|
|
||||||
return rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Type[] GetDistributedTypes(Type type)
|
|
||||||
{
|
|
||||||
if (type.IsArray)
|
|
||||||
return GetDistributedTypes(type.GetElementType());
|
|
||||||
else if (type.IsEnum)
|
|
||||||
return new Type[] { type };
|
|
||||||
else if (Codec.ImplementsInterface(type, typeof(IRecord))
|
|
||||||
|| Codec.ImplementsInterface(type, typeof(IResource)))
|
|
||||||
{
|
|
||||||
return new Type[] { type };
|
|
||||||
}
|
|
||||||
else if (type.IsGenericType)
|
|
||||||
{
|
|
||||||
var genericType = type.GetGenericTypeDefinition();
|
|
||||||
var genericTypeArgs = type.GetGenericArguments();
|
|
||||||
|
|
||||||
if (genericType == typeof(List<>)
|
|
||||||
|| genericType == typeof(PropertyContext<>)
|
|
||||||
|| genericType == typeof(AsyncReply<>)
|
|
||||||
|| genericType == typeof(ResourceLink<>))
|
|
||||||
{
|
|
||||||
return GetDistributedTypes(genericTypeArgs[0]);
|
|
||||||
}
|
|
||||||
else if (genericType == typeof(Tuple<>)
|
|
||||||
|| genericType == typeof(Map<,>))
|
|
||||||
{
|
|
||||||
var rt = new List<Type>();
|
|
||||||
for (var i = 0; i < genericTypeArgs.Length; i++)
|
|
||||||
{
|
|
||||||
var depTypes = GetDistributedTypes(genericTypeArgs[i]);
|
|
||||||
foreach (var depType in depTypes)
|
|
||||||
if (!rt.Contains(depType))
|
|
||||||
rt.Add(depType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rt.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return new Type[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static TypeDef[] GetDependencies(TypeDef schema, Warehouse warehouse)
|
|
||||||
{
|
|
||||||
|
|
||||||
var list = new List<TypeDef>();
|
|
||||||
|
|
||||||
// Add self
|
|
||||||
list.Add(schema);
|
|
||||||
|
|
||||||
|
|
||||||
Action<TypeDef, List<TypeDef>> getDependenciesFunc = null;
|
|
||||||
|
|
||||||
getDependenciesFunc = (TypeDef sch, List<TypeDef> bag) =>
|
|
||||||
{
|
|
||||||
if (schema.DefinedType == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Add parents
|
|
||||||
var parentType = sch.ParentDefinedType;
|
|
||||||
|
|
||||||
// Get parents
|
|
||||||
while (parentType != null)
|
|
||||||
{
|
|
||||||
var parentTypeDef = warehouse.GetTypeDefByType(parentType);
|
|
||||||
if (parentTypeDef != null)
|
|
||||||
{
|
|
||||||
list.Add(parentTypeDef);
|
|
||||||
parentType = parentTypeDef.ParentDefinedType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// functions
|
|
||||||
foreach (var f in sch.functions)
|
|
||||||
{
|
|
||||||
var functionReturnTypes = GetDistributedTypes(f.MethodInfo.ReturnType);
|
|
||||||
|
|
||||||
foreach (var functionReturnType in functionReturnTypes)
|
|
||||||
{
|
|
||||||
var functionReturnTypeDef = warehouse.GetTypeDefByType(functionReturnType);
|
|
||||||
if (functionReturnTypeDef != null)
|
|
||||||
{
|
|
||||||
if (!bag.Contains(functionReturnTypeDef))
|
|
||||||
{
|
|
||||||
list.Add(functionReturnTypeDef);
|
|
||||||
getDependenciesFunc(functionReturnTypeDef, bag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var args = f.MethodInfo.GetParameters();
|
|
||||||
|
|
||||||
for (var i = 0; i < args.Length - 1; i++)
|
|
||||||
{
|
|
||||||
var fpTypes = GetDistributedTypes(args[i].ParameterType);
|
|
||||||
|
|
||||||
foreach (var fpType in fpTypes)
|
|
||||||
{
|
|
||||||
var fpt = warehouse.GetTypeDefByType(fpType);
|
|
||||||
if (fpt != null)
|
|
||||||
{
|
|
||||||
if (!bag.Contains(fpt))
|
|
||||||
{
|
|
||||||
bag.Add(fpt);
|
|
||||||
getDependenciesFunc(fpt, bag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip EpConnection argument
|
|
||||||
if (args.Length > 0)
|
|
||||||
{
|
|
||||||
var last = args.Last();
|
|
||||||
if (last.ParameterType != typeof(EpConnection))
|
|
||||||
{
|
|
||||||
|
|
||||||
var fpTypes = GetDistributedTypes(last.ParameterType);
|
|
||||||
|
|
||||||
foreach (var fpType in fpTypes)
|
|
||||||
{
|
|
||||||
var fpt = warehouse.GetTypeDefByType(fpType);
|
|
||||||
if (fpt != null)
|
|
||||||
{
|
|
||||||
if (!bag.Contains(fpt))
|
|
||||||
{
|
|
||||||
bag.Add(fpt);
|
|
||||||
getDependenciesFunc(fpt, bag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// properties
|
|
||||||
foreach (var p in sch.properties)
|
|
||||||
{
|
|
||||||
var propertyTypes = GetDistributedTypes(p.PropertyInfo.PropertyType);
|
|
||||||
|
|
||||||
foreach (var propertyType in propertyTypes)
|
|
||||||
{
|
|
||||||
var propertyTypeDef = warehouse.GetTypeDefByType(propertyType);
|
|
||||||
if (propertyTypeDef != null)
|
|
||||||
{
|
|
||||||
if (!bag.Contains(propertyTypeDef))
|
|
||||||
{
|
|
||||||
bag.Add(propertyTypeDef);
|
|
||||||
getDependenciesFunc(propertyTypeDef, bag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// events
|
|
||||||
foreach (var e in sch.events)
|
|
||||||
{
|
|
||||||
var eventTypes = GetDistributedTypes(e.EventInfo.EventHandlerType.GenericTypeArguments[0]);
|
|
||||||
|
|
||||||
foreach (var eventType in eventTypes)
|
|
||||||
{
|
|
||||||
var eventTypeDef = warehouse.GetTypeDefByType(eventType);
|
|
||||||
|
|
||||||
if (eventTypeDef != null)
|
|
||||||
{
|
|
||||||
if (!bag.Contains(eventTypeDef))
|
|
||||||
{
|
|
||||||
bag.Add(eventTypeDef);
|
|
||||||
getDependenciesFunc(eventTypeDef, bag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getDependenciesFunc(schema, list);
|
|
||||||
return list.Distinct().ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static string GetTypeName(Type type, char separator = '.')
|
|
||||||
{
|
|
||||||
|
|
||||||
if (type.IsGenericType)
|
|
||||||
{
|
|
||||||
var index = type.Name.IndexOf("`");
|
|
||||||
var name = $"{type.Namespace}{separator}{((index > -1) ? type.Name.Substring(0, index) : type.Name)}Of";
|
|
||||||
foreach (var t in type.GenericTypeArguments)
|
|
||||||
name += GetTypeName(t, '_');
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return $"{type.Namespace?.Replace('.', separator) ?? "Global"}{separator}{type.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public bool IsWrapper { get; private set; }
|
|
||||||
|
|
||||||
public TypeDef(Type type, Warehouse warehouse = null)
|
|
||||||
{
|
|
||||||
if (Codec.ImplementsInterface(type, typeof(IResource)))
|
|
||||||
typeDefKind = TypeDefKind.Resource;
|
|
||||||
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
|
||||||
typeDefKind = TypeDefKind.Record;
|
|
||||||
else if (type.IsEnum)
|
|
||||||
typeDefKind = TypeDefKind.Enum;
|
|
||||||
else
|
|
||||||
throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource.");
|
|
||||||
|
|
||||||
IsWrapper = Codec.InheritsClass(type, typeof(EpResource));
|
|
||||||
|
|
||||||
type = ResourceProxy.GetBaseType(type);
|
|
||||||
|
|
||||||
DefinedType = type;
|
|
||||||
|
|
||||||
typeName = GetTypeName(type);
|
|
||||||
|
|
||||||
// set guid
|
|
||||||
typeId = GetTypeUUID(type);
|
|
||||||
|
|
||||||
if (warehouse != null)
|
|
||||||
warehouse.RegisterTypeDef(this);
|
|
||||||
|
|
||||||
var hierarchy = GetHierarchy(type);
|
|
||||||
|
|
||||||
if (hierarchy.ContainsKey(MemberTypes.Field))
|
|
||||||
{
|
|
||||||
foreach (var cd in hierarchy[MemberTypes.Field])
|
|
||||||
{
|
|
||||||
constants.Add(ConstantDef.MakeConstantDef
|
|
||||||
(type, (FieldInfo)cd.GetMemberInfo(), cd.Index, cd.Name, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hierarchy.ContainsKey(MemberTypes.Property))
|
|
||||||
{
|
|
||||||
foreach (var pd in hierarchy[MemberTypes.Property])
|
|
||||||
{
|
|
||||||
properties.Add(PropertyDef.MakePropertyDef
|
|
||||||
(type, (PropertyInfo)pd.GetMemberInfo(), pd.Name, pd.Index, pd.PropertyPermission, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeDefKind == TypeDefKind.Resource)
|
|
||||||
{
|
|
||||||
if (hierarchy.ContainsKey(MemberTypes.Method))
|
|
||||||
{
|
|
||||||
foreach (var fd in hierarchy[MemberTypes.Method])
|
|
||||||
{
|
|
||||||
functions.Add(FunctionDef.MakeFunctionDef
|
|
||||||
(type, (MethodInfo)fd.GetMemberInfo(), fd.Index, fd.Name, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hierarchy.ContainsKey(MemberTypes.Event))
|
|
||||||
{
|
|
||||||
foreach (var ed in hierarchy[MemberTypes.Event])
|
|
||||||
{
|
|
||||||
events.Add(EventDef.MakeEventDef
|
|
||||||
(type, (EventInfo)ed.GetMemberInfo(), ed.Index, ed.Name, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// add attributes
|
|
||||||
var attrs = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(x => x.GetCustomAttribute<AttributeAttribute>() != null);
|
|
||||||
|
|
||||||
foreach (var attr in attrs)
|
|
||||||
{
|
|
||||||
var attrAttr = attr.GetCustomAttribute<AttributeAttribute>();
|
|
||||||
|
|
||||||
attributes.Add(AttributeDef
|
|
||||||
.MakeAttributeDef(type, attr, 0, attrAttr?.Name ?? attr.Name, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// bake it binarily
|
|
||||||
var b = new BinaryList();
|
|
||||||
|
|
||||||
// find the first parent type that implements IResource
|
|
||||||
|
|
||||||
|
|
||||||
var hasParent = HasParent(type);
|
|
||||||
var classAnnotations = type.GetCustomAttributes<AnnotationAttribute>(false);
|
|
||||||
|
|
||||||
|
|
||||||
var hasClassAnnotation = (classAnnotations != null) && (classAnnotations.Count() > 0);
|
|
||||||
|
|
||||||
var typeNameBytes = DC.ToBytes(typeName);
|
|
||||||
|
|
||||||
b.AddUInt8((byte)((hasParent ? 0x80 : 0) | (hasClassAnnotation ? 0x40 : 0x0) | (byte)typeDefKind))
|
|
||||||
.AddUUID(typeId)
|
|
||||||
.AddUInt8((byte)typeNameBytes.Length)
|
|
||||||
.AddUInt8Array(typeNameBytes);
|
|
||||||
|
|
||||||
if (hasParent)
|
|
||||||
{
|
|
||||||
// find the first parent type that implements IResource
|
|
||||||
ParentDefinedType = ResourceProxy.GetBaseType(type.BaseType);
|
|
||||||
var parentId = GetTypeUUID(ParentDefinedType);
|
|
||||||
b.AddUUID(parentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasClassAnnotation)
|
|
||||||
{
|
|
||||||
Annotations = new Map<string, string>();
|
|
||||||
|
|
||||||
foreach (var ann in classAnnotations)
|
|
||||||
Annotations.Add(ann.Key, ann.Value);
|
|
||||||
|
|
||||||
var classAnnotationBytes = Codec.Compose (Annotations, null, null);
|
|
||||||
|
|
||||||
b.AddUInt8Array(classAnnotationBytes);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
b.AddInt32(version)
|
|
||||||
.AddUInt16((ushort)(functions.Count + properties.Count + events.Count + constants.Count));
|
|
||||||
|
|
||||||
foreach (var ft in functions)
|
|
||||||
b.AddUInt8Array(ft.Compose());
|
|
||||||
foreach (var pt in properties)
|
|
||||||
b.AddUInt8Array(pt.Compose());
|
|
||||||
foreach (var et in events)
|
|
||||||
b.AddUInt8Array(et.Compose());
|
|
||||||
foreach (var ct in constants)
|
|
||||||
b.AddUInt8Array(ct.Compose());
|
|
||||||
|
|
||||||
content = b.ToArray();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasParent(Type type)
|
|
||||||
{
|
|
||||||
var parent = type.BaseType;
|
|
||||||
|
|
||||||
|
|
||||||
while (parent != null)
|
|
||||||
{
|
|
||||||
if (parent == typeof(Esiur.Resource.Resource)
|
|
||||||
|| parent == typeof(Record)
|
|
||||||
|| parent == typeof(EntryPoint))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (parent.GetInterfaces().Contains(typeof(IResource))
|
|
||||||
|| parent.GetInterfaces().Contains(typeof(IRecord)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
parent = parent.BaseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static Dictionary<MemberTypes, List<MemberData>> GetHierarchy(Type type)
|
|
||||||
{
|
|
||||||
var members = new List<MemberData>();
|
|
||||||
|
|
||||||
var order = 0;
|
|
||||||
|
|
||||||
while (type != null)
|
|
||||||
{
|
|
||||||
var classIsPublic = type.IsEnum || (type.GetCustomAttribute<ExportAttribute>() != null);
|
|
||||||
|
|
||||||
if (classIsPublic)
|
|
||||||
{
|
|
||||||
// get public instance members only.
|
|
||||||
var mis = type.GetMembers(BindingFlags.Public | BindingFlags.Instance
|
|
||||||
| BindingFlags.DeclaredOnly | BindingFlags.Static)
|
|
||||||
.Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
|
|
||||||
|| x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
|
|
||||||
.Where(x => !(x is FieldInfo c && !c.IsStatic))
|
|
||||||
.Where(x => x.GetCustomAttribute<IgnoreAttribute>() == null)
|
|
||||||
.Where(x => x.Name != "Instance")
|
|
||||||
.Where(x => x.Name != "Trigger")
|
|
||||||
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
|
|
||||||
.Where(x => !(x is EventInfo e &&
|
|
||||||
!(e.EventHandlerType.IsGenericType &&
|
|
||||||
(e.EventHandlerType.GetGenericTypeDefinition() == typeof(ResourceEventHandler<>)
|
|
||||||
|| e.EventHandlerType.GetGenericTypeDefinition() == typeof(CustomResourceEventHandler<>))
|
|
||||||
)
|
|
||||||
))
|
|
||||||
.Select(x => new MemberData(
|
|
||||||
info: x,
|
|
||||||
order: order
|
|
||||||
))
|
|
||||||
.OrderBy(x => x.Name);
|
|
||||||
|
|
||||||
members.AddRange(mis.ToArray());
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// allow private and public members that are marked with [Export] attribute.
|
|
||||||
var mis = type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
|
||||||
| BindingFlags.DeclaredOnly | BindingFlags.Static)
|
|
||||||
.Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
|
|
||||||
|| x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
|
|
||||||
.Where(x => !(x is FieldInfo c && !c.IsStatic))
|
|
||||||
.Where(x => x.GetCustomAttribute<ExportAttribute>() != null)
|
|
||||||
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
|
|
||||||
.Select(x => new MemberData(
|
|
||||||
info: x,
|
|
||||||
order: order
|
|
||||||
))
|
|
||||||
.OrderBy(x => x.Name);
|
|
||||||
|
|
||||||
members.AddRange(mis.ToArray());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type = type.BaseType;
|
|
||||||
|
|
||||||
if (type == null
|
|
||||||
|| type == typeof(Esiur.Resource.Resource)
|
|
||||||
|| type == typeof(Record)
|
|
||||||
|| type == typeof(EntryPoint))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (type.GetInterfaces().Contains(typeof(IResource))
|
|
||||||
|| type.GetInterfaces().Contains(typeof(IRecord)))
|
|
||||||
{
|
|
||||||
order++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// round 2: check for duplicates
|
|
||||||
for (var i = 0; i < members.Count; i++)
|
|
||||||
{
|
|
||||||
var mi = members[i];
|
|
||||||
for (var j = i + 1; j < members.Count; j++)
|
|
||||||
{
|
|
||||||
var pi = members[j];
|
|
||||||
if (pi.Info.MemberType != mi.Info.MemberType)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//if (ci.Info.Name == mi.Info.Name && ci.Order == mi.Order)
|
|
||||||
// throw new Exception($"Method overload is not supported. Method '{ci.Info.Name}'.");
|
|
||||||
|
|
||||||
if (pi.Name == mi.Name)
|
|
||||||
{
|
|
||||||
if (pi.Order == mi.Order)
|
|
||||||
throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// @TODO: check for return type and parameters they must match
|
|
||||||
if (pi.Info.Name != mi.Info.Name)
|
|
||||||
throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
mi.Parent = pi;
|
|
||||||
pi.Child = mi;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// assign indexes
|
|
||||||
var groups = members.Where(x => x.Parent == null)
|
|
||||||
.OrderBy(x => x.Name).OrderByDescending(x => x.Order)
|
|
||||||
.GroupBy(x => x.Info.MemberType);
|
|
||||||
|
|
||||||
foreach (var group in groups)
|
|
||||||
{
|
|
||||||
byte index = 0;
|
|
||||||
foreach (var mi in group)
|
|
||||||
{
|
|
||||||
//if (mi.Parent == null)
|
|
||||||
mi.Index = index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var rt = groups.ToDictionary(g => g.Key, g => g.ToList());
|
|
||||||
|
|
||||||
return rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static TypeDef Parse(byte[] data)
|
|
||||||
{
|
|
||||||
return Parse(data, 0, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static TypeDef Parse(byte[] data, uint offset, uint contentLength)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint ends = offset + contentLength;
|
|
||||||
|
|
||||||
uint oOffset = offset;
|
|
||||||
|
|
||||||
// start parsing...
|
|
||||||
|
|
||||||
var od = new TypeDef();
|
|
||||||
od.content = data.Clip(offset, contentLength);
|
|
||||||
|
|
||||||
var hasParent = (data[offset] & 0x80) > 0;
|
|
||||||
var hasClassAnnotation = (data[offset] & 0x40) > 0;
|
|
||||||
|
|
||||||
od.typeDefKind = (TypeDefKind)(data[offset++] & 0xF);
|
|
||||||
|
|
||||||
od.typeId = data.GetUUID(offset);
|
|
||||||
offset += 16;
|
|
||||||
od.typeName = data.GetString(offset + 1, data[offset]);
|
|
||||||
offset += (uint)data[offset] + 1;
|
|
||||||
|
|
||||||
|
|
||||||
if (hasParent)
|
|
||||||
{
|
|
||||||
od.parentId = data.GetUUID(offset);
|
|
||||||
offset += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasClassAnnotation)
|
|
||||||
{
|
|
||||||
var (len, anns) = Codec.ParseSync(data, offset, null);
|
|
||||||
|
|
||||||
if (anns is Map<string, string> annotations)
|
|
||||||
od.Annotations = annotations;
|
|
||||||
|
|
||||||
offset += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
od.version = data.GetInt32(offset, Endian.Little);
|
|
||||||
offset += 4;
|
|
||||||
|
|
||||||
ushort methodsCount = data.GetUInt16(offset, Endian.Little);
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
byte functionIndex = 0;
|
|
||||||
byte propertyIndex = 0;
|
|
||||||
byte eventIndex = 0;
|
|
||||||
byte constantIndex = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < methodsCount; i++)
|
|
||||||
{
|
|
||||||
var inherited = (data[offset] & 0x80) > 0;
|
|
||||||
var type = (data[offset] >> 5) & 0x3;
|
|
||||||
|
|
||||||
if (type == 0) // function
|
|
||||||
{
|
|
||||||
var (len, ft) = FunctionDef.Parse(data, offset, functionIndex++, inherited);
|
|
||||||
offset += len;
|
|
||||||
od.functions.Add(ft);
|
|
||||||
}
|
|
||||||
else if (type == 1) // property
|
|
||||||
{
|
|
||||||
var (len, pt) = PropertyDef.Parse(data, offset, propertyIndex++, inherited);
|
|
||||||
offset += len;
|
|
||||||
od.properties.Add(pt);
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (type == 2) // Event
|
|
||||||
{
|
|
||||||
var (len, et) = EventDef.Parse(data, offset, eventIndex++, inherited);
|
|
||||||
offset += len;
|
|
||||||
od.events.Add(et);
|
|
||||||
}
|
|
||||||
// constant
|
|
||||||
else if (type == 3)
|
|
||||||
{
|
|
||||||
var (len, ct) = ConstantDef.Parse(data, offset, constantIndex++, inherited);
|
|
||||||
offset += len;
|
|
||||||
od.constants.Add(ct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return od;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<byte, object> CastProperties(Map<string, object> properties)
|
public Map<byte, object> CastProperties(Map<string, object> properties)
|
||||||
{
|
{
|
||||||
var rt = new Map<byte, object>();
|
var rt = new Map<byte, object>();
|
||||||
@@ -755,5 +162,12 @@ public class TypeDef
|
|||||||
|
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual byte[] Compose(EpConnection connection)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,33 +59,37 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Remove="Data\IRemoteRecord.cs" />
|
||||||
<Compile Remove="Data\NullabilityInfo.cs" />
|
<Compile Remove="Data\NullabilityInfo.cs" />
|
||||||
<Compile Remove="Data\NullabilityInfoContext.cs" />
|
<Compile Remove="Data\NullabilityInfoContext.cs" />
|
||||||
|
<Compile Remove="Data\TypeDefId.cs" />
|
||||||
|
<Compile Remove="Net\Packets\EpAuthPacketAcknowledgement.cs" />
|
||||||
|
<Compile Remove="Net\Packets\EpAuthPacketAction.cs" />
|
||||||
<Compile Remove="Net\Packets\EpAuthPacketAuthMode.cs" />
|
<Compile Remove="Net\Packets\EpAuthPacketAuthMode.cs" />
|
||||||
|
<Compile Remove="Net\Packets\EpAuthPacketEvent.cs" />
|
||||||
<Compile Remove="Net\Sockets\TcpSocket.cs" />
|
<Compile Remove="Net\Sockets\TcpSocket.cs" />
|
||||||
<Compile Remove="Protocol\Authentication\HashAnonymousAuthenticator.cs" />
|
<Compile Remove="Protocol\Authentication\HashAnonymousAuthenticator.cs" />
|
||||||
<Compile Remove="Security\Authority\Authentication.cs" />
|
|
||||||
<Compile Remove="Security\Authority\AuthenticationMethod.cs" />
|
<Compile Remove="Security\Authority\AuthenticationMethod.cs" />
|
||||||
<Compile Remove="Security\Authority\IAuthenticationInitiator.cs" />
|
|
||||||
<Compile Remove="Security\Authority\IAuthenticationResponder.cs" />
|
|
||||||
<Compile Remove="Security\Membership\SimpleMembership.cs" />
|
<Compile Remove="Security\Membership\SimpleMembership.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="Data\IRemoteRecord.cs" />
|
||||||
<None Include="Data\NullabilityInfo.cs" />
|
<None Include="Data\NullabilityInfo.cs" />
|
||||||
<None Include="Data\NullabilityInfoContext.cs" />
|
<None Include="Data\NullabilityInfoContext.cs" />
|
||||||
|
<None Include="Data\TypeDefId.cs" />
|
||||||
<None Include="Data\Types\ArgumentDef.cs" />
|
<None Include="Data\Types\ArgumentDef.cs" />
|
||||||
<None Include="Data\Types\AttributeDef.cs" />
|
<None Include="Data\Types\AttributeDef.cs" />
|
||||||
<None Include="LICENSE" Pack="true" PackagePath=""></None>
|
<None Include="LICENSE" Pack="true" PackagePath=""></None>
|
||||||
|
<None Include="Net\Packets\EpAuthPacketAcknowledgement.cs" />
|
||||||
|
<None Include="Net\Packets\EpAuthPacketAction.cs" />
|
||||||
<None Include="Net\Packets\EpAuthPacketAuthMode.cs" />
|
<None Include="Net\Packets\EpAuthPacketAuthMode.cs" />
|
||||||
|
<None Include="Net\Packets\EpAuthPacketEvent.cs" />
|
||||||
<None Include="Net\Sockets\TcpSocket.cs" />
|
<None Include="Net\Sockets\TcpSocket.cs" />
|
||||||
<None Include="Protocol\Authentication\HashAnonymousAuthenticator.cs" />
|
<None Include="Protocol\Authentication\HashAnonymousAuthenticator.cs" />
|
||||||
<None Include="README.md" Pack="true" PackagePath="" />
|
<None Include="README.md" Pack="true" PackagePath="" />
|
||||||
<None Include="Security\Authority\Authentication.cs" />
|
|
||||||
<None Include="Security\Authority\AuthenticationMethod.cs" />
|
<None Include="Security\Authority\AuthenticationMethod.cs" />
|
||||||
<None Include="Security\Authority\IAuthenticationInitiator.cs" />
|
|
||||||
<None Include="Security\Authority\IAuthenticationResponder.cs" />
|
|
||||||
<None Include="Security\Membership\SimpleMembership.cs" />
|
<None Include="Security\Membership\SimpleMembership.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Esiur.Data;
|
using Esiur.Data;
|
||||||
|
using Esiur.Resource;
|
||||||
using Esiur.Security.Authority;
|
using Esiur.Security.Authority;
|
||||||
using Esiur.Security.Cryptography;
|
using Esiur.Security.Cryptography;
|
||||||
using System;
|
using System;
|
||||||
@@ -38,29 +39,39 @@ namespace Esiur.Net.Packets;
|
|||||||
|
|
||||||
public class EpAuthPacket : Packet
|
public class EpAuthPacket : Packet
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Warehouse _warehouse;
|
||||||
|
|
||||||
|
public EpAuthPacket(Warehouse warehouse)
|
||||||
|
{
|
||||||
|
_warehouse = warehouse;
|
||||||
|
}
|
||||||
|
|
||||||
public EpAuthPacketCommand Command
|
public EpAuthPacketCommand Command
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EpAuthPacketAction Action
|
public EpAuthPacketMethod Method { get; set; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EpAuthPacketEvent Event
|
//public EpAuthPacketAction Action
|
||||||
{
|
//{
|
||||||
get;
|
// get;
|
||||||
set;
|
// set;
|
||||||
}
|
//}
|
||||||
|
|
||||||
public EpAuthPacketAcknowledgement Acknowledgement
|
//public EpAuthPacketEvent Event
|
||||||
{
|
//{
|
||||||
get;
|
// get;
|
||||||
set;
|
// set;
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
//public EpAuthPacketAcknowledgement Acknowledgement
|
||||||
|
//{
|
||||||
|
// get;
|
||||||
|
// set;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
public AuthenticationMode AuthMode
|
public AuthenticationMode AuthMode
|
||||||
@@ -101,7 +112,7 @@ public class EpAuthPacket : Packet
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ParsedTdu? Tdu
|
public PlainTdu? Tdu
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
@@ -114,8 +125,6 @@ public class EpAuthPacket : Packet
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private uint dataLengthNeeded;
|
private uint dataLengthNeeded;
|
||||||
|
|
||||||
bool NotEnough(uint offset, uint ends, uint needed)
|
bool NotEnough(uint offset, uint ends, uint needed)
|
||||||
@@ -131,7 +140,7 @@ public class EpAuthPacket : Packet
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Command.ToString() + " " + Action.ToString();
|
return Command.ToString() + " " + Method.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override long Parse(byte[] data, uint offset, uint ends)
|
public override long Parse(byte[] data, uint offset, uint ends)
|
||||||
@@ -146,23 +155,23 @@ public class EpAuthPacket : Packet
|
|||||||
|
|
||||||
if (Command == EpAuthPacketCommand.Initialize)
|
if (Command == EpAuthPacketCommand.Initialize)
|
||||||
{
|
{
|
||||||
AuthMode = (AuthenticationMode)(data[offset] >> 3 & 0x7);
|
AuthMode = (AuthenticationMode)(data[offset] >> 2 & 0x4);
|
||||||
EncryptionMode = (EncryptionMode)(data[offset++] & 0x7);
|
EncryptionMode = (EncryptionMode)(data[offset++] & 0x7);
|
||||||
}
|
}
|
||||||
else if (Command == EpAuthPacketCommand.Acknowledge)
|
else if (Command == EpAuthPacketCommand.Acknowledge)
|
||||||
{
|
{
|
||||||
// remove last two reserved LSBs
|
// remove hasTdu
|
||||||
Acknowledgement = (EpAuthPacketAcknowledgement)(data[offset++]);// & 0xFC);
|
Method = (EpAuthPacketMethod)(data[offset++] & 0xDF);
|
||||||
}
|
}
|
||||||
else if (Command == EpAuthPacketCommand.Action)
|
else if (Command == EpAuthPacketCommand.Action)
|
||||||
{
|
{
|
||||||
// remove last two reserved LSBs
|
// remove hasTdu
|
||||||
Action = (EpAuthPacketAction)(data[offset++]);// & 0xFC);
|
Method = (EpAuthPacketMethod)(data[offset++] & 0xDF);
|
||||||
}
|
}
|
||||||
else if (Command == EpAuthPacketCommand.Event)
|
else if (Command == EpAuthPacketCommand.Event)
|
||||||
{
|
{
|
||||||
// remove last two reserved LSBs
|
// remove hasTdu
|
||||||
Event = (EpAuthPacketEvent)(data[offset++]);// & 0xFC);
|
Method = (EpAuthPacketMethod)(data[offset++] & 0xDF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -174,7 +183,7 @@ public class EpAuthPacket : Packet
|
|||||||
if (NotEnough(offset, ends, 1))
|
if (NotEnough(offset, ends, 1))
|
||||||
return -dataLengthNeeded;
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
Tdu = ParsedTdu.Parse(data, offset, ends);
|
Tdu = PlainTdu.Parse(data, offset, ends);//, _warehouse);
|
||||||
|
|
||||||
if (Tdu.Value.Class == TduClass.Invalid)
|
if (Tdu.Value.Class == TduClass.Invalid)
|
||||||
return -(int)Tdu.Value.TotalLength;
|
return -(int)Tdu.Value.TotalLength;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ namespace Esiur.Net.Packets
|
|||||||
Referrer,
|
Referrer,
|
||||||
Time,
|
Time,
|
||||||
IPAddress,
|
IPAddress,
|
||||||
|
Identity,
|
||||||
|
AuthenticationProtocol,
|
||||||
AuthenticationData,
|
AuthenticationData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Net.Packets
|
||||||
|
{
|
||||||
|
public enum EpAuthPacketMethod
|
||||||
|
{
|
||||||
|
// Initialize
|
||||||
|
Initialize = 0x00,
|
||||||
|
//InitializeEncrypted = 0x01,
|
||||||
|
//InitializeNoAuth = 0x02,
|
||||||
|
//InitializeNoAuthEncrypted = 0x3,
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
Handshake = 0x80,
|
||||||
|
FinalHandshake = 0x81,
|
||||||
|
|
||||||
|
// Acks
|
||||||
|
Denied = 0x40, // no reason, terminate connection
|
||||||
|
NotSupported = 0x41, // auth not supported, terminate connection
|
||||||
|
TrySupported = 0x42, // auth not supported, but other auth methods in the reply are supported. connection is still open
|
||||||
|
Retry = 0x43, // try another auth method, connection is still open
|
||||||
|
ProceedToHandshake = 0x44, // auth method accepted, proceed to handshake, connection is still open
|
||||||
|
ProceedToFinalHandshake = 0x45, // auth method accepted, proceed to final handshake, connection is still open
|
||||||
|
ProceedToEstablishSession = 0x46, // auth method accepted, proceed to establish session, connection is still open
|
||||||
|
SessionEstablished = 0x47, // session established, session Id provided, switch to session mode, connection is still open
|
||||||
|
|
||||||
|
// Events
|
||||||
|
ErrorTerminate = 0xC0,
|
||||||
|
ErrorMustEncrypt = 0xC1,
|
||||||
|
ErrorRetry = 0xC2,
|
||||||
|
|
||||||
|
IndicationEstablished = 0xC8,
|
||||||
|
|
||||||
|
IAuthPlain = 0xD0,
|
||||||
|
IAuthHashed = 0xD1,
|
||||||
|
IAuthEncrypted = 0xD2
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Esiur.Resource;
|
||||||
|
|
||||||
namespace Esiur.Net.Packets;
|
namespace Esiur.Net.Packets;
|
||||||
class EpPacket : Packet
|
class EpPacket : Packet
|
||||||
@@ -44,12 +45,22 @@ class EpPacket : Packet
|
|||||||
|
|
||||||
public byte Extension { get; set; }
|
public byte Extension { get; set; }
|
||||||
|
|
||||||
public ParsedTdu? Tdu { get; set; }
|
//public ParsedTdu? Tdu { get; set; }
|
||||||
|
|
||||||
|
//public byte[] TduPayload { get; set; }
|
||||||
|
|
||||||
|
public PlainTdu? Tdu { get; set; }
|
||||||
|
|
||||||
private uint dataLengthNeeded;
|
private uint dataLengthNeeded;
|
||||||
private uint originalOffset;
|
private uint originalOffset;
|
||||||
|
|
||||||
|
Warehouse _warehouse;
|
||||||
|
|
||||||
|
public EpPacket(Warehouse warehouse)
|
||||||
|
{
|
||||||
|
_warehouse = warehouse;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Compose()
|
public override bool Compose()
|
||||||
{
|
{
|
||||||
return base.Compose();
|
return base.Compose();
|
||||||
@@ -124,15 +135,22 @@ class EpPacket : Packet
|
|||||||
if (NotEnough(offset, ends, 1))
|
if (NotEnough(offset, ends, 1))
|
||||||
return -dataLengthNeeded;
|
return -dataLengthNeeded;
|
||||||
|
|
||||||
Tdu = ParsedTdu.Parse(data, offset, ends);
|
Tdu = PlainTdu.Parse(data, offset, ends);
|
||||||
|
|
||||||
if (Tdu.Value.Class == TduClass.Invalid)
|
if (Tdu.Value.Class == TduClass.Invalid)
|
||||||
return -(int)Tdu.Value.TotalLength;
|
return -(int)Tdu.Value.TotalLength;
|
||||||
|
|
||||||
|
//Tdu = ParsedTdu.ParseSync(data, offset, ends, _warehouse);
|
||||||
|
|
||||||
|
//if (Tdu.Value.Class == TduClass.Invalid)
|
||||||
|
// return -(int)Tdu.Value.TotalLength;
|
||||||
|
|
||||||
|
//offset += (uint)Tdu.Value.TotalLength;
|
||||||
offset += (uint)Tdu.Value.TotalLength;
|
offset += (uint)Tdu.Value.TotalLength;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//Tdu = null;
|
||||||
Tdu = null;
|
Tdu = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
|||||||
using Esiur.Core;
|
|
||||||
using Esiur.Data;
|
|
||||||
using Esiur.Net.Packets;
|
|
||||||
using Esiur.Security.Membership;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Esiur.Protocol;
|
|
||||||
|
|
||||||
public class EpConnectionConfig
|
|
||||||
{
|
|
||||||
public ExceptionLevel ExceptionLevel { get; set; }
|
|
||||||
= ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace;
|
|
||||||
|
|
||||||
public Func<AuthorizationRequest, AsyncReply<object>> Authenticator { get; set; }
|
|
||||||
|
|
||||||
public bool AutoReconnect { get; set; } = false;
|
|
||||||
|
|
||||||
public uint ReconnectInterval { get; set; } = 5;
|
|
||||||
|
|
||||||
public string Username { get; set; }
|
|
||||||
|
|
||||||
public bool UseWebSocket { get; set; }
|
|
||||||
|
|
||||||
public bool SecureWebSocket { get; set; }
|
|
||||||
|
|
||||||
public string Password { get; set; }
|
|
||||||
|
|
||||||
public string Token { get; set; }
|
|
||||||
|
|
||||||
public ulong TokenIndex { get; set; }
|
|
||||||
|
|
||||||
public string Domain { get; set; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using Esiur.Core;
|
||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Net.Packets;
|
||||||
|
using Esiur.Resource;
|
||||||
|
using Esiur.Security.Membership;
|
||||||
|
using Esiur.Security.Permissions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Protocol;
|
||||||
|
|
||||||
|
public class EpConnectionContext : ResourceContext
|
||||||
|
{
|
||||||
|
public EpConnectionContext()
|
||||||
|
: base(0, new Map<string, object>(), null, null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Build()
|
||||||
|
{
|
||||||
|
Attributes["AutoConnect"] = AutoReconnect;
|
||||||
|
Attributes["ReconnectInterval"] = ReconnectInterval;
|
||||||
|
Attributes["UseWebSocket"] = UseWebSocket;
|
||||||
|
Attributes["SecureWebSocket"] = SecureWebSocket;
|
||||||
|
Attributes["Domain"] = SecureWebSocket;
|
||||||
|
Attributes["AuthenticationProtocol"] = SecureWebSocket;
|
||||||
|
Attributes["Identity"] = SecureWebSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExceptionLevel ExceptionLevel { get; set; }
|
||||||
|
= ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace;
|
||||||
|
|
||||||
|
//public Func<AuthorizationRequest, AsyncReply<object>> Authenticator { get; set; }
|
||||||
|
//public Func<AuthorizationRequest, AsyncReply<object>> Authenticator { get; set; }
|
||||||
|
|
||||||
|
public string Identity { get; set; }
|
||||||
|
public string AuthenticationProtocol { get; set; }
|
||||||
|
|
||||||
|
public bool AutoReconnect { get; set; } = false;
|
||||||
|
|
||||||
|
public uint ReconnectInterval { get; set; } = 5;
|
||||||
|
|
||||||
|
//public string Username { get; set; }
|
||||||
|
|
||||||
|
public bool UseWebSocket { get; set; }
|
||||||
|
|
||||||
|
public bool SecureWebSocket { get; set; }
|
||||||
|
|
||||||
|
// public string Password { get; set; }
|
||||||
|
|
||||||
|
//public string Token { get; set; }
|
||||||
|
|
||||||
|
//public ulong TokenIndex { get; set; }
|
||||||
|
|
||||||
|
public string Domain { get; set; }
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -81,7 +81,7 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connection responsible for the distributed resource.
|
/// Connection responsible for the distributed resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EpConnection DistributedResourceConnection
|
public EpConnection ResourceConnection
|
||||||
{
|
{
|
||||||
get { return connection; }
|
get { return connection; }
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resource link
|
/// Resource link
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DistributedResourceLink
|
public string ResourceLink
|
||||||
{
|
{
|
||||||
get { return link; }
|
get { return link; }
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instance Id given by the other end.
|
/// Instance Id given by the other end.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint DistributedResourceInstanceId
|
public uint ResourceInstanceId
|
||||||
{
|
{
|
||||||
get { return instanceId; }
|
get { return instanceId; }
|
||||||
internal set { instanceId = value; }
|
internal set { instanceId = value; }
|
||||||
@@ -128,9 +128,9 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resource is attached when all its properties are received.
|
/// Resource is attached when all its properties are received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DistributedResourceAttached => attached;
|
public bool ResourceAttached => attached;
|
||||||
|
|
||||||
public bool DistributedResourceSuspended => suspended;
|
public bool ResourceSuspended => suspended;
|
||||||
|
|
||||||
|
|
||||||
// public DistributedResourceStack Stack
|
// public DistributedResourceStack Stack
|
||||||
@@ -216,10 +216,18 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
public AsyncReply Subscribe(EventDef et)
|
public AsyncReply Subscribe(EventDef et)
|
||||||
{
|
{
|
||||||
if (et == null)
|
if (et == null)
|
||||||
return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, ""));
|
{
|
||||||
|
var rt = new AsyncReply();
|
||||||
|
rt.TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, ""));
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
if (!et.Subscribable)
|
if (!et.Subscribable)
|
||||||
return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotSubscribable, ""));
|
{
|
||||||
|
var rt = new AsyncReply();
|
||||||
|
rt.TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotSubscribable, ""));
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
return connection.SendSubscribeRequest(instanceId, et.Index);
|
return connection.SendSubscribeRequest(instanceId, et.Index);
|
||||||
}
|
}
|
||||||
@@ -235,10 +243,18 @@ public class EpResource : DynamicObject, IResource, INotifyPropertyChanged, IDyn
|
|||||||
public AsyncReply Unsubscribe(EventDef et)
|
public AsyncReply Unsubscribe(EventDef et)
|
||||||
{
|
{
|
||||||
if (et == null)
|
if (et == null)
|
||||||
return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, ""));
|
{
|
||||||
|
var rt = new AsyncReply();
|
||||||
|
rt.TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.MethodNotFound, ""));
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
if (!et.Subscribable)
|
if (!et.Subscribable)
|
||||||
return new AsyncReply().TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotSubscribable, ""));
|
{
|
||||||
|
var rt = new AsyncReply();
|
||||||
|
rt.TriggerError(new AsyncException(ErrorType.Management, (ushort)ExceptionCode.NotSubscribable, ""));
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
return connection.SendUnsubscribeRequest(instanceId, et.Index);
|
return connection.SendUnsubscribeRequest(instanceId, et.Index);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Esiur.Protocol;
|
namespace Esiur.Protocol;
|
||||||
|
|
||||||
internal class EpResourceAttachRequestInfo
|
internal class FetchRequestInfo<TValue, TId>
|
||||||
{
|
{
|
||||||
public AsyncReply<EpResource> Reply { get; set; }
|
public AsyncReply<TValue> Reply { get; set; }
|
||||||
public uint[] RequestSequence { get; set; }
|
public TId[] RequestSequence { get; set; }
|
||||||
|
|
||||||
public EpResourceAttachRequestInfo(AsyncReply<EpResource> reply, uint[] requestSequence)
|
public FetchRequestInfo(AsyncReply<TValue> reply, TId[] requestSequence)
|
||||||
{
|
{
|
||||||
Reply = reply;
|
Reply = reply;
|
||||||
RequestSequence = requestSequence;
|
RequestSequence = requestSequence;
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ public class EpServer : NetworkServer<EpConnection>, IResource
|
|||||||
|
|
||||||
public EpServer MapCall(string call, Delegate handler)
|
public EpServer MapCall(string call, Delegate handler)
|
||||||
{
|
{
|
||||||
var fd = FunctionDef.MakeFunctionDef(null, handler.Method, 0, call, null);
|
var fd = FunctionDef.MakeFunctionDef(Instance.Warehouse, null, handler.Method, 0, call, null);
|
||||||
Calls.Add(call, new CallInfo() { Delegate = handler, Definition = fd });
|
Calls.Add(call, new CallInfo() { Delegate = handler, Definition = fd });
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ namespace Esiur.Proxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === Emission helpers (ported from your original generator) ===
|
// === Emission helpers (ported from your original generator) ===
|
||||||
private static void EmitTypeDefs(SourceProductionContext spc, TypeDef[] typeDefs)
|
private static void EmitTypeDefs(SourceProductionContext spc, RemoteTypeDef[] typeDefs)
|
||||||
{
|
{
|
||||||
foreach (var typeDef in typeDefs)
|
foreach (var typeDef in typeDefs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public static class TypeDefGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static string GenerateRecord(TypeDef typeDef, TypeDef[] typeDefs)
|
internal static string GenerateRecord(RemoteTypeDef typeDef, TypeDef[] typeDefs)
|
||||||
{
|
{
|
||||||
var cls = typeDef.Name.Split('.');
|
var cls = typeDef.Name.Split('.');
|
||||||
|
|
||||||
@@ -82,7 +82,8 @@ public static class TypeDefGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
//rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
||||||
|
rt.AppendLine($"[Remote(\"{typeDef.Name}\", \"{typeDef.Domain}\")]");
|
||||||
rt.AppendLine($"[Export] public class {className} : IRecord {{");
|
rt.AppendLine($"[Export] public class {className} : IRecord {{");
|
||||||
|
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ public static class TypeDefGenerator
|
|||||||
return rt.ToString();
|
return rt.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GenerateEnum(TypeDef typeDef, TypeDef[] typeDefs)
|
internal static string GenerateEnum(RemoteTypeDef typeDef, TypeDef[] typeDefs)
|
||||||
{
|
{
|
||||||
var cls = typeDef.Name.Split('.');
|
var cls = typeDef.Name.Split('.');
|
||||||
|
|
||||||
@@ -129,7 +130,9 @@ public static class TypeDefGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
//rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
||||||
|
rt.AppendLine($"[Remote(\"{typeDef.Name}\", \"{typeDef.Domain}\")]");
|
||||||
|
|
||||||
rt.AppendLine($"[Export] public enum {className} {{");
|
rt.AppendLine($"[Export] public enum {className} {{");
|
||||||
|
|
||||||
rt.AppendLine(String.Join(",\r\n", typeDef.Constants.Select(x => $"{x.Name}={x.Value}")));
|
rt.AppendLine(String.Join(",\r\n", typeDef.Constants.Select(x => $"{x.Name}={x.Value}")));
|
||||||
@@ -142,19 +145,26 @@ public static class TypeDefGenerator
|
|||||||
|
|
||||||
static string GetTypeName(Tru tru, TypeDef[] typeDefs)
|
static string GetTypeName(Tru tru, TypeDef[] typeDefs)
|
||||||
{
|
{
|
||||||
string name;
|
string name = null;
|
||||||
|
|
||||||
if (tru.Identifier == TruIdentifier.TypedResource)// == DataType.Resource)
|
if (tru is TruTypeDef truTypeDef)
|
||||||
name = typeDefs.First(x => x.Id == tru.UUID && (x.Kind == TypeDefKind.Resource)).Name;
|
{
|
||||||
else if (tru.Identifier == TruIdentifier.TypedRecord)
|
name = truTypeDef.TypeDef.Name;// typeDefs.First(x => x.Id == tru.TypeDef.Value.Value).Name;
|
||||||
name = typeDefs.First(x => x.Id == tru.UUID && x.Kind == TypeDefKind.Record).Name;
|
}
|
||||||
else if (tru.Identifier == TruIdentifier.Enum)
|
//if (tru.Identifier == TruIdentifier.TypedResource)// == DataType.Resource)
|
||||||
name = typeDefs.First(x => x.Id == tru.UUID && x.Kind == TypeDefKind.Enum).Name;
|
// name = typeDefs.First(x => x.Id == tru.UUID && (x.Kind == TypeDefKind.Resource)).Name;
|
||||||
else if (tru.Identifier == TruIdentifier.TypedList)
|
//else if (tru.Identifier == TruIdentifier.TypedRecord)
|
||||||
name = GetTypeName(tru.SubTypes[0], typeDefs) + "[]";
|
// name = typeDefs.First(x => x.Id == tru.UUID && x.Kind == TypeDefKind.Record).Name;
|
||||||
|
//else if (tru.Identifier == TruIdentifier.Enum)
|
||||||
|
// name = typeDefs.First(x => x.Id == tru.UUID && x.Kind == TypeDefKind.Enum).Name;
|
||||||
|
|
||||||
|
else if (tru is TruComposite truComposite)
|
||||||
|
{
|
||||||
|
if (tru.Identifier == TruIdentifier.TypedList)
|
||||||
|
name = GetTypeName(truComposite.SubTypes[0], typeDefs) + "[]";
|
||||||
else if (tru.Identifier == TruIdentifier.TypedMap)
|
else if (tru.Identifier == TruIdentifier.TypedMap)
|
||||||
name = "Map<" + GetTypeName(tru.SubTypes[0], typeDefs)
|
name = "Map<" + GetTypeName(truComposite.SubTypes[0], typeDefs)
|
||||||
+ "," + GetTypeName(tru.SubTypes[1], typeDefs)
|
+ "," + GetTypeName(truComposite.SubTypes[1], typeDefs)
|
||||||
+ ">";
|
+ ">";
|
||||||
else if (tru.Identifier == TruIdentifier.Tuple2 ||
|
else if (tru.Identifier == TruIdentifier.Tuple2 ||
|
||||||
tru.Identifier == TruIdentifier.Tuple3 ||
|
tru.Identifier == TruIdentifier.Tuple3 ||
|
||||||
@@ -162,8 +172,9 @@ public static class TypeDefGenerator
|
|||||||
tru.Identifier == TruIdentifier.Tuple5 ||
|
tru.Identifier == TruIdentifier.Tuple5 ||
|
||||||
tru.Identifier == TruIdentifier.Tuple6 ||
|
tru.Identifier == TruIdentifier.Tuple6 ||
|
||||||
tru.Identifier == TruIdentifier.Tuple7)
|
tru.Identifier == TruIdentifier.Tuple7)
|
||||||
name = "(" + String.Join(",", tru.SubTypes.Select(x => GetTypeName(x, typeDefs)))
|
name = "(" + String.Join(",", truComposite.SubTypes.Select(x => GetTypeName(x, typeDefs)))
|
||||||
+ ")";
|
+ ")";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -193,6 +204,8 @@ public static class TypeDefGenerator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name == null) return "object";
|
||||||
|
|
||||||
return (tru.Nullable) ? name + "?" : name;
|
return (tru.Nullable) ? name + "?" : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,8 +218,9 @@ public static class TypeDefGenerator
|
|||||||
throw new Exception("Invalid EP URL");
|
throw new Exception("Invalid EP URL");
|
||||||
|
|
||||||
var path = urlRegex.Split(url);
|
var path = urlRegex.Split(url);
|
||||||
var con = Warehouse.Default.Get<EpConnection>(path[1] + "://" + path[2],
|
var con = Warehouse.Default.Get<EpConnection>(path[1] + "://" + path[2], new ResourceContext(0,
|
||||||
!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) ? new { Username = username, Password = password } : null
|
new Map<string, object> { ["username"] = username, ["password"] = password }, null, null)
|
||||||
|
// !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) ? new { Username = username, Password = password } : null
|
||||||
).Wait(20000);
|
).Wait(20000);
|
||||||
|
|
||||||
if (con == null)
|
if (con == null)
|
||||||
@@ -279,7 +293,7 @@ public static class TypeDefGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GenerateClass(TypeDef typeDef, TypeDef[] typeDefs, bool asyncSetters)
|
internal static string GenerateClass(RemoteTypeDef typeDef, TypeDef[] typeDefs, bool asyncSetters)
|
||||||
{
|
{
|
||||||
var cls = typeDef.Name.Split('.');
|
var cls = typeDef.Name.Split('.');
|
||||||
|
|
||||||
@@ -302,13 +316,14 @@ public static class TypeDefGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
rt.AppendLine($"[Remote(\"{typeDef.Name}\", \"{typeDef.Domain}\")]");
|
||||||
|
//rt.AppendLine($"[TypeId(\"{typeDef.Id.Data.ToHex(0, 16, null)}\")]");
|
||||||
|
|
||||||
// extends
|
// extends
|
||||||
if (typeDef.ParentId == null)
|
if (typeDef.ParentTypeId == null)
|
||||||
rt.AppendLine($"public class {className} : EpResource {{");
|
rt.AppendLine($"public class {className} : EpResource {{");
|
||||||
else
|
else
|
||||||
rt.AppendLine($"public class {className} : {typeDefs.First(x => x.Id == typeDef.ParentId && x.Kind == TypeDefKind.Resource).Name} {{");
|
rt.AppendLine($"public class {className} : {typeDefs.First(x => x.Id == typeDef.ParentTypeId && x.Kind == TypeDefKind.Resource).Name} {{");
|
||||||
|
|
||||||
|
|
||||||
rt.AppendLine($"public {className}(EpConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {{}}");
|
rt.AppendLine($"public {className}(EpConnection connection, uint instanceId, ulong age, string link) : base(connection, instanceId, age, link) {{}}");
|
||||||
|
|||||||
@@ -710,7 +710,15 @@ public class Instance
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ruling.DontCare;
|
// Apply default permissions if no manager is applicable or if the resource is not available.
|
||||||
|
if (action == ActionType.GetProperty
|
||||||
|
|| action == ActionType.ViewTypeDef
|
||||||
|
|| action == ActionType.ReceiveEvent
|
||||||
|
|| action == ActionType.Attach
|
||||||
|
|| action == ActionType.Execute)
|
||||||
|
return Ruling.Allowed;
|
||||||
|
else
|
||||||
|
return Ruling.Denied;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +761,7 @@ public class Instance
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.definition = warehouse.GetTypeDefByType(resource.GetType());
|
this.definition = warehouse.GetLocalTypeDefByType(resource.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// set ages
|
// set ages
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Resource
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Class, Inherited = false)]
|
||||||
|
public class RemoteAttribute:Attribute
|
||||||
|
{
|
||||||
|
public string Domain { get; private set; }
|
||||||
|
public string FullName { get; private set; }
|
||||||
|
|
||||||
|
public RemoteAttribute(string domain, string fullName)
|
||||||
|
{
|
||||||
|
Domain = domain;
|
||||||
|
FullName = fullName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Security.Authority;
|
||||||
|
using Esiur.Security.Permissions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Resource
|
||||||
|
{
|
||||||
|
public class ResourceContext
|
||||||
|
{
|
||||||
|
public ulong Age { get; }
|
||||||
|
public Map<string, object> Attributes { get; }
|
||||||
|
public Map<string, object> Properties { get; }
|
||||||
|
public IPermissionsManager PermissionsManager { get; }
|
||||||
|
|
||||||
|
public ResourceContext(ulong age, Map<string, object> attributes, Map<string, object> properties, IPermissionsManager permissionsManager)
|
||||||
|
{
|
||||||
|
Age = age;
|
||||||
|
Attributes = attributes;
|
||||||
|
Properties = properties;
|
||||||
|
PermissionsManager = permissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Build()
|
||||||
|
{
|
||||||
|
// update the context based on the current state of the resource and its environment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,13 +29,16 @@ using Esiur.Misc;
|
|||||||
using Esiur.Net.Packets;
|
using Esiur.Net.Packets;
|
||||||
using Esiur.Protocol;
|
using Esiur.Protocol;
|
||||||
using Esiur.Proxy;
|
using Esiur.Proxy;
|
||||||
|
using Esiur.Security.Authority;
|
||||||
using Esiur.Security.Permissions;
|
using Esiur.Security.Permissions;
|
||||||
|
using Org.BouncyCastle.Asn1.Cms;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata;
|
using System.Reflection.Metadata;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -51,47 +54,83 @@ public class Warehouse
|
|||||||
|
|
||||||
//static byte prefixCounter;
|
//static byte prefixCounter;
|
||||||
|
|
||||||
//static AutoList<IStore, Instance> stores = new AutoList<IStore, Instance>(null);
|
ConcurrentDictionary<uint, WeakReference<IResource>> _resources = new ConcurrentDictionary<uint, WeakReference<IResource>>();
|
||||||
ConcurrentDictionary<uint, WeakReference<IResource>> resources = new ConcurrentDictionary<uint, WeakReference<IResource>>();
|
ConcurrentDictionary<IStore, List<WeakReference<IResource>>> _stores = new ConcurrentDictionary<IStore, List<WeakReference<IResource>>>();
|
||||||
ConcurrentDictionary<IStore, List<WeakReference<IResource>>> stores = new ConcurrentDictionary<IStore, List<WeakReference<IResource>>>();
|
|
||||||
|
volatile int _resourceCounter = 0;
|
||||||
|
volatile int _typeDefsCounter = 0;
|
||||||
|
|
||||||
|
|
||||||
uint resourceCounter = 0;
|
//KeyList<TypeDefKind, KeyList<uint, LocalTypeDef>> _localTypeDefs
|
||||||
|
// = new KeyList<TypeDefKind, KeyList<uint, LocalTypeDef>>()
|
||||||
|
// {
|
||||||
|
// [TypeDefKind.Resource] = new KeyList<uint, LocalTypeDef>(),
|
||||||
|
// [TypeDefKind.Record] = new KeyList<uint, LocalTypeDef>(),
|
||||||
|
// [TypeDefKind.Enum] = new KeyList<uint, LocalTypeDef>(),
|
||||||
|
// };
|
||||||
|
|
||||||
|
KeyList<ulong, TypeDef> _localTypeDefs
|
||||||
|
= new KeyList<ulong, TypeDef>();
|
||||||
|
|
||||||
|
|
||||||
KeyList<TypeDefKind, KeyList<Uuid, TypeDef>> typeDefs
|
KeyList<string, KeyList<ulong, RemoteTypeDef>> _remoteTypeDefs
|
||||||
= new KeyList<TypeDefKind, KeyList<Uuid, TypeDef>>()
|
= new KeyList<string, KeyList<ulong, RemoteTypeDef>>();
|
||||||
{
|
|
||||||
[TypeDefKind.Resource] = new KeyList<Uuid, TypeDef>(),
|
|
||||||
[TypeDefKind.Record] = new KeyList<Uuid, TypeDef>(),
|
|
||||||
[TypeDefKind.Enum] = new KeyList<Uuid, TypeDef>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
object typeDefsLock = new object();
|
//KeyList<string, KeyList<TypeDefKind, KeyList<uint, RemoteTypeDef>>> _remoteTypeDefs
|
||||||
|
// = new KeyList<string, KeyList<TypeDefKind, KeyList<uint, RemoteTypeDef>>>();
|
||||||
|
|
||||||
bool warehouseIsOpen = false;
|
|
||||||
|
Map<string, IAuthenticationProvider> _authenticationProviders = new Map<string, IAuthenticationProvider>();
|
||||||
|
List<IPermissionsManager> _permissionsManagers = new List<IPermissionsManager>();
|
||||||
|
|
||||||
|
|
||||||
|
object _typeDefsLock = new object();
|
||||||
|
|
||||||
|
bool _warehouseIsOpen = false;
|
||||||
|
|
||||||
public delegate void StoreEvent(IStore store);
|
public delegate void StoreEvent(IStore store);
|
||||||
public event StoreEvent StoreConnected;
|
public event StoreEvent StoreConnected;
|
||||||
public event StoreEvent StoreDisconnected;
|
public event StoreEvent StoreDisconnected;
|
||||||
|
|
||||||
public delegate AsyncReply<IStore> ProtocolInstance(string name, object properties);
|
public delegate AsyncReply<IStore> ProtocolInstance(string name, ResourceContext resourceContext);
|
||||||
|
|
||||||
public KeyList<string, ProtocolInstance> Protocols { get; } = new KeyList<string, ProtocolInstance>();
|
public KeyList<string, ProtocolInstance> Protocols { get; } = new KeyList<string, ProtocolInstance>();
|
||||||
|
|
||||||
private Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
|
private Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
|
||||||
|
|
||||||
|
|
||||||
|
public void RegisterAuthenticationProvider(IAuthenticationProvider provider)
|
||||||
|
{
|
||||||
|
RegisterAuthenticationProvider(provider.DefaultName, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterAuthenticationProvider(string name, IAuthenticationProvider provider)
|
||||||
|
{
|
||||||
|
_authenticationProviders.Add(name, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void RegisterPermissionsManager(IPermissionsManager manager)
|
||||||
|
{
|
||||||
|
_permissionsManagers.Add(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAuthenticationProvider GetAuthenticationProvider(string name)
|
||||||
|
{
|
||||||
|
if (_authenticationProviders.ContainsKey(name))
|
||||||
|
return _authenticationProviders[name];
|
||||||
|
throw new Exception("Authentication provider not found.");
|
||||||
|
}
|
||||||
|
|
||||||
public Warehouse()
|
public Warehouse()
|
||||||
{
|
{
|
||||||
Protocols.Add("EP",
|
Protocols.Add("EP",
|
||||||
async (name, attributes)
|
async (name, context)
|
||||||
=> await New<EpConnection>(name, null, attributes));
|
=> await New<EpConnection>(name, context));
|
||||||
|
|
||||||
new TypeDef(typeof(EpAuthPacketIAuthHeader), this);
|
//new LocalTypeDef(typeof(EpAuthPacketIAuthHeader), this);
|
||||||
|
//new LocalTypeDef(typeof(EpAuthPacketIAuthDestination), this);
|
||||||
new TypeDef(typeof(EpAuthPacketIAuthDestination), this);
|
//new LocalTypeDef(typeof(EpAuthPacketIAuthFormat), this);
|
||||||
new TypeDef(typeof(EpAuthPacketIAuthFormat), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,13 +141,13 @@ public class Warehouse
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IStore GetStore(string name)
|
public IStore GetStore(string name)
|
||||||
{
|
{
|
||||||
foreach (var s in stores)
|
foreach (var s in _stores)
|
||||||
if (s.Key.Instance.Name == name)
|
if (s.Key.Instance.Name == name)
|
||||||
return s.Key;
|
return s.Key;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WeakReference<IResource>[] Resources => resources.Values.ToArray();
|
public WeakReference<IResource>[] Resources => _resources.Values.ToArray();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a resource by instance Id.
|
/// Get a resource by instance Id.
|
||||||
@@ -117,10 +156,10 @@ public class Warehouse
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public AsyncReply<IResource> GetById(uint id)
|
public AsyncReply<IResource> GetById(uint id)
|
||||||
{
|
{
|
||||||
if (resources.ContainsKey(id))
|
if (_resources.ContainsKey(id))
|
||||||
{
|
{
|
||||||
IResource r;
|
IResource r;
|
||||||
if (resources[id].TryGetTarget(out r))
|
if (_resources[id].TryGetTarget(out r))
|
||||||
return new AsyncReply<IResource>(r);
|
return new AsyncReply<IResource>(r);
|
||||||
else
|
else
|
||||||
return new AsyncReply<IResource>(null);
|
return new AsyncReply<IResource>(null);
|
||||||
@@ -129,33 +168,33 @@ public class Warehouse
|
|||||||
return new AsyncReply<IResource>(null);
|
return new AsyncReply<IResource>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadGenerated()
|
//void LoadGenerated()
|
||||||
{
|
//{
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
// foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
{
|
// {
|
||||||
var generatedType = assembly.GetType("Esiur.Generated");
|
// var generatedType = assembly.GetType("Esiur.Generated");
|
||||||
if (generatedType != null)
|
// if (generatedType != null)
|
||||||
{
|
// {
|
||||||
var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null);
|
// var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null);
|
||||||
foreach (var t in resourceTypes)
|
// foreach (var t in resourceTypes)
|
||||||
{
|
// {
|
||||||
RegisterTypeDef(new TypeDef(t));
|
// RegisterTypeDef(new TypeDef(t));
|
||||||
}
|
// }
|
||||||
|
|
||||||
var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null);
|
// var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null);
|
||||||
foreach (var t in recordTypes)
|
// foreach (var t in recordTypes)
|
||||||
{
|
// {
|
||||||
RegisterTypeDef(new TypeDef(t));
|
// RegisterTypeDef(new TypeDef(t));
|
||||||
}
|
// }
|
||||||
|
|
||||||
var enumsTypes = (Type[])generatedType.GetProperty("Enums").GetValue(null);
|
// var enumsTypes = (Type[])generatedType.GetProperty("Enums").GetValue(null);
|
||||||
foreach (var t in enumsTypes)
|
// foreach (var t in enumsTypes)
|
||||||
{
|
// {
|
||||||
RegisterTypeDef(new TypeDef(t));
|
// RegisterTypeDef(new TypeDef(t));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Open the warehouse.
|
/// Open the warehouse.
|
||||||
@@ -164,16 +203,16 @@ public class Warehouse
|
|||||||
/// <returns>True, if no problem occurred.</returns>
|
/// <returns>True, if no problem occurred.</returns>
|
||||||
public async AsyncReply<bool> Open()
|
public async AsyncReply<bool> Open()
|
||||||
{
|
{
|
||||||
if (warehouseIsOpen)
|
if (_warehouseIsOpen)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Load generated models
|
// Load generated models
|
||||||
LoadGenerated();
|
//LoadGenerated();
|
||||||
|
|
||||||
|
|
||||||
warehouseIsOpen = true;
|
_warehouseIsOpen = true;
|
||||||
|
|
||||||
var resSnap = resources.Select(x =>
|
var resSnap = _resources.Select(x =>
|
||||||
{
|
{
|
||||||
IResource r;
|
IResource r;
|
||||||
if (x.Value.TryGetTarget(out r))
|
if (x.Value.TryGetTarget(out r))
|
||||||
@@ -222,7 +261,7 @@ public class Warehouse
|
|||||||
|
|
||||||
var bag = new AsyncBag<bool>();
|
var bag = new AsyncBag<bool>();
|
||||||
|
|
||||||
foreach (var resource in resources.Values)
|
foreach (var resource in _resources.Values)
|
||||||
{
|
{
|
||||||
IResource r;
|
IResource r;
|
||||||
if (resource.TryGetTarget(out r))
|
if (resource.TryGetTarget(out r))
|
||||||
@@ -233,11 +272,11 @@ public class Warehouse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var store in stores)
|
foreach (var store in _stores)
|
||||||
bag.Add(store.Key.Trigger(ResourceTrigger.Terminate));
|
bag.Add(store.Key.Trigger(ResourceTrigger.Terminate));
|
||||||
|
|
||||||
|
|
||||||
foreach (var resource in resources.Values)
|
foreach (var resource in _resources.Values)
|
||||||
{
|
{
|
||||||
IResource r;
|
IResource r;
|
||||||
if (resource.TryGetTarget(out r))
|
if (resource.TryGetTarget(out r))
|
||||||
@@ -248,7 +287,7 @@ public class Warehouse
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var store in stores)
|
foreach (var store in _stores)
|
||||||
bag.Add(store.Key.Trigger(ResourceTrigger.SystemTerminated));
|
bag.Add(store.Key.Trigger(ResourceTrigger.SystemTerminated));
|
||||||
|
|
||||||
bag.Seal();
|
bag.Seal();
|
||||||
@@ -274,7 +313,7 @@ public class Warehouse
|
|||||||
{
|
{
|
||||||
var p = path.Trim().TrimStart('/').Split('/');
|
var p = path.Trim().TrimStart('/').Split('/');
|
||||||
|
|
||||||
foreach (var store in stores.Keys)
|
foreach (var store in _stores.Keys)
|
||||||
{
|
{
|
||||||
if (p[0] == store.Instance.Name)
|
if (p[0] == store.Instance.Name)
|
||||||
{
|
{
|
||||||
@@ -298,7 +337,7 @@ public class Warehouse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
/// <returns>Resource instance.</returns>
|
/// <returns>Resource instance.</returns>
|
||||||
public async AsyncReply<T> Get<T>(string path, object attributes = null, IResource parent = null, IPermissionsManager manager = null)
|
public async AsyncReply<T> Get<T>(string path, ResourceContext resourceContext = null)
|
||||||
where T : IResource
|
where T : IResource
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -309,11 +348,11 @@ public class Warehouse
|
|||||||
|
|
||||||
if (Protocols.ContainsKey(url[1]))
|
if (Protocols.ContainsKey(url[1]))
|
||||||
{
|
{
|
||||||
if (!warehouseIsOpen)
|
if (!_warehouseIsOpen)
|
||||||
await Open();
|
await Open();
|
||||||
|
|
||||||
var handler = Protocols[url[1]];
|
var handler = Protocols[url[1]];
|
||||||
var store = await handler(url[2], attributes);
|
var store = await handler(url[2], resourceContext);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -346,7 +385,7 @@ public class Warehouse
|
|||||||
/// <param name="resource">Resource instance.</param>
|
/// <param name="resource">Resource instance.</param>
|
||||||
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
|
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
|
||||||
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
|
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
|
||||||
public async AsyncReply<T> Put<T>(string path, T resource, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource
|
public async AsyncReply<T> Put<T>(string path, T resource, ResourceContext resourceContext = null) where T : IResource
|
||||||
{
|
{
|
||||||
if (resource.Instance != null)
|
if (resource.Instance != null)
|
||||||
throw new Exception("Resource already initialized.");
|
throw new Exception("Resource already initialized.");
|
||||||
@@ -385,18 +424,17 @@ public class Warehouse
|
|||||||
|
|
||||||
var resourceReference = new WeakReference<IResource>(resource);
|
var resourceReference = new WeakReference<IResource>(resource);
|
||||||
|
|
||||||
resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, age);
|
var resourceId = (uint)Interlocked.Increment(ref _resourceCounter);
|
||||||
|
|
||||||
if (attributes != null)
|
resource.Instance = new Instance(this, resourceId, instanceName, resource, store, resourceContext?.Age ?? 0);
|
||||||
if (attributes is Map<string, object> attrs)
|
|
||||||
resource.Instance.SetAttributes(attrs);
|
if (resourceContext?.Attributes != null)
|
||||||
else
|
resource.Instance.SetAttributes(resourceContext.Attributes);
|
||||||
resource.Instance.SetAttributes(Map<string, object>.FromObject(attributes));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (resource is IStore)
|
if (resource is IStore)
|
||||||
stores.TryAdd(resource as IStore, new List<WeakReference<IResource>>());
|
_stores.TryAdd(resource as IStore, new List<WeakReference<IResource>>());
|
||||||
else if ((IResource)resource != store)
|
else if ((IResource)resource != store)
|
||||||
{
|
{
|
||||||
if (!await store.Put(resource, string.Join("/", location.Skip(1).ToArray())))
|
if (!await store.Put(resource, string.Join("/", location.Skip(1).ToArray())))
|
||||||
@@ -406,9 +444,9 @@ public class Warehouse
|
|||||||
var t = resource.GetType();
|
var t = resource.GetType();
|
||||||
Global.Counters["T-" + t.Namespace + "." + t.Name]++;
|
Global.Counters["T-" + t.Namespace + "." + t.Name]++;
|
||||||
|
|
||||||
resources.TryAdd(resource.Instance.Id, resourceReference);
|
_resources.TryAdd(resource.Instance.Id, resourceReference);
|
||||||
|
|
||||||
if (warehouseIsOpen)
|
if (_warehouseIsOpen)
|
||||||
{
|
{
|
||||||
await resource.Trigger(ResourceTrigger.Initialize);
|
await resource.Trigger(ResourceTrigger.Initialize);
|
||||||
if (resource is IStore)
|
if (resource is IStore)
|
||||||
@@ -429,31 +467,53 @@ public class Warehouse
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Create<T>(object properties = null)
|
public T Create<T>(Map<string, object> properties = null)
|
||||||
{
|
{
|
||||||
return (T)Create(typeof(T), properties);
|
return (T)Create(typeof(T), properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IResource Create(Type type, object properties = null)
|
public IResource CreateFromIndexedProperties(Type type, Map<byte, object> properties)
|
||||||
{
|
{
|
||||||
type = ResourceProxy.GetProxy(type);
|
type = ResourceProxy.GetProxy(type);
|
||||||
|
|
||||||
var res = Activator.CreateInstance(type) as IResource;
|
var res = Activator.CreateInstance(type) as IResource;
|
||||||
|
|
||||||
|
|
||||||
if (properties != null)
|
if (properties != null)
|
||||||
{
|
{
|
||||||
if (properties is Map<byte, object> map)
|
var typeDef = GetLocalTypeDefByType(type);
|
||||||
|
foreach (var p in properties)
|
||||||
{
|
{
|
||||||
var typeDef = GetTypeDefByType(type);
|
var pi = typeDef.GetPropertyDefByIndex(p.Key).PropertyInfo;
|
||||||
foreach (var kvp in map)
|
|
||||||
typeDef.GetPropertyDefByIndex(kvp.Key).PropertyInfo.SetValue(res, kvp.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var ps = Map<string, object>.FromObject(properties);
|
|
||||||
|
|
||||||
foreach (var p in ps)
|
if (pi != null)
|
||||||
|
{
|
||||||
|
if (pi.CanWrite)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pi.SetValue(res, p.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Global.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResource Create(Type type, Map<string, object> properties)
|
||||||
|
{
|
||||||
|
type = ResourceProxy.GetProxy(type);
|
||||||
|
var res = Activator.CreateInstance(type) as IResource;
|
||||||
|
|
||||||
|
if (properties != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var p in properties)
|
||||||
{
|
{
|
||||||
var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
||||||
if (pi != null)
|
if (pi != null)
|
||||||
@@ -487,63 +547,133 @@ public class Warehouse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async AsyncReply<IResource> New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null)
|
public async AsyncReply<IResource> New(Type type, string path, ResourceContext resourceContext)
|
||||||
{
|
{
|
||||||
var res = Create(type, properties);
|
var res = Create(type, resourceContext?.Properties);
|
||||||
return await Put(path, res, 0, manager, attributes);
|
return await Put(path, res, resourceContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async AsyncReply<T> New<T>(string path, IPermissionsManager manager = null, object attributes = null, object properties = null)
|
public async AsyncReply<T> New<T>(string path, ResourceContext resourceContext = null)
|
||||||
where T : IResource
|
where T : IResource
|
||||||
{
|
{
|
||||||
return (T)(await New(typeof(T), path, manager, attributes, properties));
|
return (T)(await New(typeof(T), path, resourceContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void IsProxyType(Type type)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterProxyType(Type type)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Put a resource schema in the schemas warehouse.
|
/// Register TypeDef.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="typeDef">Resource type definition.</param>
|
/// <param name="typeDef">Resource type definition.</param>
|
||||||
public void RegisterTypeDef(TypeDef typeDef)
|
public uint RegisterLocalTypeDef(LocalTypeDef typeDef)
|
||||||
{
|
{
|
||||||
lock (typeDefsLock)
|
lock (_typeDefsLock)
|
||||||
{
|
{
|
||||||
if (typeDefs[typeDef.Kind].ContainsKey(typeDef.Id))
|
//if (_localTypeDefs[typeDef.Kind].ContainsKey(typeDef.Id))
|
||||||
throw new Exception($"TypeDef with same class Id already exists. {typeDefs[typeDef.Kind][typeDef.Id].Name} -> {typeDef.Name}");
|
if (_localTypeDefs.ContainsKey(typeDef.Id))
|
||||||
|
throw new Exception($"TypeDef with same class Id already exists. {_localTypeDefs[typeDef.Id].Name} -> {typeDef.Name}");
|
||||||
|
//throw new Exception($"TypeDef with same class Id already exists. {_localTypeDefs[typeDef.Kind][typeDef.Id].Name} -> {typeDef.Name}");
|
||||||
|
|
||||||
typeDefs[typeDef.Kind][typeDef.Id] = typeDef;
|
var typeDefId = (uint)Interlocked.Increment(ref _typeDefsCounter);
|
||||||
|
|
||||||
|
typeDef.Id = typeDefId;
|
||||||
|
|
||||||
|
//_localTypeDefs[typeDef.Kind][typeDef.Id] = typeDef;
|
||||||
|
_localTypeDefs[typeDef.Id] = typeDef;
|
||||||
|
|
||||||
|
return typeDefId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryRegisterTypeDef(TypeDef typeDef)
|
public bool TryRegisterLocalTypeDef(LocalTypeDef typeDef)
|
||||||
{
|
{
|
||||||
lock (typeDefsLock)
|
lock (_typeDefsLock)
|
||||||
{
|
{
|
||||||
if (typeDefs[typeDef.Kind].ContainsKey(typeDef.Id))
|
if (_localTypeDefs.ContainsKey(typeDef.Id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
typeDefs[typeDef.Kind][typeDef.Id] = typeDef;
|
var typeDefId = (uint)Interlocked.Increment(ref _typeDefsCounter);
|
||||||
|
typeDef.Id = typeDefId;
|
||||||
|
|
||||||
|
_localTypeDefs[typeDef.Id] = typeDef;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryRegisterRemoteTypeDef(string domain, RemoteTypeDef typeDef)
|
||||||
|
{
|
||||||
|
lock (_typeDefsLock)
|
||||||
|
{
|
||||||
|
if (!_remoteTypeDefs.ContainsKey(domain))
|
||||||
|
{
|
||||||
|
_remoteTypeDefs.Add(domain, new KeyList<ulong, RemoteTypeDef>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_remoteTypeDefs[domain].ContainsKey(typeDef.Id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// @TODO: Try to find a proxy type for the remote type def, if not found, create a new proxy type and register it in the warehouse.
|
||||||
|
_remoteTypeDefs[domain][typeDef.Id] = typeDef;
|
||||||
|
|
||||||
|
var localTypeDefId = (uint)Interlocked.Increment(ref _typeDefsCounter);
|
||||||
|
typeDef.LocalTypeDefId = localTypeDefId;
|
||||||
|
_localTypeDefs[localTypeDefId] = typeDef;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//public TypeDef FindTypeDefByType(Type type)
|
||||||
|
//{
|
||||||
|
// var remote = type.GetCustomAttribute<RemoteAttribute>();
|
||||||
|
|
||||||
|
// if (remote != null)
|
||||||
|
// {
|
||||||
|
// return GetRemoteTypeDefByName(remote.Domain, remote.FullName);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return GetLocalTypeDefByType(type);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public TypeDef FindTypeDefByTypeDefId(TypeDefId typeDefId, string domain)
|
||||||
|
//{
|
||||||
|
// if (typeDefId.Remote)
|
||||||
|
// {
|
||||||
|
// return GetRemoteTypeDefById(domain, typeDefId.Value);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return GetLocalTypeDefById(typeDefId.Value);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a TypeDef by type from the warehouse. If not in the warehouse, a new TypeDef is created and added to the warehouse.
|
/// Get a TypeDef by type from the warehouse. If not in the warehouse, a new TypeDef is created and added to the warehouse.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">.Net type.</param>
|
/// <param name="type">.Net type.</param>
|
||||||
/// <returns>Resource TypeDef.</returns>
|
/// <returns>Resource TypeDef.</returns>
|
||||||
public TypeDef GetTypeDefByType(Type type)
|
public TypeDef GetLocalTypeDefByType(Type type)
|
||||||
{
|
{
|
||||||
|
//if (!(type.IsClass || type.IsEnum))
|
||||||
if (!(type.IsClass || type.IsEnum))
|
// return null;
|
||||||
return null;
|
|
||||||
|
|
||||||
|
|
||||||
var baseType = ResourceProxy.GetBaseType(type);
|
var baseType = ResourceProxy.GetBaseType(type);
|
||||||
|
|
||||||
@@ -561,16 +691,33 @@ public class Warehouse
|
|||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
lock (typeDefsLock)
|
lock (_typeDefsLock)
|
||||||
{
|
{
|
||||||
var typeDef = typeDefs[typeDefKind].Values.FirstOrDefault(x => x.DefinedType == baseType);
|
//var typeDef = _localTypeDefs.Values.FirstOrDefault(x => x is LocalTypeDef ltd
|
||||||
if (typeDef != null)
|
// && ltd.DefinedType == baseType);
|
||||||
return typeDef;
|
|
||||||
|
foreach (var td in _localTypeDefs.Values)
|
||||||
|
{
|
||||||
|
if (td is LocalTypeDef ltd && ltd.DefinedType == baseType)
|
||||||
|
{
|
||||||
|
return td;
|
||||||
|
}
|
||||||
|
else if (td is RemoteTypeDef rtd && rtd.ProxyType == baseType)
|
||||||
|
{
|
||||||
|
return td;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (typeDef != null)
|
||||||
|
// return typeDef;
|
||||||
|
|
||||||
// create new TypeDef for type
|
// create new TypeDef for type
|
||||||
typeDef = new TypeDef(baseType, this);
|
|
||||||
TypeDef.GetDependencies(typeDef, this);
|
//Console.WriteLine($"Creating {baseType.Name}");
|
||||||
return typeDef;
|
|
||||||
|
var ntd = new LocalTypeDef(baseType, this);
|
||||||
|
//LocalTypeDef.GetDependencies(ntd, this);
|
||||||
|
return ntd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,28 +726,35 @@ public class Warehouse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="typeId">typeId.</param>
|
/// <param name="typeId">typeId.</param>
|
||||||
/// <returns>TypeDef.</returns>
|
/// <returns>TypeDef.</returns>
|
||||||
public TypeDef GetTypeDefById(Uuid typeId, TypeDefKind? typeDefKind = null)
|
public TypeDef GetLocalTypeDefById(ulong typeId)
|
||||||
{
|
{
|
||||||
if (typeDefKind == null)
|
return _localTypeDefs[typeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public RemoteTypeDef GetRemoteTypeDefById(string domain, ulong typeId)
|
||||||
{
|
{
|
||||||
// look into resources
|
if (string.IsNullOrEmpty(domain) || !_remoteTypeDefs.ContainsKey(domain))
|
||||||
var typeDef = typeDefs[TypeDefKind.Resource][typeId];
|
return null;
|
||||||
if (typeDef != null)
|
return _remoteTypeDefs[domain][typeId];
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
// look into records
|
|
||||||
typeDef = typeDefs[TypeDefKind.Record][typeId];
|
|
||||||
if (typeDef != null)
|
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
// look into enums
|
|
||||||
typeDef = typeDefs[TypeDefKind.Enum][typeId];
|
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return typeDefs[typeDefKind.Value][typeId];
|
|
||||||
|
|
||||||
|
public TypeDef GetRemoteTypeDefByName(string domain, string typeName, TypeDefKind? typeDefKind = null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(domain) || !_remoteTypeDefs.ContainsKey(domain))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return _remoteTypeDefs[domain].Values.FirstOrDefault(x => x.Name == typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeDef GetRemoteTypeDefByType(Type type)
|
||||||
|
{
|
||||||
|
var remoteAttr = type.GetCustomAttribute<RemoteAttribute>();
|
||||||
|
|
||||||
|
if (remoteAttr == null) return null;
|
||||||
|
|
||||||
|
return GetRemoteTypeDefByName(remoteAttr.Domain, remoteAttr.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -608,42 +762,20 @@ public class Warehouse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="typeName">Class full name.</param>
|
/// <param name="typeName">Class full name.</param>
|
||||||
/// <returns>TypeDef.</returns>
|
/// <returns>TypeDef.</returns>
|
||||||
public TypeDef GetTypeDefByName(string typeName, TypeDefKind? typeDefKind = null)
|
public TypeDef GetLocalTypeDefByName(string typeName)
|
||||||
{
|
{
|
||||||
if (typeDefKind == null)
|
return _localTypeDefs.Values.FirstOrDefault(x => x.Name == typeName);
|
||||||
{
|
|
||||||
// look into resources
|
|
||||||
var typeDef = typeDefs[TypeDefKind.Resource].Values.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
if (typeDef != null)
|
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
// look into records
|
|
||||||
typeDef = typeDefs[TypeDefKind.Record].Values.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
if (typeDef != null)
|
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
// look into enums
|
|
||||||
typeDef = typeDefs[TypeDefKind.Enum].Values.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
return typeDef;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return typeDefs[typeDefKind.Value].Values.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(IResource resource)
|
public bool Remove(IResource resource)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (resource.Instance == null)
|
if (resource.Instance == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
WeakReference<IResource> resourceReference;
|
WeakReference<IResource> resourceReference;
|
||||||
|
|
||||||
if (resources.ContainsKey(resource.Instance.Id))
|
if (_resources.ContainsKey(resource.Instance.Id))
|
||||||
resources.TryRemove(resource.Instance.Id, out resourceReference);
|
_resources.TryRemove(resource.Instance.Id, out resourceReference);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -651,7 +783,7 @@ public class Warehouse
|
|||||||
if (resource != resource.Instance.Store)
|
if (resource != resource.Instance.Store)
|
||||||
{
|
{
|
||||||
List<WeakReference<IResource>> list;
|
List<WeakReference<IResource>> list;
|
||||||
if (stores.TryGetValue(resource.Instance.Store, out list))
|
if (_stores.TryGetValue(resource.Instance.Store, out list))
|
||||||
{
|
{
|
||||||
|
|
||||||
lock (((ICollection)list).SyncRoot)
|
lock (((ICollection)list).SyncRoot)
|
||||||
@@ -665,7 +797,7 @@ public class Warehouse
|
|||||||
|
|
||||||
List<WeakReference<IResource>> toBeRemoved;
|
List<WeakReference<IResource>> toBeRemoved;
|
||||||
|
|
||||||
stores.TryRemove(store, out toBeRemoved);
|
_stores.TryRemove(store, out toBeRemoved);
|
||||||
|
|
||||||
|
|
||||||
foreach (var o in toBeRemoved)
|
foreach (var o in toBeRemoved)
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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.Security.Authority;
|
|
||||||
|
|
||||||
public class Authentication
|
|
||||||
{
|
|
||||||
AuthenticationMode type;
|
|
||||||
|
|
||||||
public AuthenticationMethod Method { get; set; }
|
|
||||||
|
|
||||||
public ulong TokenIndex { get; set; }
|
|
||||||
|
|
||||||
public string Username { get; set; }
|
|
||||||
public Certificate Certificate { get; set; }
|
|
||||||
public string Domain { get; set; }
|
|
||||||
|
|
||||||
public string FullName => Username + "@" + Domain;
|
|
||||||
|
|
||||||
public Source Source { get; } = new Source();
|
|
||||||
|
|
||||||
public AuthenticationState State
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationMode Type
|
|
||||||
{
|
|
||||||
get => type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Authentication(AuthenticationMode type)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,16 +6,14 @@ namespace Esiur.Security.Authority
|
|||||||
{
|
{
|
||||||
public class AuthenticationContext
|
public class AuthenticationContext
|
||||||
{
|
{
|
||||||
public AuthenticationMode Mode { get; }
|
public AuthenticationDirection Direction { get; set; }
|
||||||
|
public AuthenticationMode Mode { get; set; }
|
||||||
|
|
||||||
public string? LocalDomain { get; }
|
public string Domain { get; set; }
|
||||||
public string? RemoteDomain { get; }
|
public string? InitiatorIdentity { get; set; }
|
||||||
|
public string? ResponderIdentity { get; set; }
|
||||||
public string? LocalHost { get; }
|
public AuthenticationMaterial[] Materials { get; set; }
|
||||||
public string? RemoteHost { get; }
|
|
||||||
|
|
||||||
//public AuthenticationComponentContext LocalToRemote { get; } = new();
|
|
||||||
//public AuthenticationComponentContext RemoteToLocal { get; } = new();
|
|
||||||
|
|
||||||
|
public string? HostName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Esiur.Security.Authority
|
namespace Esiur.Security.Authority
|
||||||
{
|
{
|
||||||
public interface IAuthenticationResponder
|
public enum AuthenticationDirection
|
||||||
{
|
{
|
||||||
public AuthenticationResult Process(Session session);
|
Initiator,
|
||||||
|
Responder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority
|
||||||
|
{
|
||||||
|
internal class AuthenticationHandler
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority
|
||||||
|
{
|
||||||
|
public class AuthenticationMaterial
|
||||||
|
{
|
||||||
|
public AuthenticationMaterialType Type { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority
|
||||||
|
{
|
||||||
|
public enum AuthenticationMaterialType: byte
|
||||||
|
{
|
||||||
|
Secret,
|
||||||
|
Key,
|
||||||
|
Identity,
|
||||||
|
Data,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,20 +8,24 @@ namespace Esiur.Security.Authority
|
|||||||
public class AuthenticationResult
|
public class AuthenticationResult
|
||||||
{
|
{
|
||||||
public AuthenticationRuling Ruling { get; internal set; }
|
public AuthenticationRuling Ruling { get; internal set; }
|
||||||
public string Identity { get; internal set; }
|
public string LocalIdentity { get; internal set; }
|
||||||
|
public string RemoteIdentity { get; internal set; }
|
||||||
|
|
||||||
public object HandshakePayload { get; internal set; }
|
//public object HandshakePayload { get; internal set; }
|
||||||
|
|
||||||
public byte[] SessionKey { get; internal set; }
|
public byte[] SessionKey { get; internal set; }
|
||||||
|
|
||||||
public ExceptionCode? ExceptionCode { get; internal set; }
|
public ExceptionCode? ExceptionCode { get; internal set; }
|
||||||
public string ExceptionMessage { get; internal set; }
|
public string ExceptionMessage { get; internal set; }
|
||||||
|
|
||||||
public AuthenticationResult(AuthenticationRuling ruling, string identity, object handshakePayload, byte[] sessionKey)
|
public object AuthenticationData { get; internal set; }
|
||||||
|
|
||||||
|
public AuthenticationResult(AuthenticationRuling ruling, object authenticationData, string localIdentity = null, string remoteIdentity = null, byte[] sessionKey = null)
|
||||||
{
|
{
|
||||||
Ruling = ruling;
|
Ruling = ruling;
|
||||||
Identity = identity;
|
LocalIdentity = localIdentity;
|
||||||
HandshakePayload = handshakePayload;
|
RemoteIdentity = remoteIdentity;
|
||||||
|
AuthenticationData = authenticationData;
|
||||||
SessionKey = sessionKey;
|
SessionKey = sessionKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ namespace Esiur.Security.Authority
|
|||||||
public interface IAuthenticationHandler
|
public interface IAuthenticationHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
public AuthenticationMode Mode { get; }
|
public string Protocol { get; }
|
||||||
public AuthenticationResult Initialize(Session session, object authenticationData);
|
//public AuthenticationMode Mode { get; }
|
||||||
|
//public AuthenticationResult Initialize(object authData);
|
||||||
|
|
||||||
public AuthenticationResult Process(object authenticationData);
|
public AuthenticationResult Process(object authData);
|
||||||
|
|
||||||
public void Terminate(Session session);
|
//public AuthenticationResult? Result { get; }
|
||||||
|
|
||||||
public void Update(Session session, object authData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Esiur.Security.Authority
|
|
||||||
{
|
|
||||||
public interface IAuthenticationInitiator
|
|
||||||
{
|
|
||||||
public AuthenticationResult Initiate(Session session);
|
|
||||||
|
|
||||||
public AuthenticationResult Process(object handshakePayload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//using System;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
//using System.Text;
|
|
||||||
|
|
||||||
//namespace Esiur.Security.Authority
|
|
||||||
//{
|
|
||||||
// public interface IAuthenticationMethodProvider
|
|
||||||
// {
|
|
||||||
// string Method { get; }
|
|
||||||
|
|
||||||
// bool CanHandle(AuthenticationCreationContext context);
|
|
||||||
|
|
||||||
// IAuthenticator CreateAuthenticator(AuthenticationCreationContext context);
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority
|
||||||
|
{
|
||||||
|
public interface IAuthenticationProvider
|
||||||
|
{
|
||||||
|
public IAuthenticationHandler
|
||||||
|
CreateAuthenticationHandler(AuthenticationContext context);
|
||||||
|
|
||||||
|
public string DefaultName { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Esiur.Security.Authority
|
|
||||||
{
|
|
||||||
public sealed class InitiatorAuthenticationContext
|
|
||||||
{
|
|
||||||
public string LocalIdentity { get; } = string.Empty;
|
|
||||||
public string RemoteIdentity { get; } = string.Empty;
|
|
||||||
|
|
||||||
public string? RemoteDomain { get; }
|
|
||||||
public string? LocalDomain { get; }
|
|
||||||
|
|
||||||
public string? RemoteIpAddress { get; }
|
|
||||||
|
|
||||||
public AuthenticationMode Mode { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority
|
||||||
|
{
|
||||||
|
internal class PpapAuthenticationProvider : IAuthenticationProvider
|
||||||
|
{
|
||||||
|
public string DefaultName => "PPAP";
|
||||||
|
|
||||||
|
public IAuthenticationHandler CreateAuthenticationHandler(AuthenticationContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,606 @@
|
|||||||
|
using Esiur.Misc;
|
||||||
|
using Esiur.Security.Permissions;
|
||||||
|
using Org.BouncyCastle.Crypto.Digests;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Esiur.Data;
|
||||||
|
using Esiur.Data.Types;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority.Providers
|
||||||
|
{
|
||||||
|
internal class PasswordAuthenticationHandler : IAuthenticationHandler
|
||||||
|
{
|
||||||
|
public string Protocol => "hash";
|
||||||
|
|
||||||
|
byte[] localNonce, remoteNonce;
|
||||||
|
byte[] localSalt, remoteSalt;
|
||||||
|
|
||||||
|
string initiatorIdentity, responderIdentity;
|
||||||
|
|
||||||
|
byte[] initiatorPassword, responderPassword;
|
||||||
|
|
||||||
|
string hostName, domain;
|
||||||
|
|
||||||
|
int step = 0;
|
||||||
|
|
||||||
|
AuthenticationMode mode;
|
||||||
|
AuthenticationDirection direction;
|
||||||
|
|
||||||
|
PasswordAuthenticationProvider provider;
|
||||||
|
|
||||||
|
|
||||||
|
public byte[] ComputeSha3(byte[] data, int bitLength = 256)
|
||||||
|
{
|
||||||
|
// 1. Initialize the digest (supports 224, 256, 384, 512)
|
||||||
|
var digest = new Sha3Digest(bitLength);
|
||||||
|
|
||||||
|
// 3. Update the digest with data
|
||||||
|
digest.BlockUpdate(data, 0, data.Length);
|
||||||
|
|
||||||
|
// 4. Retrieve the final hash
|
||||||
|
byte[] result = new byte[digest.GetDigestSize()];
|
||||||
|
digest.DoFinal(result, 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationResult Process(object authData)
|
||||||
|
{
|
||||||
|
var remoteAuthData = (object[])authData;
|
||||||
|
var localAuthData = new List<object>();
|
||||||
|
|
||||||
|
if (direction == AuthenticationDirection.Initiator)
|
||||||
|
{
|
||||||
|
if (mode == AuthenticationMode.None)
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.InitializerIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
// step 0: send local nonce and initiator identity.
|
||||||
|
if (initiatorIdentity == null)
|
||||||
|
(initiatorIdentity, initiatorPassword) = provider.GetSelfIdentityAndCredential(domain, hostName);
|
||||||
|
else
|
||||||
|
initiatorPassword = provider.GetSelfCredential(initiatorIdentity, domain, hostName);
|
||||||
|
|
||||||
|
if (initiatorPassword == null || initiatorIdentity == null)
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
|
||||||
|
// send local nonce and initiator identity
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
localAuthData.Add(initiatorIdentity);
|
||||||
|
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress, localAuthData);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect remote nonce, salt and challenge.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
remoteSalt = (byte[])remoteAuthData[1];
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[2];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make salted hash of password.
|
||||||
|
var hashedPassword = ComputeSha3(initiatorPassword.Concat(remoteSalt).ToArray());
|
||||||
|
|
||||||
|
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(hashedPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
if (!remoteChallenge.SequenceEqual(expectedRemoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make hash challenge response.
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(hashedPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
step = -1;
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// initiator identity + initiator password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(initiatorIdentity.ToBytes()
|
||||||
|
.Concat(hashedPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, localAuthData, initiatorIdentity, null, sessionKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.ResponderIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
// just send local nonce.
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress, localAuthData);
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect responder identity and nonce.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
responderIdentity = (string)remoteAuthData[1];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if responder identity is valid and get password.
|
||||||
|
(localSalt, responderPassword) = provider.GetHostedAccountCredential(responderIdentity, domain);
|
||||||
|
|
||||||
|
if (responderPassword == null)
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make hash challenge response.
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(responderPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
// send localSalt and challenge
|
||||||
|
localAuthData.Add(localSalt);
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
step = 2;
|
||||||
|
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress, localAuthData);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step == 2)
|
||||||
|
{
|
||||||
|
// expect remote challenge.
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[0];
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(responderPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
if (!remoteChallenge.SequenceEqual(expectedRemoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// responder identity + responder hashed password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(responderIdentity.ToBytes()
|
||||||
|
.Concat(responderPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, null, initiatorIdentity, responderIdentity, sessionKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.DualIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
// step 0: send local nonce and initiator identity.
|
||||||
|
if (initiatorIdentity == null)
|
||||||
|
(initiatorIdentity, initiatorPassword) = provider.GetSelfIdentityAndCredential(domain, hostName);
|
||||||
|
else
|
||||||
|
initiatorPassword = provider.GetSelfCredential(initiatorIdentity, domain, hostName);
|
||||||
|
|
||||||
|
if (initiatorPassword == null || initiatorIdentity == null)
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
localAuthData.Add(initiatorIdentity);
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress, localAuthData);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect responder identity, nonce and salt.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
responderIdentity = (string)remoteAuthData[1];
|
||||||
|
remoteSalt = (byte[])remoteAuthData[2];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if responder identity is valid and get password.
|
||||||
|
(localSalt, responderPassword) = provider.GetHostedAccountCredential(responderIdentity, domain);
|
||||||
|
|
||||||
|
if (responderPassword == null)
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make salted hash of password.
|
||||||
|
var hashedPassword = ComputeSha3(initiatorPassword.Concat(remoteSalt).ToArray());
|
||||||
|
|
||||||
|
// make hash challenge response.
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(hashedPassword)
|
||||||
|
.Concat(responderPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// send localSalt and challenge
|
||||||
|
localAuthData.Add(localSalt);
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
step = 2;
|
||||||
|
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress, localAuthData);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step == 2)
|
||||||
|
{
|
||||||
|
// expect remote challenge.
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[0];
|
||||||
|
|
||||||
|
// make salted hash of password.
|
||||||
|
var hashedPassword = ComputeSha3(initiatorPassword.Concat(remoteSalt).ToArray());
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(hashedPassword)
|
||||||
|
.Concat(responderPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
if (!remoteChallenge.SequenceEqual(expectedRemoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// responder identity + responder password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(initiatorIdentity.ToBytes()
|
||||||
|
.Concat(responderIdentity.ToBytes())
|
||||||
|
.Concat(hashedPassword)
|
||||||
|
.Concat(responderPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, null, initiatorIdentity, responderIdentity, sessionKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (direction == AuthenticationDirection.Responder)
|
||||||
|
{
|
||||||
|
if (mode == AuthenticationMode.None)
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.InitializerIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
if (remoteAuthData.Length < 2)
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
|
||||||
|
// step 0: expect remote nonce and initiator identity.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
initiatorIdentity = (string)remoteAuthData[1];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
// @TODO: We can change our localNonce then send it
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get initiator password from provider.
|
||||||
|
(localSalt, initiatorPassword) = provider.GetHostedAccountCredential(initiatorIdentity, domain);
|
||||||
|
|
||||||
|
// account not found or no password for this account.
|
||||||
|
if (initiatorPassword == null || initiatorIdentity == null)
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(initiatorPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// send local nonce, salt and challenge.
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
localAuthData.Add(localSalt);
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
|
||||||
|
step = 1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress,
|
||||||
|
localAuthData);
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect challenge response.
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[0];
|
||||||
|
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(initiatorPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
// compare remote challenge
|
||||||
|
if (!expectedRemoteChallenge.SequenceEqual(remoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute session key.
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// initiator identity + initiator password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(initiatorIdentity.ToBytes()
|
||||||
|
.Concat(initiatorPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, null, initiatorIdentity, responderIdentity, sessionKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.ResponderIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
if (remoteAuthData.Length < 1)
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
|
||||||
|
// step 0: receive remote nonce.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
// @TODO: We can change our localNonce then send it
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get responder identity from provider.
|
||||||
|
if (responderIdentity == null)
|
||||||
|
(responderIdentity, responderPassword) = provider.GetSelfIdentityAndCredential(domain, hostName);
|
||||||
|
else
|
||||||
|
responderPassword = provider.GetSelfCredential(responderIdentity, domain, hostName);
|
||||||
|
|
||||||
|
if (responderPassword == null || responderIdentity == null)
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
localAuthData.Add(responderIdentity);
|
||||||
|
|
||||||
|
step = 1;
|
||||||
|
// send local nonce and identity.
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress,
|
||||||
|
localAuthData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect remote salt and challenge.
|
||||||
|
remoteSalt = (byte[])remoteAuthData[0];
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[1];
|
||||||
|
|
||||||
|
// compute expected challenge response.
|
||||||
|
var hashedPassword = ComputeSha3(responderPassword.Concat(remoteSalt).ToArray());
|
||||||
|
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(hashedPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
if (!expectedRemoteChallenge.SequenceEqual(remoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute our challenge response.
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(hashedPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// responder identity + responder hashed password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(responderIdentity.ToBytes()
|
||||||
|
.Concat(hashedPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, localAuthData, responderIdentity, null, sessionKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (mode == AuthenticationMode.DualIdentity)
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
if (remoteAuthData.Length < 2)
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
|
||||||
|
// step 0: receive remote nonce and initiator identity.
|
||||||
|
remoteNonce = (byte[])remoteAuthData[0];
|
||||||
|
initiatorIdentity = (string)remoteAuthData[1];
|
||||||
|
|
||||||
|
// prevent reply attack by checking if remote nonce is same as local nonce.
|
||||||
|
// @TODO: We can change our localNonce then send it
|
||||||
|
if (remoteNonce.SequenceEqual(localNonce))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get responder identity from provider.
|
||||||
|
if (responderIdentity == null)
|
||||||
|
(responderIdentity, responderPassword) = provider.GetSelfIdentityAndCredential(domain, hostName);
|
||||||
|
else
|
||||||
|
responderPassword = provider.GetSelfCredential(responderIdentity, domain, hostName);
|
||||||
|
|
||||||
|
if (responderPassword == null || responderIdentity == null)
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get initiator password from provider.
|
||||||
|
(localSalt, initiatorPassword) = provider.GetHostedAccountCredential(initiatorIdentity, domain);
|
||||||
|
|
||||||
|
// account not found or no password for this account.
|
||||||
|
if (initiatorPassword == null || initiatorIdentity == null)
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send local nonce, salt and responder identity.
|
||||||
|
localAuthData.Add(localNonce);
|
||||||
|
localAuthData.Add(localSalt);
|
||||||
|
localAuthData.Add(responderIdentity);
|
||||||
|
|
||||||
|
step = 1;
|
||||||
|
// send local nonce and identity.
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.InProgress,
|
||||||
|
localAuthData
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (step == 1)
|
||||||
|
{
|
||||||
|
// expect initiator salt and challenge.
|
||||||
|
var remoteSalt = (byte[])remoteAuthData[0];
|
||||||
|
var remoteChallenge = (byte[])remoteAuthData[1];
|
||||||
|
|
||||||
|
// compute expected challenge response.
|
||||||
|
var hashedPassword = ComputeSha3(responderPassword.Concat(remoteSalt).ToArray());
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
var expectedRemoteChallenge = ComputeSha3(remoteNonce.Concat(initiatorPassword)
|
||||||
|
.Concat(hashedPassword)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
// compare remote challenge
|
||||||
|
if (!expectedRemoteChallenge.SequenceEqual(remoteChallenge))
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute our challenge
|
||||||
|
var localChallenge = ComputeSha3(localNonce.Concat(hashedPassword)
|
||||||
|
.Concat(initiatorPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
localAuthData.Add(localChallenge);
|
||||||
|
|
||||||
|
// derive a session key from nonces and password.
|
||||||
|
// responder identity + responder password + initiator nonce + responder nonce
|
||||||
|
|
||||||
|
var sessionKey = ComputeSha3(initiatorIdentity.ToBytes()
|
||||||
|
.Concat(responderIdentity.ToBytes())
|
||||||
|
.Concat(initiatorPassword)
|
||||||
|
.Concat(hashedPassword)
|
||||||
|
.Concat(remoteNonce)
|
||||||
|
.Concat(localNonce)
|
||||||
|
.ToArray(), 512);
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Succeeded, localAuthData, initiatorIdentity, responderIdentity, sessionKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
step = -1;
|
||||||
|
return new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordAuthenticationHandler(AuthenticationMode mode,
|
||||||
|
AuthenticationDirection direction,
|
||||||
|
string initiatorIdentity,
|
||||||
|
string responderIdentity,
|
||||||
|
string hostName,
|
||||||
|
string domain,
|
||||||
|
PasswordAuthenticationProvider provider)
|
||||||
|
{
|
||||||
|
localNonce = Global.GenerateBytes(20);
|
||||||
|
|
||||||
|
this.provider = provider;
|
||||||
|
this.initiatorIdentity = initiatorIdentity;
|
||||||
|
this.responderIdentity = responderIdentity;
|
||||||
|
this.mode = mode;
|
||||||
|
this.direction = direction;
|
||||||
|
this.domain = domain;
|
||||||
|
this.hostName = hostName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Security.Authority.Providers
|
||||||
|
{
|
||||||
|
internal class PasswordAuthenticationProvider : IAuthenticationProvider
|
||||||
|
{
|
||||||
|
public string DefaultName => "hash";
|
||||||
|
|
||||||
|
public IAuthenticationHandler CreateAuthenticationHandler(AuthenticationContext context)
|
||||||
|
{
|
||||||
|
var authHandler = new PasswordAuthenticationHandler(context.Mode,
|
||||||
|
context.Direction,
|
||||||
|
context.InitiatorIdentity,
|
||||||
|
context.ResponderIdentity,
|
||||||
|
context.HostName,
|
||||||
|
context.Domain,
|
||||||
|
this);
|
||||||
|
|
||||||
|
return authHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual (byte[], byte[]) GetHostedAccountCredential(string identity, string domain)
|
||||||
|
{
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual (string, byte[]) GetSelfIdentityAndCredential(string domain, string hostname)
|
||||||
|
{
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual byte[] GetSelfCredential(string identity, string domain, string hostname)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Esiur.Security.Authority
|
|
||||||
{
|
|
||||||
public sealed class ResponderAuthenticationContext
|
|
||||||
{
|
|
||||||
public string? RemoteIpAddress { get; }
|
|
||||||
|
|
||||||
public string? LocalDomain { get; }
|
|
||||||
|
|
||||||
public AuthenticationMode Mode { get; }
|
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, string> Headers { get; }
|
|
||||||
= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,5 +59,6 @@ public class Session
|
|||||||
public IAuthenticationHandler AuthenticationHandler { get; set; }
|
public IAuthenticationHandler AuthenticationHandler { get; set; }
|
||||||
//public IAuthenticationHandler AuthenticationResponder { get; set; }
|
//public IAuthenticationHandler AuthenticationResponder { get; set; }
|
||||||
|
|
||||||
public string AuthorizedIdentity { get; set; }
|
public string LocalIdentity { get; set; }
|
||||||
|
public string RemoteIdentity { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,4 +52,5 @@ public interface IPermissionsManager
|
|||||||
bool Initialize(Map<string, object> settings, IResource resource);
|
bool Initialize(Map<string, object> settings, IResource resource);
|
||||||
|
|
||||||
Map<string, object> Settings { get; }
|
Map<string, object> Settings { get; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ public class UserPermissionsManager : IPermissionsManager
|
|||||||
{
|
{
|
||||||
Map<string,object> userPermissions = null;
|
Map<string,object> userPermissions = null;
|
||||||
|
|
||||||
if (settings.ContainsKey(session.AuthorizedIdentity))
|
if (settings.ContainsKey(session.RemoteIdentity))
|
||||||
userPermissions = settings[session.AuthorizedIdentity] as Map<string, object>;
|
userPermissions = settings[session.RemoteIdentity] as Map<string, object>;
|
||||||
else if (settings.ContainsKey("public"))
|
else if (settings.ContainsKey("public"))
|
||||||
userPermissions = settings["public"] as Map<string,object>;
|
userPermissions = settings["public"] as Map<string,object>;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public static class EsiurExtensions
|
|||||||
|
|
||||||
var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource);
|
var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource);
|
||||||
|
|
||||||
await options.Warehouse.Put($"{store.Instance.Name}/{typeof(T).Name}/{id}", res, 0, manager);
|
await options.Warehouse.Put($"{store.Instance.Name}/{typeof(T).Name}/{id}", res, new ResourceContext(0, null, null, manager));
|
||||||
|
|
||||||
return (T)res;
|
return (T)res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ public class EsiurProxyRewrite : IModelFinalizingConvention
|
|||||||
if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource)))
|
if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource)))
|
||||||
{
|
{
|
||||||
// check if the object exists
|
// check if the object exists
|
||||||
var obj = options.Warehouse.Create(entityType.ClrType) as IResource;
|
var obj = options.Warehouse.Create(entityType.ClrType, null) as IResource;
|
||||||
options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id);
|
options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id);
|
||||||
options.Warehouse.Put($"{options.Store.Instance.Name}/{entityType.ClrType.Name}/{id}", obj, 0, manager).Wait();
|
options.Warehouse.Put($"{options.Store.Instance.Name}/{entityType.ClrType.Name}/{id}", obj, new ResourceContext(0, null, null, manager)).Wait();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace Esiur.Stores.MongoDB
|
|||||||
public class MongoDBStore<T> : MongoDBStore where T:IResource
|
public class MongoDBStore<T> : MongoDBStore where T:IResource
|
||||||
{
|
{
|
||||||
[Export]
|
[Export]
|
||||||
public async AsyncReply<T> New(string name = null, object properties = null)
|
public async AsyncReply<T> New(string name = null, Map<string, object> properties = null)
|
||||||
{
|
{
|
||||||
var resource = Instance.Warehouse.Create<T>(properties);
|
var resource = Instance.Warehouse.Create<T>(properties);
|
||||||
await Instance.Warehouse.Put(this.Instance.Name + "/" + name, resource);
|
await Instance.Warehouse.Put(this.Instance.Name + "/" + name, resource);
|
||||||
|
|||||||
@@ -33,13 +33,6 @@ public partial class MyService
|
|||||||
[Export] bool boolean = true;
|
[Export] bool boolean = true;
|
||||||
[Export] bool[] booleanArray = new bool[] { true, false, true, false, true };
|
[Export] bool[] booleanArray = new bool[] { true, false, true, false, true };
|
||||||
|
|
||||||
[Export]
|
|
||||||
public MyGenericRecord<MyResource> GetGenericRecord()
|
|
||||||
{
|
|
||||||
return new MyGenericRecord<MyResource>() { Needed = 3, Start = 10, Results = new MyResource[0], Total = 102 };
|
|
||||||
}
|
|
||||||
|
|
||||||
[Export] public static string staticFunction(string name) => $"Hello {name}";
|
|
||||||
|
|
||||||
[Export] byte uInt8Test = 8;
|
[Export] byte uInt8Test = 8;
|
||||||
[Export] byte? uInt8Null = null;
|
[Export] byte? uInt8Null = null;
|
||||||
@@ -85,25 +78,33 @@ public partial class MyService
|
|||||||
|
|
||||||
[Export] DateTime time = DateTime.Now;
|
[Export] DateTime time = DateTime.Now;
|
||||||
|
|
||||||
|
[Export] public const double PI = Math.PI;
|
||||||
|
|
||||||
|
[Export] public MyService Me => this;
|
||||||
|
|
||||||
|
[Export] int PrivateInt32 { get; set; } = 99;
|
||||||
|
|
||||||
|
[Export("Object")] object objectTest = "String as object";
|
||||||
|
|
||||||
|
[Export] object[] objectArray = new object[] { 1, 1.2f, Math.PI, "Hello World" };
|
||||||
|
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
Map<string, object> stringMap = new Map<string, object>()
|
Map<string, object> stringMap = new Map<string, object>()
|
||||||
{
|
{
|
||||||
["int"] = 33,
|
["Sequence"] = 123,
|
||||||
["string"] = "Hello World"
|
["Message"] = "Hello World"
|
||||||
};
|
};
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
Map<int, string> intStringMap = new()
|
Map<int, string> intStringMap = new()
|
||||||
{
|
{
|
||||||
[4] = "Abcd",
|
[4] = "Abcd",
|
||||||
[44] = "EfG"
|
[3] = "EfG"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
[Export("Object")] object objectTest = "object";
|
|
||||||
|
|
||||||
[Export] object[] objectArray = new object[] { 1, 1.2f, Math.PI, "Hello World" };
|
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public PropertyContext<int> PropertyContext
|
public PropertyContext<int> PropertyContext
|
||||||
@@ -119,10 +120,10 @@ public partial class MyService
|
|||||||
int MyPasscode = 2025;
|
int MyPasscode = 2025;
|
||||||
public PropertyContext<int> Passcode
|
public PropertyContext<int> Passcode
|
||||||
{
|
{
|
||||||
get => new((sender) => sender.Session.AuthorizedIdentity == "alice" ? MyPasscode : 0);
|
get => new((sender) => sender.Session.RemoteIdentity == "alice" ? MyPasscode : 0);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value.Connection.Session.AuthorizedIdentity != "alice")
|
if (value.Connection.Session.RemoteIdentity != "alice")
|
||||||
throw new Exception("Only Alice is allowed.");
|
throw new Exception("Only Alice is allowed.");
|
||||||
MyPasscode = value.Value;
|
MyPasscode = value.Value;
|
||||||
}
|
}
|
||||||
@@ -159,9 +160,6 @@ public partial class MyService
|
|||||||
[Export]
|
[Export]
|
||||||
public void InvokeEvents(string msg, InvocationContext context)
|
public void InvokeEvents(string msg, InvocationContext context)
|
||||||
{
|
{
|
||||||
//if (context.Connection.Session.AuthorizedAccount != "Alice")
|
|
||||||
// throw new Exception("Only Alice is allowed.");
|
|
||||||
|
|
||||||
StringEvent?.Invoke(msg);
|
StringEvent?.Invoke(msg);
|
||||||
ArrayEvent?.Invoke(new object[] { DateTime.UtcNow, "Event", msg });
|
ArrayEvent?.Invoke(new object[] { DateTime.UtcNow, "Event", msg });
|
||||||
}
|
}
|
||||||
@@ -207,9 +205,13 @@ public partial class MyService
|
|||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export] public const double PI = Math.PI;
|
|
||||||
|
|
||||||
[Export] public MyService Me => this;
|
[Export]
|
||||||
|
public MyGenericRecord<MyResource> GetGenericRecord()
|
||||||
|
{
|
||||||
|
return new MyGenericRecord<MyResource>() { Needed = 3, Start = 10, Results = new MyResource[0], Total = 102 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export] public static string staticFunction(string name) => $"Hello {name}";
|
||||||
|
|
||||||
[Export] int PrivateInt32 { get; set; } = 99;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class Program
|
|||||||
//TestSerialization(10.1d);
|
//TestSerialization(10.1d);
|
||||||
//TestSerialization((byte)1);
|
//TestSerialization((byte)1);
|
||||||
//TestSerialization((byte)2);
|
//TestSerialization((byte)2);
|
||||||
TestSerialization(new int[] { 1, 2, 3, 4 });
|
//TestSerialization(new int[] { 1, 2, 3, 4 });
|
||||||
//var x = LogLevel.Warning;
|
//var x = LogLevel.Warning;
|
||||||
|
|
||||||
//TestSerialization(LogLevel.Warning);
|
//TestSerialization(LogLevel.Warning);
|
||||||
@@ -213,18 +213,22 @@ class Program
|
|||||||
private static async void TestClient(IResource local)
|
private static async void TestClient(IResource local)
|
||||||
{
|
{
|
||||||
|
|
||||||
var con = await new Warehouse().Get<EpConnection>("EP://localhost", new EpConnectionConfig
|
var con = await new Warehouse().Get<EpConnection>("EP://localhost", new EpConnectionContext
|
||||||
{
|
{
|
||||||
AutoReconnect = true,
|
AutoReconnect = true,
|
||||||
Username = "admin",
|
//Username = "admin",
|
||||||
Password = "admin",
|
//Password = "admin",
|
||||||
Authenticator = Authenticator
|
Identity = "demo",
|
||||||
|
AuthenticationProtocol = "hash"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
dynamic remote = await con.Get("sys/service");
|
dynamic remote = await con.Get("sys/service");
|
||||||
var gr = await remote.GetGenericRecord();
|
|
||||||
Console.WriteLine(gr);
|
TestObjectProps(local, remote);
|
||||||
|
|
||||||
|
//return;
|
||||||
|
|
||||||
//return;
|
//return;
|
||||||
|
|
||||||
Console.WriteLine("OK");
|
Console.WriteLine("OK");
|
||||||
@@ -236,11 +240,8 @@ class Program
|
|||||||
var temp = await con.Call("temp");
|
var temp = await con.Call("temp");
|
||||||
Console.WriteLine("Temp: " + temp.GetHashCode());
|
Console.WriteLine("Temp: " + temp.GetHashCode());
|
||||||
|
|
||||||
//var template = await con.GetTemplateByClassName("Test.MyResource");
|
|
||||||
|
|
||||||
|
|
||||||
TestObjectProps(local, remote);
|
|
||||||
|
|
||||||
|
|
||||||
var opt = await remote.Optional(new { a1 = 22, a2 = 33, a4 = "What?" });
|
var opt = await remote.Optional(new { a1 = 22, a2 = 33, a4 = "What?" });
|
||||||
Console.WriteLine(opt);
|
Console.WriteLine(opt);
|
||||||
|
|||||||
Reference in New Issue
Block a user