using linker.libs;
using linker.libs.timer;
using linker.messenger.signin.args;
using System.Collections.Concurrent;
using System.Net;
namespace linker.messenger.signin
{
///
/// 登录缓存
///
public sealed class SignInServerCaching
{
private readonly SignInArgsTransfer signInArgsTransfer;
private readonly ISignInServerStore signInStore;
public ConcurrentDictionary Clients { get; set; } = new ConcurrentDictionary();
public SignInServerCaching(ISignInServerStore signInStore, SignInArgsTransfer signInArgsTransfer)
{
this.signInStore = signInStore;
this.signInArgsTransfer = signInArgsTransfer;
try
{
foreach (var item in signInStore.Find())
{
item.Connected = false;
Clients.TryAdd(item.MachineId, item);
}
}
catch (Exception)
{
}
ClearTask();
}
public async Task Sign(SignInfo signInfo)
{
if (string.IsNullOrWhiteSpace(signInfo.MachineId))
{
signInfo.MachineId = signInStore.NewId();
}
bool has = Clients.TryGetValue(signInfo.MachineId, out SignCacheInfo cache);
if (has == false)
{
cache = new SignCacheInfo();
}
//参数验证失败
string verifyResult = await signInArgsTransfer.Validate(signInfo, cache).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(verifyResult) == false)
{
cache.Connected = false;
return verifyResult;
}
//无限制,则挤压下线
cache.Connection?.Disponse(9);
if (has == false)
{
cache.Id = signInfo.MachineId;
cache.MachineId = signInfo.MachineId;
signInStore.Insert(cache);
signInStore.Confirm();
Clients.TryAdd(signInfo.MachineId, cache);
}
signInfo.Connection.Id = signInfo.MachineId;
signInfo.Connection.Name = signInfo.MachineName;
cache.MachineName = signInfo.MachineName;
cache.Connection = signInfo.Connection;
cache.Version = signInfo.Version;
cache.Args = signInfo.Args;
cache.GroupId = signInfo.GroupId;
signInStore.Update(cache);
signInStore.Confirm();
return string.Empty;
}
public bool TryGet(string machineId, out SignCacheInfo cache)
{
if (machineId == null)
{
cache = null;
return false;
}
return Clients.TryGetValue(machineId, out cache);
}
public bool TryGet(string from, string to, out SignCacheInfo fromValue, out SignCacheInfo toValue)
{
fromValue = null;
toValue = null;
if (from == null || to == null)
{
return false;
}
return Clients.TryGetValue(from, out fromValue) && Clients.TryGetValue(to, out toValue) && fromValue.SameGroup(toValue);
}
public List Get()
{
return Clients.Values.ToList();
}
public List Get(SignCacheInfo other)
{
return Clients.Values.Where(c => c.GroupId == other.GroupId).ToList();
}
public bool GetOnline(string machineId)
{
return Clients.TryGetValue(machineId, out SignCacheInfo cache) && cache.Connected;
}
public void GetOnline(out int all, out int online)
{
all = Clients.Count;
online = Clients.Values.Count(c => c.Connected);
}
public bool TryRemove(string machineId, out SignCacheInfo cache)
{
if (Clients.TryRemove(machineId, out cache))
{
signInStore.Delete(cache.Id);
signInStore.Confirm();
}
return true;
}
public string NewId()
{
return signInStore.NewId();
}
public bool Exp(string machineId)
{
return signInStore.Exp(machineId);
}
private void ClearTask()
{
TimerHelper.SetIntervalLong(() =>
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Debug($"start cleaning up clients that have exceeded the {signInStore.CleanDays}-day timeout period");
}
try
{
DateTime now = DateTime.Now;
var groups = Clients.Values.GroupBy(c => c.GroupId)
.Where(group => group.All(info => info.Connected == false && (now - info.LastSignIn).TotalDays > signInStore.CleanDays))
.Select(group => group.Key).ToList();
if (groups.Count > 0)
{
var items = Clients.Values.Where(c => groups.Contains(c.GroupId)).ToList();
foreach (var item in items)
{
Clients.TryRemove(item.MachineId, out _);
signInStore.Delete(item.Id);
}
signInStore.Confirm();
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Debug($"cleaning up clients error {ex}");
}
}, 5 * 60 * 1000);
}
}
///
/// 登录缓存对象
///
public sealed class SignCacheInfo
{
public string Id { get; set; }
///
/// 客户端id
///
public string MachineId { get; set; }
///
/// 客户端名
///
public string MachineName { get; set; }
///
/// 客户端版本
///
public string Version { get; set; } = "v1.0.0";
///
/// 分组编号
///
public string GroupId { get; set; } = Helper.GlobalString;
///
/// 最后登录
///
public DateTime LastSignIn { get; set; } = DateTime.Now;
///
/// 额外参数,就是ISignInArgs
///
public Dictionary Args { get; set; } = new Dictionary();
private IPEndPoint ip = new IPEndPoint(IPAddress.Any, 0);
public IPEndPoint IP
{
get
{
if (Connection != null)
{
ip = Connection.Address;
}
return ip;
}
set
{
ip = value;
}
}
private bool connected;
public bool Connected
{
get
{
if (Connection != null)
{
connected = Connection.Connected == true;
}
return connected;
}
set
{
connected = value;
}
}
///
/// 连接对象
///
public IConnection Connection { get; set; }
public uint Order { get; set; } = int.MaxValue;
public bool SameGroup(SignCacheInfo other)
{
return this.GroupId == other.GroupId;
}
}
///
/// 登录参数
///
public sealed class SignInfo
{
public string MachineId { get; set; } = string.Empty;
public string MachineName { get; set; } = string.Empty;
public string GroupId { get; set; } = string.Empty;
public string Version { get; set; } = string.Empty;
public Dictionary Args { get; set; } = new Dictionary();
public IConnection Connection { get; set; }
}
}