diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj
index 480e7bd..e6e53e0 100644
--- a/TestApp/TestApp.csproj
+++ b/TestApp/TestApp.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj
index 606f9d4..22f73b8 100644
--- a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj
+++ b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/ZeroLevel.EventsServer/ZeroLevel.EventsServer.csproj b/ZeroLevel.EventsServer/ZeroLevel.EventsServer.csproj
index 03cb9e8..c1cb915 100644
--- a/ZeroLevel.EventsServer/ZeroLevel.EventsServer.csproj
+++ b/ZeroLevel.EventsServer/ZeroLevel.EventsServer.csproj
@@ -6,7 +6,6 @@
-
diff --git a/ZeroLevel.NN/Services/KNN/Point.cs b/ZeroLevel.NN/Services/KNN/Point.cs
new file mode 100644
index 0000000..fb37d3c
--- /dev/null
+++ b/ZeroLevel.NN/Services/KNN/Point.cs
@@ -0,0 +1,12 @@
+namespace ZeroLevel.NN.Services.KNN
+{
+ public class FPoint
+ {
+ public float[] Values { get; set; }
+ }
+
+ public interface IMetric
+ {
+ float Calculate(FPoint a, FPoint b);
+ }
+}
diff --git a/ZeroLevel.NN/ZeroLevel.NN.csproj b/ZeroLevel.NN/ZeroLevel.NN.csproj
index e081781..dc33965 100644
--- a/ZeroLevel.NN/ZeroLevel.NN.csproj
+++ b/ZeroLevel.NN/ZeroLevel.NN.csproj
@@ -35,13 +35,14 @@
-
+
+
diff --git a/ZeroLevel.SQL/ZeroLevel.SQL.csproj b/ZeroLevel.SQL/ZeroLevel.SQL.csproj
index b46f68d..82e1d8d 100644
--- a/ZeroLevel.SQL/ZeroLevel.SQL.csproj
+++ b/ZeroLevel.SQL/ZeroLevel.SQL.csproj
@@ -26,8 +26,8 @@
-
-
+
+
diff --git a/ZeroLevel.SqLite/SqLiteDelayDataStorage.cs b/ZeroLevel.SqLite/SqLiteDelayDataStorage.cs
deleted file mode 100644
index 301b7f6..0000000
--- a/ZeroLevel.SqLite/SqLiteDelayDataStorage.cs
+++ /dev/null
@@ -1,177 +0,0 @@
-using SQLite;
-using System;
-using System.Threading;
-using ZeroLevel.Services.Serialization;
-using ZeroLevel.Services.Shedulling;
-
-namespace ZeroLevel.SqLite
-{
- public sealed class ExpirationRecord
- {
- [PrimaryKey, AutoIncrement]
- public long Id { get; set; }
- [Indexed]
- public long Expiration { get; set; }
- public byte[] Data { get; set; }
- }
-
- public sealed class SqLiteDelayDataStorage
- : BaseSqLiteDB
- where T : class, IBinarySerializable, new()
- {
- #region Fields
-
- private readonly IExpirationSheduller _sheduller;
- private readonly Func _expire_date_calc_func;
- private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
-
- #endregion Fields
-
- #region Ctor
-
- public SqLiteDelayDataStorage(string database_file_path,
- Func expire_callback,
- Func expire_date_calc_func)
- : base(database_file_path)
- {
- this._expire_date_calc_func = expire_date_calc_func;
- CreateTable();
- _sheduller = Sheduller.CreateExpirationSheduller();
- OnExpire += expire_callback;
- Preload();
- }
-
- #endregion Ctor
-
- #region API
-
- public event Func OnExpire;
-
- public bool Push(T packet)
- {
- DateTime expirationDate;
- try
- {
- expirationDate = _expire_date_calc_func(packet);
- }
- catch (Exception ex)
- {
- Log.Error(ex, "[SqLiteDelayDataStorage] Fault append data to storage");
- return false;
- }
- var expirationTime = expirationDate.Ticks;
- _rwLock.EnterWriteLock();
- long id = -1;
- try
- {
- var r = Append(new ExpirationRecord { Expiration = expirationTime, Data = MessageSerializer.Serialize(packet) });
- id = r.Id;
- }
- catch (Exception ex)
- {
- Log.Error(ex, $"[SqLiteDelayDataStorage] Fault insert record in delay storage. Expiration time: '{expirationTime}'.");
- return false;
- }
- finally
- {
- _rwLock.ExitWriteLock();
- }
- _sheduller.Push(expirationDate, (k) => Pop(id));
- return true;
- }
-
- #endregion API
-
- #region Private members
-
- private void Preload()
- {
- _rwLock.EnterReadLock();
- try
- {
- foreach (var record in SelectAll())
- {
- _sheduller.Push(new DateTime(record.Expiration, DateTimeKind.Local), (k) => Pop(record.Id));
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex, "[SqLiteDelayDataStorage] Fault preload datafrom db");
- }
- finally
- {
- _rwLock.ExitReadLock();
- }
- }
-
- private void Pop(long id)
- {
- try
- {
- byte[] body;
- _rwLock.EnterReadLock();
- try
- {
- body = Single(r=>r.Id == id)?.Data;
- }
- catch (Exception ex)
- {
- Log.Error(ex, $"[SqLiteDelayDataStorage] Fault get body by id '{id}'");
- RemoveRecordById(id);
- return;
- }
- finally
- {
- _rwLock.ExitReadLock();
- }
- T packet;
- try
- {
- packet = MessageSerializer.Deserialize(body);
- }
- catch (Exception ex)
- {
- Log.Error(ex, $"[SqLiteDelayDataStorage] Fault deserialize body. Id '{id}'");
- RemoveRecordById(id);
- return;
- }
- if (OnExpire?.Invoke(packet) ?? false)
- {
- RemoveRecordById(id);
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex, "[SqLiteDelayDataStorage] Сбой обработки отложенной записи из DB");
- }
- }
-
- private void RemoveRecordById(long id)
- {
- _rwLock.EnterWriteLock();
- try
- {
- Delete(r => r.Id == id);
- }
- catch (Exception ex)
- {
- Log.Error(ex, $"[SqLiteDelayDataStorage] Fault remove record by id '{id}'");
- }
- finally
- {
- _rwLock.ExitWriteLock();
- }
- }
-
- #endregion Private members
-
- #region IDisposable
-
- protected override void DisposeStorageData()
- {
- _sheduller.Dispose();
- }
-
- #endregion IDisposable
- }
-}
diff --git a/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj b/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj
index b4447bf..bbd442c 100644
--- a/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj
+++ b/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj
@@ -9,9 +9,9 @@
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/ZeroLevel.sln b/ZeroLevel.sln
index 229af50..837e078 100644
--- a/ZeroLevel.sln
+++ b/ZeroLevel.sln
@@ -19,10 +19,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.SQL", "ZeroLevel.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.Logger", "ZeroLevel.Logger\ZeroLevel.Logger.csproj", "{D1C061DB-3565-43C3-B8F3-628DE4908750}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.SqLite", "ZeroLevel.SqLite\ZeroLevel.SqLite.csproj", "{5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.EventsServer", "ZeroLevel.EventsServer\ZeroLevel.EventsServer.csproj", "{04219F58-4D3A-4707-82A8-4DDDC9882969}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WPFExamples", "WPFExamples", "{7CCA0125-7A96-48FA-9F0D-BCF7EAD8FF9D}"
ProjectSection(SolutionItems) = preProject
WPFExamples\Controls\AlignableWrapPanel.cs = WPFExamples\Controls\AlignableWrapPanel.cs
@@ -67,7 +63,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "ConnectionTest\Cl
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoLoader", "AutoLoader", "{2EF83101-63BC-4397-A005-A747189143D4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppContainer", "AutoLoader\AppContainer\AppContainer.csproj", "{9DE345EA-955B-41A8-93AF-277C0B5A9AC5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppContainer", "AutoLoader\AppContainer\AppContainer.csproj", "{9DE345EA-955B-41A8-93AF-277C0B5A9AC5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -151,30 +147,6 @@ Global
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x64.Build.0 = Release|x64
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x86.ActiveCfg = Release|x86
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x86.Build.0 = Release|x86
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|x64.ActiveCfg = Debug|x64
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|x64.Build.0 = Debug|x64
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|x86.ActiveCfg = Debug|x86
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Debug|x86.Build.0 = Debug|x86
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|Any CPU.Build.0 = Release|Any CPU
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|x64.ActiveCfg = Release|x64
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|x64.Build.0 = Release|x64
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|x86.ActiveCfg = Release|x86
- {5B545DD6-8573-4CDD-B32D-9B0AA2AC2F9A}.Release|x86.Build.0 = Release|x86
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|x64.ActiveCfg = Debug|x64
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|x64.Build.0 = Debug|x64
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|x86.ActiveCfg = Debug|x86
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Debug|x86.Build.0 = Debug|x86
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|Any CPU.Build.0 = Release|Any CPU
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|x64.ActiveCfg = Release|x64
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|x64.Build.0 = Release|x64
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|x86.ActiveCfg = Release|x86
- {04219F58-4D3A-4707-82A8-4DDDC9882969}.Release|x86.Build.0 = Release|x86
{3496A688-0749-48C2-BD60-ABB42A5C17C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3496A688-0749-48C2-BD60-ABB42A5C17C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3496A688-0749-48C2-BD60-ABB42A5C17C9}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/ZeroLevel/Services/Config/BaseConfiguration.cs b/ZeroLevel/Services/Config/BaseConfiguration.cs
index e7bd8f8..3f4a5f3 100644
--- a/ZeroLevel/Services/Config/BaseConfiguration.cs
+++ b/ZeroLevel/Services/Config/BaseConfiguration.cs
@@ -4,13 +4,32 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
+using System.Reflection;
using ZeroLevel.Services.Collections;
+using ZeroLevel.Services.Invokation;
using ZeroLevel.Services.ObjectMapping;
using ZeroLevel.Services.Reflection;
using ZeroLevel.Services.Serialization;
namespace ZeroLevel.Services.Config
{
+ public interface IConfigRecordParser
+ {
+ object Parse(string line);
+ }
+
+ public class ConfigRecordParseAttribute
+ : Attribute
+ {
+ public IConfigRecordParser Parser { get; set; }
+
+ public ConfigRecordParseAttribute(Type parserType)
+ {
+ if (parserType == null) throw new ArgumentNullException(nameof(parserType));
+ Parser = (IConfigRecordParser)Activator.CreateInstance(parserType);
+ }
+ }
+
///
/// Base configuration
///
@@ -477,119 +496,106 @@ namespace ZeroLevel.Services.Config
var instance = TypeHelpers.CreateInitialState(type);
mapper.TraversalMembers(member =>
{
- if (Contains(member.Name))
+ int count = Count(member.Name);
+ if (count > 0)
{
- int count = Count(member.Name);
- switch (count)
+ var values = this.Items(member.Name);
+ IConfigRecordParser parser = member.Original.GetCustomAttribute()?.Parser;
+ if (TypeHelpers.IsArray(member.ClrType) && member.ClrType.GetArrayRank() == 1)
+ {
+ int index = 0;
+ var itemType = member.ClrType.GetElementType();
+ if (parser == null)
+ {
+ var elements = values.SelectMany(v => SplitRange(v, itemType)).ToArray();
+ var arrayBuilder = CollectionFactory.CreateArray(itemType, elements.Length);
+ foreach (var item in elements)
+ {
+ arrayBuilder.Set(item, index);
+ index++;
+ }
+ member.Setter(instance, arrayBuilder.Complete());
+ }
+ else
+ {
+ var elements = values.Select(v => parser.Parse(v)).ToArray();
+ var arrayBuilder = CollectionFactory.CreateArray(itemType, elements.Length);
+ foreach (var item in elements)
+ {
+ arrayBuilder.Set(item, index);
+ index++;
+ }
+ member.Setter(instance, arrayBuilder.Complete());
+ }
+ }
+ else if (TypeHelpers.IsEnumerable(member.ClrType) && member.ClrType != typeof(string))
{
- case 0: return;
- case 1: // field
- if (TypeHelpers.IsArray(member.ClrType)
- && member.ClrType.GetArrayRank() == 1)
+ var itemType = member.ClrType.GenericTypeArguments.First();
+ var collectionBuilder = CollectionFactory.Create(itemType);
+ if (parser == null)
+ {
+ var elements = values.SelectMany(v => SplitRange(v, itemType)).ToArray();
+ foreach (var item in elements)
{
- var itemType = member.ClrType.GetElementType();
- var elements = SplitRange(First(member.Name), itemType).ToArray();
- var arrayBuilder = CollectionFactory.CreateArray(itemType, elements.Length);
- int index = 0;
- foreach (var item in elements)
- {
- arrayBuilder.Set(item, index);
- index++;
- }
- member.Setter(instance, arrayBuilder.Complete());
+ collectionBuilder.Append(item);
}
- else if (TypeHelpers.IsEnumerable(member.ClrType) && member.ClrType != typeof(string))
+ }
+ else
+ {
+ var elements = values.Select(v => parser.Parse(v)).ToArray();
+ foreach (var item in elements)
{
- var itemType = member.ClrType.GenericTypeArguments.First();
- var collectionBuilder = CollectionFactory.Create(itemType);
- foreach (var item in SplitRange(First(member.Name), itemType))
- {
- collectionBuilder.Append(item);
- }
- member.Setter(instance, collectionBuilder.Complete());
+ collectionBuilder.Append(item);
}
- else if (TypeHelpers.IsEnum(member.ClrType))
+ }
+ member.Setter(instance, collectionBuilder.Complete());
+ }
+ else
+ {
+ var single = values.First();
+ if (parser != null)
+ {
+ member.Setter(instance, parser.Parse(single));
+ }
+ else
+ {
+ if (TypeHelpers.IsEnum(member.ClrType))
{
- var value = Enum.Parse(member.ClrType, First(member.Name));
+ var value = Enum.Parse(member.ClrType, single);
member.Setter(instance, value);
}
else if (TypeHelpers.IsUri(member.ClrType))
{
- var uri = new Uri(First(member.Name));
+ var uri = new Uri(single);
member.Setter(instance, uri);
}
else if (TypeHelpers.IsIpEndPoint(member.ClrType))
{
- var ep = ZeroLevel.Network.NetUtils.CreateIPEndPoint(First(member.Name));
+ var ep = ZeroLevel.Network.NetUtils.CreateIPEndPoint(single);
member.Setter(instance, ep);
}
else if (member.ClrType == typeof(IPAddress))
{
- var ip = IPAddress.Parse(First(member.Name));
+ var ip = IPAddress.Parse(single);
member.Setter(instance, ip);
}
else
{
- var item = First(member.Name);
- var itemType = member.ClrType;
- member.Setter(instance, StringToTypeConverter.TryConvert(item, itemType));
- }
- break;
- default: // array, or first
- if (TypeHelpers.IsArray(member.ClrType)
- && member.ClrType.GetArrayRank() == 1)
- {
- //throw new NotSupportedException("Multidimensions array not supported");
- var itemType = member.ClrType.GetElementType();
- if (itemType == typeof(string))
- {
- var array = Items(member.Name).ToArray();
- member.Setter(instance, array);
- }
- else
- {
- var arrayBuilder = CollectionFactory.CreateArray(itemType, count);
- int index = 0;
- foreach (var item in Items(member.Name))
- {
- arrayBuilder.Set(StringToTypeConverter.TryConvert(item, itemType), index);
- index++;
- }
- member.Setter(instance, arrayBuilder.Complete());
- }
- }
- else if (typeof(string) != member.ClrType && TypeHelpers.IsEnumerable(member.ClrType))
- {
- var itemType = member.ClrType.GenericTypeArguments.First();
- if (itemType == typeof(string))
- {
- member.Setter(instance, Items(member.Name));
- }
- else
- {
- var collectionBuilder = CollectionFactory.Create(itemType);
- foreach (var item in Items(member.Name))
- {
- collectionBuilder.Append(StringToTypeConverter.TryConvert(item, itemType));
- }
- member.Setter(instance, collectionBuilder.Complete());
- }
- }
- else
- {
- var item = First(member.Name);
var itemType = member.ClrType;
- member.Setter(instance, StringToTypeConverter.TryConvert(item, itemType));
+ member.Setter(instance, StringToTypeConverter.TryConvert(single, itemType));
}
- break;
+ }
}
}
});
return instance;
}
+
+
private static IEnumerable