From f28abaccd4f1eb2ec0894d2363be6e179f0aa912 Mon Sep 17 00:00:00 2001 From: Ogoun Date: Fri, 5 Apr 2019 16:18:39 +0300 Subject: [PATCH] Microservices refactoring --- Shemes/Network.graphml | 687 ++++++++++++++++++ ZeroLevel.Discovery/App.config | 3 +- ZeroLevel.Discovery/DiscoveryService.cs | 24 +- ZeroLevel.Discovery/RouteTable.cs | 2 +- .../ZeroLevel.Discovery.csproj | 1 - ...l.Discovery.csproj.CoreCompileInputs.cache | 2 +- ...el.Discovery.csprojAssemblyReference.cache | Bin 165137 -> 168267 bytes ZeroLevel.Microservices/BaseProxy.cs | 154 ---- .../ExchangeTransportFactory.cs | 109 --- .../Properties/AssemblyInfo.cs | 35 - .../ZeroLevel.Microservices.csproj | 71 -- ...le_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs | 0 ...le_5937a670-0e60-4077-877b-f7221da3dda1.cs | 0 ...le_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs | 0 ...croservices.csproj.CoreCompileInputs.cache | 1 - ...icroservices.csprojAssemblyReference.cache | Bin 78235 -> 0 bytes ZeroLevel.Microservices/packages.config | 4 - ZeroLevel.sln | 14 - .../Services/Network/Contract/IExClient.cs | 5 + .../Network}/ExchangeTransportFactory.cs | 26 +- .../Network/Microservices}/Checkpoint.cs | 2 +- .../Network/Microservices}/CheckpointArc.cs | 2 +- .../Network/Microservices}/CheckpointType.cs | 2 +- .../Network/Microservices/DiscoveryClient.cs | 136 ++-- .../Network/Microservices}/ExServiceHost.cs | 12 +- .../Network/Microservices}/Exchange.cs | 2 +- .../Microservices}/IDiscoveryClient.cs | 4 +- .../Microservices}/IExchangeService.cs | 2 +- .../Network/Models/MicroserviceInfo.cs | 23 +- .../{Services/IPFinder.cs => NetUtils.cs} | 38 +- .../Services/Network/Services/ExClient.cs | 4 +- .../Services/Network/Services/ExService.cs | 2 +- .../Services/ZExSocketObservableServer.cs | 4 +- .../Services/Network/SocketExtensions.cs | 44 -- ZeroLevel/ZeroLevel.csproj | 12 +- .../ZeroLevel.csproj.CoreCompileInputs.cache | 2 +- .../ZeroLevel.csprojAssemblyReference.cache | Bin 20909 -> 20301 bytes 37 files changed, 895 insertions(+), 534 deletions(-) create mode 100644 Shemes/Network.graphml delete mode 100644 ZeroLevel.Microservices/BaseProxy.cs delete mode 100644 ZeroLevel.Microservices/ExchangeTransportFactory.cs delete mode 100644 ZeroLevel.Microservices/Properties/AssemblyInfo.cs delete mode 100644 ZeroLevel.Microservices/ZeroLevel.Microservices.csproj delete mode 100644 ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs delete mode 100644 ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs delete mode 100644 ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs delete mode 100644 ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csproj.CoreCompileInputs.cache delete mode 100644 ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csprojAssemblyReference.cache delete mode 100644 ZeroLevel.Microservices/packages.config rename {ZeroLevel.Discovery => ZeroLevel/Services/Network}/ExchangeTransportFactory.cs (81%) rename {ZeroLevel.Microservices/Model => ZeroLevel/Services/Network/Microservices}/Checkpoint.cs (98%) rename {ZeroLevel.Microservices/Model => ZeroLevel/Services/Network/Microservices}/CheckpointArc.cs (93%) rename {ZeroLevel.Microservices/Model => ZeroLevel/Services/Network/Microservices}/CheckpointType.cs (73%) rename ZeroLevel.Microservices/WebApiDiscoveryClient.cs => ZeroLevel/Services/Network/Microservices/DiscoveryClient.cs (54%) rename {ZeroLevel.Microservices => ZeroLevel/Services/Network/Microservices}/ExServiceHost.cs (98%) rename {ZeroLevel.Microservices => ZeroLevel/Services/Network/Microservices}/Exchange.cs (99%) rename {ZeroLevel.Microservices/Contracts => ZeroLevel/Services/Network/Microservices}/IDiscoveryClient.cs (83%) rename {ZeroLevel.Microservices/Contracts => ZeroLevel/Services/Network/Microservices}/IExchangeService.cs (84%) rename ZeroLevel/Services/Network/{Services/IPFinder.cs => NetUtils.cs} (53%) delete mode 100644 ZeroLevel/Services/Network/SocketExtensions.cs diff --git a/Shemes/Network.graphml b/Shemes/Network.graphml new file mode 100644 index 0000000..9bcb6a4 --- /dev/null +++ b/Shemes/Network.graphml @@ -0,0 +1,687 @@ + + + + + + + + + + + + + + + + + + + + + + + + NetworkStreamFastObfuscator + + + + + + + + + + + ExchangeTransportFactory + + + + + + + + + + + IExService + + + + + + + + + + + IExClient + + + + + + + + + + + ZBaseNetwork + + + + + + + + + + + ZSocketClient + + + + + + + + + + + ZSocketServer + + + + + + + + + + + <ZSocketServerClient> + + + + + + + + + + + IZTransport + + + + + + + + + + + + + + ExClient + + + + + + + + + + + IExClient + + + + + + + + + + + + + + IZBackward + + + + + + + + + + + + + + ExRouter + + + + + + + + + + + ExService + + + + + + + + + + + IExService + + + + + + + + + + + + + + IZObservableServer + + + + + + + + + + + + + + FrameExchange + + + + + + + + + + + FrameBuilder + + + + + + + + + + + FrameParser + + + + + + + + + + + ZExSocketObservableServer + + + + + + + + + + + ExServiceHost + + + + + + + + + + + IDiscoveryClient + + + + + + + + + + + + + + IExchangeService + + + + + + + + + + + + + + RegisterService + + + + + + + + + + + RegisterService + + + + + + + + + + + MicroserviceInfo + + + + + + + + + + + DiscoveryClient + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZeroLevel.Discovery/App.config b/ZeroLevel.Discovery/App.config index f91f31e..8ac5084 100644 --- a/ZeroLevel.Discovery/App.config +++ b/ZeroLevel.Discovery/App.config @@ -5,7 +5,8 @@ - + + diff --git a/ZeroLevel.Discovery/DiscoveryService.cs b/ZeroLevel.Discovery/DiscoveryService.cs index f48cf3c..5665a7c 100644 --- a/ZeroLevel.Discovery/DiscoveryService.cs +++ b/ZeroLevel.Discovery/DiscoveryService.cs @@ -1,10 +1,18 @@ -using ZeroLevel.Services.Applications; +using System.Collections; +using System.Collections.Generic; +using ZeroLevel.Models; +using ZeroLevel.Network; +using ZeroLevel.Network.Microservices; +using ZeroLevel.Services.Applications; +using ZeroLevel.Services.Network; namespace ZeroLevel.Discovery { public sealed class DiscoveryService : BaseWindowsService, IZeroService { + private IExService _exInbox; + public DiscoveryService() : base("Discovery") { @@ -20,13 +28,23 @@ namespace ZeroLevel.Discovery public override void StartAction() { - Injector.Default.Register(new RouteTable()); - var port = Configuration.Default.First("port"); + var routeTable = new RouteTable(); + + Injector.Default.Register(routeTable); + var port = Configuration.Default.First("apiport"); Startup.StartWebPanel(port, false); + + var socketPort = Configuration.Default.First("socketport"); + _exInbox = ExchangeTransportFactory.GetServer("socket", socketPort); + _exInbox.RegisterInbox>("services", (_, __) => routeTable.Get()); + _exInbox.RegisterInbox("register", (info, _, __) => routeTable.Append(info)); + + Log.Info($"TCP server started on port {socketPort}"); } public override void StopAction() { + _exInbox.Dispose(); } } } \ No newline at end of file diff --git a/ZeroLevel.Discovery/RouteTable.cs b/ZeroLevel.Discovery/RouteTable.cs index 699dfbe..2d46f5d 100644 --- a/ZeroLevel.Discovery/RouteTable.cs +++ b/ZeroLevel.Discovery/RouteTable.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; -using ZeroLevel.Microservices; using ZeroLevel.Models; +using ZeroLevel.Network; using ZeroLevel.Network.Microservices; namespace ZeroLevel.Discovery diff --git a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj index 299b78e..3028b5e 100644 --- a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj +++ b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj @@ -77,7 +77,6 @@ Component - diff --git a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache index ffd6fd9..8950e52 100644 --- a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache +++ b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -4f0bbfe8ac44b56784f7eeaa3cdef96609d6b97e +fe8032ac49bedc0ec84767ee0419b2fc618b5766 diff --git a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache index dca3baa2f2c2463c16eeaa1df9183a7492ebe588..7e437ec59b7e20e91592e8593d40333d35ca1d2f 100644 GIT binary patch literal 168267 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 literal 165137 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 parameters) - { - if (null == resource) throw new ArgumentNullException("resource"); - var stringBuilder = new StringBuilder(baseUri); - if (baseUri[baseUri.Length - 1] != '/') - stringBuilder.Append('/'); - if (resource[0] != '/') - { - stringBuilder.Append(resource); - } - else - { - stringBuilder.Append(resource.Substring(1)); - } - parameters. - Do(list => - { - if (list.Count > 0) - { - stringBuilder.Append("?"); - foreach (string key in list.Keys) - { - var val = list[key]; - if (val == null) - { - stringBuilder.Append(key); - } - else - { - var vtype = val.GetType(); - if (vtype.IsArray) - { - if (vtype.GetElementType() == typeof(string)) - { - var arr = (string[])val; - stringBuilder.Append(string.Join("&", arr.Select(i => string.Format("{0}[]={1}", key, i)))); - } - else - { - var arr = (object[])val; - stringBuilder.Append(string.Join("&", arr.Select(i => string.Format("{0}[]={1}", key, JsonConvert.SerializeObject(i))))); - } - } - else - { - if (vtype == typeof(string)) - { - stringBuilder.AppendFormat("{0}={1}", key, val); - } - else - { - stringBuilder.AppendFormat("{0}={1}", key, JsonConvert.SerializeObject(val)); - } - } - } - stringBuilder.Append("&"); - } - } - }); - return new Uri(stringBuilder.ToString().TrimEnd('&')); - } - - protected T SendRequest(string resource, string method, object body, IDictionary parameters = null) - { - string statusCode = null; - string reason = null; - try - { - var request = (HttpWebRequest)WebRequest.Create(BuildRequestUrl(_baseUrl, resource, parameters)); - request.UseDefaultCredentials = true; - request.Method = method; - request.Proxy = null; - request.AutomaticDecompression = DecompressionMethods.GZip; - if (body != null) - { - request.Accept = "application/json"; - request.ContentType = "application/json"; - using (var streamWriter = new StreamWriter(request.GetRequestStream())) - { - streamWriter.Write(JsonConvert.SerializeObject(body)); - streamWriter.Flush(); - } - } - using (var response = (HttpWebResponse)request.GetResponse()) - { - statusCode = response.StatusCode.ToString(); - reason = response.StatusDescription; - if (response.StatusCode == HttpStatusCode.OK) - { - using (var stream = new StreamReader(response.GetResponseStream())) - { - string json = stream.ReadToEnd(); - return JsonConvert.DeserializeObject(json); - } - } - else - { - throw new Exception("Bad status code"); - } - } - } - catch (Exception ex) - { - var line = $"Resource request failed. [{method}] {resource}. Error code: {(statusCode ?? "Uncknown")}. Comment: {(reason ?? ex.Message)}"; - Log.Error(ex, line); - throw new InvalidOperationException(line, ex); - } - } - - protected T GET(string resource, IDictionary parameters = null) - { - return SendRequest(resource, "GET", null, parameters); - } - - protected T POST(string resource, object body, IDictionary parameters = null) - { - return SendRequest(resource, "POST", body, parameters); - } - - protected T DELETE(string resource, object body, IDictionary parameters = null) - { - return SendRequest(resource, "DELETE", body, parameters); - } - - static BaseProxy() - { - ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; - ServicePointManager.Expect100Continue = false; - ServicePointManager.DefaultConnectionLimit = 8; - } - - public BaseProxy(string baseUri) - { - if (false == baseUri.EndsWith("/")) - _baseUrl = baseUri + "/"; - else - _baseUrl = baseUri; - } - } -} \ No newline at end of file diff --git a/ZeroLevel.Microservices/ExchangeTransportFactory.cs b/ZeroLevel.Microservices/ExchangeTransportFactory.cs deleted file mode 100644 index f46fd78..0000000 --- a/ZeroLevel.Microservices/ExchangeTransportFactory.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Reflection; -using ZeroLevel.Network.Microservices; -using ZeroLevel.Services.Network; -using ZeroLevel.Services.Network.Contract; - -namespace ZeroLevel.Microservices -{ - internal static class ExchangeTransportFactory - { - private static readonly Dictionary _customServers = new Dictionary(); - private static readonly Dictionary _customClients = new Dictionary(); - private static readonly ConcurrentDictionary _clientInstances = new ConcurrentDictionary(); - - /// - /// Scanning the specified assembly to find the types that implement the IExchangeServer or IExchangeClient interfaces - /// - internal static void ScanAndRegisterCustomTransport(Assembly asm) - { - foreach (var type in asm.GetExportedTypes()) - { - var serverAttr = type.GetCustomAttribute(); - if (serverAttr != null && - string.IsNullOrWhiteSpace(serverAttr.Protocol) == false && - typeof(IZObservableServer).IsAssignableFrom(type)) - { - _customServers[serverAttr.Protocol] = type; - } - var clientAttr = type.GetCustomAttribute(); - if (clientAttr != null && - string.IsNullOrWhiteSpace(clientAttr.Protocol) == false && - typeof(IZTransport).IsAssignableFrom(type)) - { - _customClients[clientAttr.Protocol] = type; - } - } - } - - /// - /// Creates a server to receive messages using the specified protocol - /// - /// Protocol - /// Server - internal static ExService GetServer(string protocol) - { - ExService instance = null; - if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) - { - instance = new ExService(new ZExSocketObservableServer(new System.Net.IPEndPoint(IPFinder.GetNonLoopbackAddress(), IPFinder.GetFreeTcpPort()))); - } - else - { - var key = protocol.Trim().ToLowerInvariant(); - if (_customServers.ContainsKey(key)) - { - instance = new ExService((IZObservableServer)Activator.CreateInstance(_customServers[key])); - } - } - if (instance != null) - { - return instance; - } - throw new NotSupportedException($"Protocol {protocol} not supported"); - } - - /// - /// Creates a client to access the server using the specified protocol - /// - /// Protocol - /// Server endpoint - /// Client - internal static ExClient GetClient(string protocol, string endpoint) - { - ExClient instance = null; - var cachee_key = $"{protocol}:{endpoint}"; - if (_clientInstances.ContainsKey(cachee_key)) - { - instance = _clientInstances[cachee_key]; - if (instance.Status == ZTransportStatus.Working) - { - return instance; - } - _clientInstances.TryRemove(cachee_key, out instance); - instance.Dispose(); - instance = null; - } - if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) - { - instance = new ExClient(new ZSocketClient(SocketExtensions.CreateIPEndPoint(endpoint))); - } - else - { - var key = protocol.Trim().ToLowerInvariant(); - if (_customClients.ContainsKey(key)) - { - instance = new ExClient((IZTransport)Activator.CreateInstance(_customClients[key], new object[] { endpoint })); - } - } - if (instance != null) - { - _clientInstances[cachee_key] = instance; - return instance; - } - throw new NotSupportedException($"Protocol {protocol} not supported"); - } - } -} \ No newline at end of file diff --git a/ZeroLevel.Microservices/Properties/AssemblyInfo.cs b/ZeroLevel.Microservices/Properties/AssemblyInfo.cs deleted file mode 100644 index 916d4b4..0000000 --- a/ZeroLevel.Microservices/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ZeroLevel.Microservices")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ZeroLevel.Microservices")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("6452d91a-2dac-4982-83af-77472051e81b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ZeroLevel.Microservices/ZeroLevel.Microservices.csproj b/ZeroLevel.Microservices/ZeroLevel.Microservices.csproj deleted file mode 100644 index 5df2e61..0000000 --- a/ZeroLevel.Microservices/ZeroLevel.Microservices.csproj +++ /dev/null @@ -1,71 +0,0 @@ - - - - - Debug - AnyCPU - {6452D91A-2DAC-4982-83AF-77472051E81B} - Library - Properties - ZeroLevel.Microservices - ZeroLevel.Microservices - v4.7.2 - 512 - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - {37020d8d-34e8-4ec3-a447-8396d5080457} - ZeroLevel - - - - - - - \ No newline at end of file diff --git a/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs deleted file mode 100644 index e69de29..0000000 diff --git a/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs deleted file mode 100644 index e69de29..0000000 diff --git a/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/ZeroLevel.Microservices/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs deleted file mode 100644 index e69de29..0000000 diff --git a/ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csproj.CoreCompileInputs.cache b/ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csproj.CoreCompileInputs.cache deleted file mode 100644 index 104314d..0000000 --- a/ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csproj.CoreCompileInputs.cache +++ /dev/null @@ -1 +0,0 @@ -48781ba1f58e845d50aedda0cbff5881dfe0563f diff --git a/ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csprojAssemblyReference.cache b/ZeroLevel.Microservices/obj/Debug/ZeroLevel.Microservices.csprojAssemblyReference.cache deleted file mode 100644 index 581de84f7197b7e3b550caed25d4298acbb1e68d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78235 zcmeI5349bq+Q!o%-AN5-h!>!^M!aCb3E>7sz;H!5lmH$Cagubx$YdtWOoCx$!CSmm z7w?so)z!uOSg-ZQ`@&-tU9V5YRd-dqFTD7kr@N<9lj>Oo%=gJ}t6<(vSNHpLPtCup z-mb3h&NK4z@-`rG%G4zv=7`DB+GHY?s85IYZ;r<5!qX$Ed8u$kB5C(4ooOdi(L{V? z`QUJQxPQ2RztW24Sh_iBkBr;R>0~6+EC^GpeEs z?E-wGlr=LFYqnE)d7V1tnP%srplwxVv~~~J=SoHYgM){S>dCzd?ExzaXiS){{A&k% zEDI)HF`^o~)R2rcmX1fMq)K}qJ#0vy>S=bpowVb%cIlW@%5Fr-+o@{5aI42-eS1M7 zIj=fAW!&_(xt2lUq2U45-VRpT$(Cp>zjCdeN`>oUF^lEY+>zUy)*Meq8|^T*9gW1I z3nTnZolO^E({np=(}y<3!jq!$`Oek^wpKotg&S=FcGZX5$%JDj*)4Xgx+WU09&6V$ zH?-wBZXvkUU?*p!a6nWi8WPP|FHzgvXvfp3>Iu>G#O4}Tt0_`DFVcWtWs1EZ4QzQ_ z9gxCzEgygbsJuEBt*MUN=|O{)75F=J#&#kdQW%Y?+C&l?cfL*+Y-V!%QrNsb-wKi) z`ZG?k)8UEfbd&Q1w#L?KJEWYvV}#J~2Pwve=5*wSxRI{dNQWMM6^VF#w4pia9(9%R zR5}uKzh4P9UDuJ{kL`$4lG_B8WLw=;S~d2-RP~sJXj`1hi}Tej1H!|dW3nmM+z^eY zs>enn4e>-O9j#RlFqY)D*hsWPzK&nXhAXP(Mv^Xu+hKF#vAG|w7Ff^x=PG7+&6;($Ze#=WNHFGN!4r)8md#+i`|!?l;&8+iva1 zZC6f3Y}VM6L;%5toH2@r84km)3}}d$V5B2zLuaD>DVo=sWt~;uh^Vq2kvWU3lVOOWej8J2EUrx{=B+*U zyzrhf_kRAtn*DBn!6|jI4>H8QG$UcG{a~bmG{h+8j)vJPD{i*NAS=%-h50WjwY&}0 z#S5ov+`6+xeB>rI{jwANNRZoD_YfICLIo;!=ddRSShOx zhtc71I?QVCzzSS-sHVegIvmm7ft9`LFozCD!dMX)`8$|w7&eBKpIFTod7Lz?3kAWGZBQ=xo8lbQ894EZoF#G{@7NKyxC^NiZc0Jedj^Rc_7~IT`Na6q=

v1#@mBHD*dd9I~( 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 BAQS)q diff --git a/ZeroLevel.Microservices/packages.config b/ZeroLevel.Microservices/packages.config deleted file mode 100644 index 97c22dc..0000000 --- a/ZeroLevel.Microservices/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/ZeroLevel.sln b/ZeroLevel.sln index aef504b..444fdaa 100644 --- a/ZeroLevel.sln +++ b/ZeroLevel.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.28307.421 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel", "ZeroLevel\ZeroLevel.csproj", "{37020D8D-34E8-4EC3-A447-8396D5080457}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.Microservices", "ZeroLevel.Microservices\ZeroLevel.Microservices.csproj", "{6452D91A-2DAC-4982-83AF-77472051E81B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.Discovery", "ZeroLevel.Discovery\ZeroLevel.Discovery.csproj", "{4F55B23F-938C-4DA2-B6DC-B6BC66D36073}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroExample", "ZeroExample\ZeroExample.csproj", "{50CEBEC2-2571-4592-AFD2-970BDB41947B}" @@ -33,18 +31,6 @@ Global {37020D8D-34E8-4EC3-A447-8396D5080457}.Release|x64.Build.0 = Release|Any CPU {37020D8D-34E8-4EC3-A447-8396D5080457}.Release|x86.ActiveCfg = Release|Any CPU {37020D8D-34E8-4EC3-A447-8396D5080457}.Release|x86.Build.0 = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|x64.ActiveCfg = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|x64.Build.0 = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|x86.ActiveCfg = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Debug|x86.Build.0 = Debug|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|Any CPU.Build.0 = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|x64.ActiveCfg = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|x64.Build.0 = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|x86.ActiveCfg = Release|Any CPU - {6452D91A-2DAC-4982-83AF-77472051E81B}.Release|x86.Build.0 = Release|Any CPU {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/ZeroLevel/Services/Network/Contract/IExClient.cs b/ZeroLevel/Services/Network/Contract/IExClient.cs index d267db6..a4f7193 100644 --- a/ZeroLevel/Services/Network/Contract/IExClient.cs +++ b/ZeroLevel/Services/Network/Contract/IExClient.cs @@ -5,9 +5,14 @@ using ZeroLevel.Models; namespace ZeroLevel.Services.Network { public interface IExClient + : IDisposable { event Action Connected; + void ForceConnect(); + + ZTransportStatus Status { get; } + IPEndPoint Endpoint { get; } InvokeResult Send(T obj); diff --git a/ZeroLevel.Discovery/ExchangeTransportFactory.cs b/ZeroLevel/Services/Network/ExchangeTransportFactory.cs similarity index 81% rename from ZeroLevel.Discovery/ExchangeTransportFactory.cs rename to ZeroLevel/Services/Network/ExchangeTransportFactory.cs index f46fd78..48c0806 100644 --- a/ZeroLevel.Discovery/ExchangeTransportFactory.cs +++ b/ZeroLevel/Services/Network/ExchangeTransportFactory.cs @@ -6,13 +6,13 @@ using ZeroLevel.Network.Microservices; using ZeroLevel.Services.Network; using ZeroLevel.Services.Network.Contract; -namespace ZeroLevel.Microservices +namespace ZeroLevel.Network { - internal static class ExchangeTransportFactory + public static class ExchangeTransportFactory { private static readonly Dictionary _customServers = new Dictionary(); private static readonly Dictionary _customClients = new Dictionary(); - private static readonly ConcurrentDictionary _clientInstances = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _clientInstances = new ConcurrentDictionary(); ///

/// Scanning the specified assembly to find the types that implement the IExchangeServer or IExchangeClient interfaces @@ -43,12 +43,12 @@ namespace ZeroLevel.Microservices /// /// Protocol /// Server - internal static ExService GetServer(string protocol) + public static IExService GetServer(string protocol, int port = -1) { ExService instance = null; if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) { - instance = new ExService(new ZExSocketObservableServer(new System.Net.IPEndPoint(IPFinder.GetNonLoopbackAddress(), IPFinder.GetFreeTcpPort()))); + instance = new ExService(new ZExSocketObservableServer(new System.Net.IPEndPoint(NetUtils.GetNonLoopbackAddress(), port == -1 ? NetUtils.GetFreeTcpPort() : port))); } else { @@ -64,16 +64,15 @@ namespace ZeroLevel.Microservices } throw new NotSupportedException($"Protocol {protocol} not supported"); } - /// /// Creates a client to access the server using the specified protocol /// /// Protocol /// Server endpoint /// Client - internal static ExClient GetClient(string protocol, string endpoint) + public static IExClient GetClientWithCache(string protocol, string endpoint) { - ExClient instance = null; + IExClient instance = null; var cachee_key = $"{protocol}:{endpoint}"; if (_clientInstances.ContainsKey(cachee_key)) { @@ -86,9 +85,17 @@ namespace ZeroLevel.Microservices instance.Dispose(); instance = null; } + instance = GetClient(protocol, endpoint); + _clientInstances[cachee_key] = instance; + return instance; + } + + public static IExClient GetClient(string protocol, string endpoint) + { + ExClient instance = null; if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) { - instance = new ExClient(new ZSocketClient(SocketExtensions.CreateIPEndPoint(endpoint))); + instance = new ExClient(new ZSocketClient(NetUtils.CreateIPEndPoint(endpoint))); } else { @@ -100,7 +107,6 @@ namespace ZeroLevel.Microservices } if (instance != null) { - _clientInstances[cachee_key] = instance; return instance; } throw new NotSupportedException($"Protocol {protocol} not supported"); diff --git a/ZeroLevel.Microservices/Model/Checkpoint.cs b/ZeroLevel/Services/Network/Microservices/Checkpoint.cs similarity index 98% rename from ZeroLevel.Microservices/Model/Checkpoint.cs rename to ZeroLevel/Services/Network/Microservices/Checkpoint.cs index 05d7401..7d313b1 100644 --- a/ZeroLevel.Microservices/Model/Checkpoint.cs +++ b/ZeroLevel/Services/Network/Microservices/Checkpoint.cs @@ -2,7 +2,7 @@ using System.Runtime.Serialization; using ZeroLevel.Services.Serialization; -namespace ZeroLevel.Microservices.Model +namespace ZeroLevel.Network.Microservices { [DataContract] public class Checkpoint : diff --git a/ZeroLevel.Microservices/Model/CheckpointArc.cs b/ZeroLevel/Services/Network/Microservices/CheckpointArc.cs similarity index 93% rename from ZeroLevel.Microservices/Model/CheckpointArc.cs rename to ZeroLevel/Services/Network/Microservices/CheckpointArc.cs index fad92bc..8d0d59d 100644 --- a/ZeroLevel.Microservices/Model/CheckpointArc.cs +++ b/ZeroLevel/Services/Network/Microservices/CheckpointArc.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace ZeroLevel.Microservices.Model +namespace ZeroLevel.Network.Microservices { [DataContract] public sealed class CheckpointArc diff --git a/ZeroLevel.Microservices/Model/CheckpointType.cs b/ZeroLevel/Services/Network/Microservices/CheckpointType.cs similarity index 73% rename from ZeroLevel.Microservices/Model/CheckpointType.cs rename to ZeroLevel/Services/Network/Microservices/CheckpointType.cs index 1f360f4..352b702 100644 --- a/ZeroLevel.Microservices/Model/CheckpointType.cs +++ b/ZeroLevel/Services/Network/Microservices/CheckpointType.cs @@ -1,4 +1,4 @@ -namespace ZeroLevel.Microservices.Model +namespace ZeroLevel.Network.Microservices { public enum CheckpointType { diff --git a/ZeroLevel.Microservices/WebApiDiscoveryClient.cs b/ZeroLevel/Services/Network/Microservices/DiscoveryClient.cs similarity index 54% rename from ZeroLevel.Microservices/WebApiDiscoveryClient.cs rename to ZeroLevel/Services/Network/Microservices/DiscoveryClient.cs index 5c5f440..8b52894 100644 --- a/ZeroLevel.Microservices/WebApiDiscoveryClient.cs +++ b/ZeroLevel/Services/Network/Microservices/DiscoveryClient.cs @@ -3,31 +3,16 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; -using ZeroLevel.Microservices.Contracts; using ZeroLevel.Models; +using ZeroLevel.Network; using ZeroLevel.Network.Microservices; -using ZeroLevel.ProxyREST; using ZeroLevel.Services.Collections; -namespace ZeroLevel.Microservices +namespace ZeroLevel.Services.Network.Microservices { - public sealed class WebApiDiscoveryClient : - BaseProxy, IDiscoveryClient + public class DiscoveryClient + : IDiscoveryClient { - #region WebAPI - - private IEnumerable GetRecords() - { - return GET>("api/v0/routes"); - } - - public InvokeResult Post(MicroserviceInfo info) - { - return POST("api/v0/routes", info); - } - - #endregion WebAPI - private readonly ConcurrentDictionary> _tableByKey = new ConcurrentDictionary>(); @@ -38,10 +23,11 @@ namespace ZeroLevel.Microservices new ConcurrentDictionary>(); private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + private readonly IExClient _discoveryServerClient; - public WebApiDiscoveryClient(string url) - : base(url) + public DiscoveryClient(string protocol, string endpoint) { + _discoveryServerClient = ExchangeTransportFactory.GetClient(protocol, endpoint); UpdateServiceListInfo(); Sheduller.RemindEvery(TimeSpan.FromSeconds(30), UpdateServiceListInfo); } @@ -79,63 +65,89 @@ namespace ZeroLevel.Microservices private void UpdateServiceListInfo() { - IEnumerable records; - try - { - records = GetRecords(); - } - catch (Exception ex) - { - Log.Error(ex, "[WebApiDiscoveryClient] Update service list error, discrovery service response is absent"); - return; - } - if (records == null) - { - Log.Warning("[WebApiDiscoveryClient] Update service list canceled, discrovery response is empty"); - return; - } - _lock.EnterWriteLock(); - try + _discoveryServerClient.ForceConnect(); + if (_discoveryServerClient.Status == ZTransportStatus.Working) { - _tableByGroups.Clear(); - _tableByTypes.Clear(); - var keysToRemove = new List(_tableByKey.Keys); - foreach (var info in records) + IEnumerable records = null; + try { - var key = info.ServiceKey.Trim().ToLowerInvariant(); - UpdateOrAddRecord(key, info); - keysToRemove.Remove(key); + var ir = _discoveryServerClient.Request>("services", response => records = response); + if (!ir.Success) + { + Log.Warning($"[DiscoveryClient] UpdateServiceListInfo. Error request to inbox 'services'. {ir.Comment}"); + return; + } } - RoundRobinCollection removed; - foreach (var key in keysToRemove) + catch (Exception ex) { - _tableByKey.TryRemove(key, out removed); - removed.Dispose(); + Log.Error(ex, "[DiscoveryClient] UpdateServiceListInfo. Discrovery service response is absent"); + return; + } + if (records == null) + { + Log.Warning("[DiscoveryClient] UpdateServiceListInfo. Discrovery response is empty"); + return; + } + _lock.EnterWriteLock(); + try + { + _tableByGroups.Clear(); + _tableByTypes.Clear(); + var keysToRemove = new List(_tableByKey.Keys); + foreach (var info in records) + { + var key = info.ServiceKey.Trim().ToLowerInvariant(); + UpdateOrAddRecord(key, info); + keysToRemove.Remove(key); + } + foreach (var key in keysToRemove) + { + _tableByKey.TryRemove(key, out RoundRobinCollection removed); + removed.Dispose(); + } + } + catch (Exception ex) + { + Log.Error(ex, "[DiscoveryClient] UpdateServiceListInfo. Update local routing table error."); + } + finally + { + _lock.ExitWriteLock(); } } - catch (Exception ex) - { - Log.Error(ex, "[WebApiDiscoveryClient] Update service list error"); - } - finally + else { - _lock.ExitWriteLock(); + Log.Warning("[DiscoveryClient] UpdateServiceListInfo. No connection to discovery server"); } } - public void Register(MicroserviceInfo info) + public bool Register(MicroserviceInfo info) { - try + _discoveryServerClient.ForceConnect(); + if (_discoveryServerClient.Status == ZTransportStatus.Working) { - var result = Post(info); - if (result.Success == false) + bool result = false; + try { - Log.Warning($"[WebApiDiscoveryClient] Service can't register. Discovery reason: {result.Comment}. Comment: {result.Comment}"); + _discoveryServerClient.Request("register", info, r => + { + result = r.Success; + if (!result) + { + Log.Warning($"[DiscoveryClient] Register canceled. Discovery reason: {r.Comment}. Comment: {r.Comment}"); + } + }); } + catch (Exception ex) + { + Log.Error(ex, "[DiscoveryClient] Register fault"); + } + return result; } - catch (Exception ex) + else { - Log.Error(ex, "[WebApiDiscoveryClient] Fault register"); + Log.Warning("[DiscoveryClient] Register. No connection to discovery server"); + return false; } } diff --git a/ZeroLevel.Microservices/ExServiceHost.cs b/ZeroLevel/Services/Network/Microservices/ExServiceHost.cs similarity index 98% rename from ZeroLevel.Microservices/ExServiceHost.cs rename to ZeroLevel/Services/Network/Microservices/ExServiceHost.cs index fa8d5b6..7f631e7 100644 --- a/ZeroLevel.Microservices/ExServiceHost.cs +++ b/ZeroLevel/Services/Network/Microservices/ExServiceHost.cs @@ -4,19 +4,19 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using ZeroLevel.Microservices.Contracts; +using ZeroLevel.Network; using ZeroLevel.Network.Microservices; using ZeroLevel.Services.Network; namespace ZeroLevel.Microservices { - internal sealed class ExServiceHost + public sealed class ExServiceHost : IDisposable { private class MetaService { public MicroserviceInfo ServiceInfo { get; set; } - public ExService Server { get; set; } + public IExService Server { get; set; } } private bool _disposed = false; @@ -26,13 +26,13 @@ namespace ZeroLevel.Microservices private readonly ConcurrentDictionary _services = new ConcurrentDictionary(); - internal ExServiceHost(IDiscoveryClient client) + public ExServiceHost(IDiscoveryClient client) { _discoveryClient = client; _registerTaskKey = Sheduller.RemindEvery(TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(15), RegisterServicesInDiscovery); } - internal IExService RegisterService(IExchangeService service) + public IExService RegisterService(IExchangeService service) { try { @@ -76,7 +76,7 @@ namespace ZeroLevel.Microservices } } - internal IExService RegisterService(MicroserviceInfo serviceInfo) + public IExService RegisterService(MicroserviceInfo serviceInfo) { try { diff --git a/ZeroLevel.Microservices/Exchange.cs b/ZeroLevel/Services/Network/Microservices/Exchange.cs similarity index 99% rename from ZeroLevel.Microservices/Exchange.cs rename to ZeroLevel/Services/Network/Microservices/Exchange.cs index 5b4d4e7..d61d83d 100644 --- a/ZeroLevel.Microservices/Exchange.cs +++ b/ZeroLevel/Services/Network/Microservices/Exchange.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using ZeroLevel.Microservices.Contracts; +using ZeroLevel.Network; using ZeroLevel.Network.Microservices; using ZeroLevel.Services.Network; diff --git a/ZeroLevel.Microservices/Contracts/IDiscoveryClient.cs b/ZeroLevel/Services/Network/Microservices/IDiscoveryClient.cs similarity index 83% rename from ZeroLevel.Microservices/Contracts/IDiscoveryClient.cs rename to ZeroLevel/Services/Network/Microservices/IDiscoveryClient.cs index 6bd1b3f..482dfd8 100644 --- a/ZeroLevel.Microservices/Contracts/IDiscoveryClient.cs +++ b/ZeroLevel/Services/Network/Microservices/IDiscoveryClient.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; using ZeroLevel.Network.Microservices; -namespace ZeroLevel.Microservices.Contracts +namespace ZeroLevel.Network { public interface IDiscoveryClient { - void Register(MicroserviceInfo info); + bool Register(MicroserviceInfo info); IEnumerable GetServiceEndpoints(string serviceKey); diff --git a/ZeroLevel.Microservices/Contracts/IExchangeService.cs b/ZeroLevel/Services/Network/Microservices/IExchangeService.cs similarity index 84% rename from ZeroLevel.Microservices/Contracts/IExchangeService.cs rename to ZeroLevel/Services/Network/Microservices/IExchangeService.cs index 67c4823..f54650c 100644 --- a/ZeroLevel.Microservices/Contracts/IExchangeService.cs +++ b/ZeroLevel/Services/Network/Microservices/IExchangeService.cs @@ -1,4 +1,4 @@ -namespace ZeroLevel.Microservices.Contracts +namespace ZeroLevel.Network { public interface IExchangeService { diff --git a/ZeroLevel/Services/Network/Models/MicroserviceInfo.cs b/ZeroLevel/Services/Network/Models/MicroserviceInfo.cs index c89c40b..3ad94fc 100644 --- a/ZeroLevel/Services/Network/Models/MicroserviceInfo.cs +++ b/ZeroLevel/Services/Network/Models/MicroserviceInfo.cs @@ -1,12 +1,13 @@ using System; using System.Runtime.Serialization; +using ZeroLevel.Services.Serialization; namespace ZeroLevel.Network.Microservices { [Serializable] [DataContract] public sealed class MicroserviceInfo : - IEquatable + IEquatable, IBinarySerializable { public const string DEFAULT_GROUP_NAME = "__service_default_group__"; public const string DEFAULT_TYPE_NAME = "__service_default_type__"; @@ -73,6 +74,26 @@ namespace ZeroLevel.Network.Microservices return this.ServiceKey.GetHashCode() ^ this.Protocol.GetHashCode() ^ this.Endpoint.GetHashCode(); } + public void Serialize(IBinaryWriter writer) + { + writer.WriteString(this.ServiceKey); + writer.WriteString(this.ServiceGroup); + writer.WriteString(this.ServiceType); + writer.WriteString(this.Protocol); + writer.WriteString(this.Endpoint); + writer.WriteString(this.Version); + } + + public void Deserialize(IBinaryReader reader) + { + this.ServiceKey = reader.ReadString(); + this.ServiceGroup = reader.ReadString(); + this.ServiceType = reader.ReadString(); + this.Protocol = reader.ReadString(); + this.Endpoint = reader.ReadString(); + this.Version = reader.ReadString(); + } + public override string ToString() { return $"{ServiceKey} ({Version})"; diff --git a/ZeroLevel/Services/Network/Services/IPFinder.cs b/ZeroLevel/Services/Network/NetUtils.cs similarity index 53% rename from ZeroLevel/Services/Network/Services/IPFinder.cs rename to ZeroLevel/Services/Network/NetUtils.cs index e3c4be6..d554b82 100644 --- a/ZeroLevel/Services/Network/Services/IPFinder.cs +++ b/ZeroLevel/Services/Network/NetUtils.cs @@ -1,12 +1,48 @@ using System; +using System.Globalization; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace ZeroLevel.Services.Network { - public static class IPFinder + public static class NetUtils { + public static int Compare(this IPEndPoint x, IPEndPoint y) + { + var xx = x.Address.ToString(); + var yy = y.Address.ToString(); + var result = string.CompareOrdinal(xx, yy); + return result == 0 ? x.Port.CompareTo(y.Port) : result; + } + + public static IPEndPoint CreateIPEndPoint(string endPoint) + { + string[] ep = endPoint.Split(':'); + if (ep.Length < 2) throw new FormatException("Invalid endpoint format"); + IPAddress ip; + if (ep.Length > 2) + { + if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip)) + { + throw new FormatException("Invalid ip-adress"); + } + } + else + { + if (!IPAddress.TryParse(ep[0], out ip)) + { + throw new FormatException("Invalid ip-adress"); + } + } + int port; + if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) + { + throw new FormatException("Invalid port"); + } + return new IPEndPoint(ip, port); + } + public static int GetFreeTcpPort() { TcpListener l = new TcpListener(IPAddress.Loopback, 0); diff --git a/ZeroLevel/Services/Network/Services/ExClient.cs b/ZeroLevel/Services/Network/Services/ExClient.cs index ca61457..713af59 100644 --- a/ZeroLevel/Services/Network/Services/ExClient.cs +++ b/ZeroLevel/Services/Network/Services/ExClient.cs @@ -6,8 +6,8 @@ using ZeroLevel.Services.Network.Services; namespace ZeroLevel.Services.Network { - public class ExClient - : ZBaseNetwork, IExClient, IZBackward, IDisposable + internal sealed class ExClient + : ZBaseNetwork, IExClient, IZBackward { private readonly IZTransport _transport; private readonly ExRouter _router; diff --git a/ZeroLevel/Services/Network/Services/ExService.cs b/ZeroLevel/Services/Network/Services/ExService.cs index d9a9857..b6bf69a 100644 --- a/ZeroLevel/Services/Network/Services/ExService.cs +++ b/ZeroLevel/Services/Network/Services/ExService.cs @@ -5,7 +5,7 @@ using ZeroLevel.Services.Network.Services; namespace ZeroLevel.Services.Network { - public class ExService + internal sealed class ExService : ZBaseNetwork, IExService { private readonly ExRouter _router; diff --git a/ZeroLevel/Services/Network/Services/ZExSocketObservableServer.cs b/ZeroLevel/Services/Network/Services/ZExSocketObservableServer.cs index 92d7fe2..11a2420 100644 --- a/ZeroLevel/Services/Network/Services/ZExSocketObservableServer.cs +++ b/ZeroLevel/Services/Network/Services/ZExSocketObservableServer.cs @@ -14,9 +14,9 @@ namespace ZeroLevel.Services.Network public IPEndPoint Endpoint => base.LocalEndpoint; - public event Action OnMessage = (f, c) => { }; + public event Action OnMessage = (_, __) => { }; - public event Func OnRequest = (f, c) => null; + public event Func OnRequest = (_, __) => null; protected override void Handle(Frame frame, IZBackward client) { diff --git a/ZeroLevel/Services/Network/SocketExtensions.cs b/ZeroLevel/Services/Network/SocketExtensions.cs deleted file mode 100644 index 306aaaa..0000000 --- a/ZeroLevel/Services/Network/SocketExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Globalization; -using System.Net; - -namespace ZeroLevel.Services.Network -{ - public static class SocketExtensions - { - public static int Compare(this IPEndPoint x, IPEndPoint y) - { - var xx = x.Address.ToString(); - var yy = y.Address.ToString(); - var result = string.CompareOrdinal(xx, yy); - return result == 0 ? x.Port.CompareTo(y.Port) : result; - } - - public static IPEndPoint CreateIPEndPoint(string endPoint) - { - string[] ep = endPoint.Split(':'); - if (ep.Length < 2) throw new FormatException("Invalid endpoint format"); - IPAddress ip; - if (ep.Length > 2) - { - if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip)) - { - throw new FormatException("Invalid ip-adress"); - } - } - else - { - if (!IPAddress.TryParse(ep[0], out ip)) - { - throw new FormatException("Invalid ip-adress"); - } - } - int port; - if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) - { - throw new FormatException("Invalid port"); - } - return new IPEndPoint(ip, port); - } - } -} \ No newline at end of file diff --git a/ZeroLevel/ZeroLevel.csproj b/ZeroLevel/ZeroLevel.csproj index db88542..c1ee42e 100644 --- a/ZeroLevel/ZeroLevel.csproj +++ b/ZeroLevel/ZeroLevel.csproj @@ -238,6 +238,15 @@ + + + + + + + + + @@ -251,11 +260,10 @@ - + - diff --git a/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache b/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache index e77e86a..5d7709e 100644 --- a/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache +++ b/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -7dc74ae62ea3925694bcfe614d7c1f201cc0d873 +34e7ecccf08c9607e57fb18cb5dd41e7bc1a3610 diff --git a/ZeroLevel/obj/Debug/ZeroLevel.csprojAssemblyReference.cache b/ZeroLevel/obj/Debug/ZeroLevel.csprojAssemblyReference.cache index 55850f9cfb6e9bd6556534aa992dbacb5b18550a..a0c6a033da8691069448b36902d5e7ba48590eab 100644 GIT binary patch delta 1221 zcmZXTO=uHQ6ouy%8v3S-DpFg`Lc6J0G>aG^ib&eTpVZp1R9tmoEg=StBS~FUkm643 zFU+b71<{2Ih01_}3qjO^wxSl);!mhr(SR*P7cK%yKQ-PGO>!k82?ZtW8xyWZ!Hspnb=kS?dFl+%dQ0#9?PoBY(MN__$91&X`W zmsB>oFB(Y=4iD<`6~Hr9@PF<`KX=0tETX*l|z=2hg;V@k4vMbaan@tX-?xZ zcbcxfLNHvXN45sI;J4WjYOjpn^vybTs W`in$wsjIJ8M&EuN-NUaGjsF0JlvWJ@ delta 1145 zcmZXTPe@cz6vjOhBfcvlr7;sKq!na~5rzpYl>A?gB9#&ZwHQSvDH(9wTDf8x<1 z7cOkmqCk0qn>LX`8P-5HQ3{$-;y=a~?V{KDPR-*z?t}U9&Ue4_aqoR+mZ#|X6PkHj z?emXVmrFXyOjkD_QvUl=48NkBoZQa4$-&-!Wh`)EEHbhW4f7kF|6|*IwrxYDb6niw z0xqQ#NDr7-u$cRr<-Go6Ph#LsU$-*eAaF?wJnIB?wFIig7Z12|A@@AmRae}JgsMbM&`Ja`Gw2uUKIWLOw1%L& zAz=NkjZ=7sUCy2CqHj;@D{}W8u^wF*A+6^?;k57@Xq{|mAUZJPjdjeY!foN1 zCMdUs&xHHJP&4#|a7Or37;b@{6wZOxua*F!3oc=yLpUx>2@khIzbZ6^E5f7Em#lw^ zVl~(XUKdUZSB0hR&~FN-gzN3$;zImK^7w1}=7(-vI~LivM~mjei@_p{x>sK^XQRPN zjPhgl<1r5Y-((@?*XvG+8w0AlF_~U>THF{t-Hmzky4S>wdD7h&C9iu^&Vz~Z>RX~? XBE0$@>j9rXV`e(K6i%4oALaiAhzv{-