mirror of https://github.com/ogoun/Zero.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
8.1 KiB
211 lines
8.1 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Threading;
|
|
using ZeroLevel.Models;
|
|
using ZeroLevel.Services.Collections;
|
|
|
|
namespace ZeroLevel.Network
|
|
{
|
|
public class DiscoveryClient
|
|
: IDiscoveryClient
|
|
{
|
|
private sealed class DCRouter:
|
|
IDisposable
|
|
{
|
|
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
|
private IEnumerable<ServiceEndpointInfo> _empty = Enumerable.Empty<ServiceEndpointInfo>();
|
|
private List<ServiceEndpointInfo> _services = new List<ServiceEndpointInfo>();
|
|
|
|
private Dictionary<string, RoundRobinCollection<ServiceEndpointInfo>> _tableByKey;
|
|
private Dictionary<string, RoundRobinCollection<ServiceEndpointInfo>> _tableByGroups;
|
|
private Dictionary<string, RoundRobinCollection<ServiceEndpointInfo>> _tableByTypes;
|
|
|
|
internal void Update(IEnumerable<ServiceEndpointsInfo> records)
|
|
{
|
|
if (records == null)
|
|
{
|
|
Log.Warning("[DiscoveryClient] UpdateServiceListInfo. Discrovery response is empty");
|
|
return;
|
|
}
|
|
var services = new List<ServiceEndpointInfo>();
|
|
foreach (var service in records)
|
|
{
|
|
var key = service.ServiceKey.ToUpperInvariant();
|
|
var type = service.ServiceType.ToUpperInvariant();
|
|
var group = service.ServiceGroup.ToUpperInvariant();
|
|
services.AddRange(service.Endpoints.Select(e => new ServiceEndpointInfo { Endpoint = e, Group = group, Key = key, Type = type }));
|
|
}
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_services = services;
|
|
_tableByKey = _services.GroupBy(r => r.Key).ToDictionary(g => g.Key, g => new RoundRobinCollection<ServiceEndpointInfo>(g));
|
|
_tableByTypes = _services.GroupBy(r => r.Type).ToDictionary(g => g.Key, g => new RoundRobinCollection<ServiceEndpointInfo>(g));
|
|
_tableByGroups = _services.GroupBy(r => r.Group).ToDictionary(g => g.Key, g => new RoundRobinCollection<ServiceEndpointInfo>(g));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "[DiscoveryClient] UpdateServiceListInfo. Update local routing table error.");
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
public ServiceEndpointInfo GetService(string serviceKey, string endpoint)
|
|
{
|
|
var key = serviceKey.ToUpperInvariant();
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
if (_tableByKey.ContainsKey(key) && _tableByKey[key].Count > 0)
|
|
{
|
|
return _tableByKey[key].Find(s => s.Endpoint.Equals(endpoint, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitReadLock();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpoints(string serviceKey)
|
|
{
|
|
var key = serviceKey.Trim().ToUpperInvariant();
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
if (_tableByKey.ContainsKey(key) && _tableByKey[key].Count > 0)
|
|
{
|
|
return _tableByKey[key].GetCurrentSeq();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitReadLock();
|
|
}
|
|
return _empty;
|
|
}
|
|
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpointsByGroup(string serviceGroup)
|
|
{
|
|
var group = serviceGroup.Trim().ToUpperInvariant();
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
if (_tableByGroups.ContainsKey(group) && _tableByGroups[group].Count > 0)
|
|
{
|
|
return _tableByGroups[group].GetCurrentSeq();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitReadLock();
|
|
}
|
|
return _empty;
|
|
}
|
|
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpointsByType(string serviceType)
|
|
{
|
|
var type = serviceType.Trim().ToUpperInvariant();
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
if (_tableByTypes.ContainsKey(type) && _tableByTypes[type].Count > 0)
|
|
{
|
|
return _tableByTypes[type].GetCurrentSeq();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitReadLock();
|
|
}
|
|
return _empty;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_lock.Dispose();
|
|
}
|
|
}
|
|
|
|
private readonly DCRouter _router = new DCRouter();
|
|
private readonly ExClient _discoveryServerClient;
|
|
|
|
public DiscoveryClient(ExClient client)
|
|
{
|
|
_discoveryServerClient = client;
|
|
UpdateServiceListInfo();
|
|
Sheduller.RemindEvery(TimeSpan.FromSeconds(30), UpdateServiceListInfo);
|
|
}
|
|
|
|
private void UpdateServiceListInfo()
|
|
{
|
|
_discoveryServerClient.ForceConnect();
|
|
if (_discoveryServerClient.Status == SocketClientStatus.Working)
|
|
{
|
|
try
|
|
{
|
|
var ir = _discoveryServerClient.Request<IEnumerable<ServiceEndpointsInfo>>("services", records => _router.Update(records));
|
|
if (!ir.Success)
|
|
{
|
|
Log.Warning($"[DiscoveryClient] UpdateServiceListInfo. Error request to inbox 'services'. {ir.Comment}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "[DiscoveryClient] UpdateServiceListInfo. Discrovery service response is absent");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Warning("[DiscoveryClient] UpdateServiceListInfo. No connection to discovery server");
|
|
}
|
|
}
|
|
|
|
public bool Register(ZeroServiceInfo info)
|
|
{
|
|
_discoveryServerClient.ForceConnect();
|
|
if (_discoveryServerClient.Status == SocketClientStatus.Working)
|
|
{
|
|
bool result = false;
|
|
try
|
|
{
|
|
_discoveryServerClient.Request<ZeroServiceInfo, InvokeResult>("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;
|
|
}
|
|
else
|
|
{
|
|
Log.Warning("[DiscoveryClient] Register. No connection to discovery server");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpoints(string serviceKey) => _router.GetServiceEndpoints(serviceKey);
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpointsByGroup(string serviceGroup) => _router.GetServiceEndpointsByGroup(serviceGroup);
|
|
public IEnumerable<ServiceEndpointInfo> GetServiceEndpointsByType(string serviceType) => _router.GetServiceEndpointsByType(serviceType);
|
|
public ServiceEndpointInfo GetService(string serviceKey, string endpoint) => _router.GetService(serviceKey, endpoint);
|
|
|
|
public void Dispose()
|
|
{
|
|
_router.Dispose();
|
|
_discoveryServerClient.Dispose();
|
|
}
|
|
}
|
|
} |