using DeepCore;
using DeepCore.IO;
using DeepCore.Log;
using DeepCore.Reflection;
using DeepCrystal.FuckPomeloServer;
using DeepCrystal.ORM.Generic;
using DeepCrystal.RPC;
using DeepMMO.Data;
using DeepMMO.Protocol.Client;
using DeepMMO.Server.SystemMessage;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace DeepMMO.Server.Gate
{
public class GateServer : IService
{
///
/// 控制账号是否可以登录,默认为false,特殊权限账号忽略该配置.
///
private bool mServerOpenFlag = false;
public bool ServerOpenFlag { get => mServerOpenFlag; set => mServerOpenFlag = value; }
private static Random random = new Random();
protected readonly Logger log;
protected readonly IServer acceptor;
protected readonly ConnectorNodeMap groupMap;
protected IRemoteNodeInfo[] realmNodes;
protected bool isReady = false;
///
/// 最小连接数量,由GM系统控制。
///
public static int MIN_CLIENT_NUMBER_SOFT_LIMIT = 50;
///
/// 最大连接数量,由GM系统控制。
///
public static int MAX_CLIENT_NUMBER_SOFT_LIMIT = 100;
///
/// 最大连接数量,由GM系统控制。
///
public static int CLIENT_NUMBER_HARD_LIMIT = 100;
///
/// 最大连接数量软限制,由GM系统控制。
///
public static int CLIENT_NUMBER_SOFT_LIMIT = 10;
///
/// 排队的最大数量限制,由GM系统控制。
///
public static int QUEUE_MAX_LIMIT = 1;
///
/// 每一名角色增加时间,由GM系统控制。
///
public static int QUEUE_ADD_TIME = 30;
///
/// 每一名角色增加时间,由GM系统控制。
///
public static int QUEUE_MAX_HARD_ADD_TIME = 300;
///
/// 间隔数量
///
public static int POST_SERVER_NUMBER_INTERVAL = 5;
///
/// 软进入百分比
///
public static float SOFT_ENTER_PERCENTAGE = 0.1f;
///
/// 硬进入百分比
///
public static float HARD_ENTER_PERCENTAGE = 0.1f;
///
/// 硬进入最大百分比
///
public static float MAX_HARD_ENTER_PERCENTAGE = 0.08f;
//------------------------------------------------------------------------------------------
//public override bool IsConcurrent => false;
//------------------------------------------------------------------------------------------
public GateServer(ServiceStartInfo start) : base(start)
{
var factory = ServerFactory.Instance;
var codec = ReflectionUtil.CreateInterface(start.Config["NetCodec"].ToString());
this.log = LoggerFactory.GetLogger(start.Address.FullPath);
if (!string.IsNullOrEmpty(DeepMMO.Server.GlobalConfig.ReplaceNetHost))
{
start.Config["Host"] = DeepMMO.Server.GlobalConfig.ReplaceNetHost;
}
this.acceptor = factory.CreateServer(new HashMap(start.Config), codec);
this.acceptor.OnSessionConnected += Acceptor_OnSessionConnected;
this.acceptor.OnSessionDisconnected += Acceptor_OnSessionDisconnected;
this.acceptor.OnServerError += Acceptor_OnServerError;
this.groupMap = new ConnectorNodeMap(log);
// H.Q.Cai 添加代码开始
start.Config.TryGetAsInt("ClientNumberHardLimit", out CLIENT_NUMBER_HARD_LIMIT);
start.Config.TryGetAsInt("ClientNumberSoftLimit", out CLIENT_NUMBER_SOFT_LIMIT);
start.Config.TryGetAsInt("QueueMaxLimit", out QUEUE_MAX_LIMIT);
start.Config.TryGetAsInt("QueueAddTime", out QUEUE_ADD_TIME);
start.Config.TryGetAsInt("QueueMaxHardAddTime", out QUEUE_MAX_HARD_ADD_TIME);
start.Config.TryGetAsInt("PostServerNumberInterval", out POST_SERVER_NUMBER_INTERVAL);
start.Config.TryGetAsFloat("SoftEnterPercentage", out SOFT_ENTER_PERCENTAGE);
start.Config.TryGetAsFloat("HardEnterPercentage", out HARD_ENTER_PERCENTAGE);
start.Config.TryGetAsFloat("MaxHardEnterPercentage", out MAX_HARD_ENTER_PERCENTAGE);
if(start.Config.TryGetAsInt("MinClientNumberSoftLimit", out var minClientNumberSoftLimit))
{
MIN_CLIENT_NUMBER_SOFT_LIMIT = minClientNumberSoftLimit;
}
if (start.Config.TryGetAsInt("MaxClientNumberSoftLimit", out var maxClientNumberSoftLimit))
{
MAX_CLIENT_NUMBER_SOFT_LIMIT = maxClientNumberSoftLimit;
}
// H.Q.Cai 添加代码结束
}
protected override void OnDisposed()
{
this.groupMap.Dispose();
}
protected override Task OnStartAsync()
{
foreach (var server in RPGServerTemplateManager.Instance.GetAllServers())
{
log.WarnFormat("Templates Server:{0} Group:{1} State:{2}", server.id, server.group, server.state);
}
var interval = TimeSpan.FromSeconds(TimerConfig.timer_sec_GateUpdateQueue);
//var interval = TimeSpan.FromSeconds(3);
this.Provider.CreateTimer(UpdateInQueue, this, interval, interval);
return Task.CompletedTask;
}
protected override Task OnStopAsync(ServiceStopInfo reason)
{
this.acceptor.Dispose();
return Task.FromResult(0);
}
public override bool GetState(TextWriter output)
{
this.groupMap.WriteStatus(output);
return true;
}
//------------------------------------------------------------------------------------------
[RpcHandler(typeof(SystemShutdownNotify))]
public virtual void rpc_HandleSystem(SystemShutdownNotify shutdown)
{
this.acceptor.StopAsync(shutdown.reason);
}
[RpcHandler(typeof(SystemGateReloadServerList))]
public virtual void rpc_HandleReloadServerList(SystemGateReloadServerList reload)
{
this.groupMap.ReloadServerGroups();
}
[RpcHandler(typeof(SystemStaticServicesStartedNotify))]
public virtual void rpc_HandleSystem(SystemStaticServicesStartedNotify shutdown)
{
base.Execute(async () =>
{
using (var log = StringBuilderObjectPool.AllocAutoRelease())
{
log.WriteLine(CUtils.SequenceChar('-', 100));
log.WriteLine("- 获取查询远端服务示例");
log.WriteLine(CUtils.SequenceChar('-', 100));
{
log.WriteLine("Provider.GetServicesWithAddressPatternAsync(\"\\w+@\\w+@ConnectServer\")");
var svcs = await base.Provider.GetServicesWithAddressPatternAsync(@"\w+@\w+@ConnectServer");
foreach (var svc in svcs) { log.WriteLine(svc); }
}
log.WriteLine(CUtils.SequenceChar('-', 100));
{
log.WriteLine("Provider.GetServicesWithInfoLinqAsync(\"Address.ServiceType =\\\"AreaService\\\"\", \"Address.ServiceName\")");
var svcs = await base.Provider.GetServicesWithInfoLinqAsync("Address.ServiceType=\"AreaService\"", "Address.ServiceName");
foreach (var svc in svcs) { log.WriteLine(svc); }
}
log.WriteLine(CUtils.SequenceChar('-', 100));
{
log.WriteLine("Provider.GetStaticServicesAsync()");
var svcs = await base.Provider.GetStaticServicesAsync();
foreach (var svc in svcs) { log.WriteLine(svc); }
}
log.WriteLine(CUtils.SequenceChar('-', 100));
{
log.WriteLine("Provider.FindStaticServiceWithTypeAsync(\"RankingService\")");
log.WriteLine("根据分组1,获取Ranking服务分片");
var group = 1;
var svc = await base.Provider.FindStaticServiceWithTypeAsync(ServerNames.RankingServiceType, (list) =>
{
if (list.Length == 1) return list[0];
if (list.Length > 0)
{
var rank_group = (group % list.Length).ToString();
return Array.Find(list, e =>
{
return e.Config["IndexId"] == rank_group;
});
}
return null;
});
log.WriteLine(svc);
}
log.WriteLine(CUtils.SequenceChar('-', 100));
this.log.Info("\n" + log.ToString());
}
});
}
//------------------------------------------------------------------------------------------
[RpcHandler(typeof(Ping), typeof(Pong))]
public virtual Task rpc_OnHandlePing(Ping msg)
{
log.Info("ping index = " + msg.index);
//log.Info("on rpc_OnHandle All : " + msg);
//await Task.Delay(random.Next()%1000);
return Task.FromResult(new Pong() { time = msg.time, index = msg.index });
}
[RpcHandler(typeof(SyncConnectToGateNotify), ServerNames.ConnectServerType)]
public virtual void rpc_OnHandleConnector(SyncConnectToGateNotify msg)
{
// log.Info("on SyncConnectToGateNotify : " + msg.connectAddress);
if (groupMap.SyncConnect(msg))
{
if (isReady == false)
{
isReady = true;
this.acceptor.StartAsync();
log.Info($"Gate Service Is Ready ! Port={this.StartConfig["Port"]}");
}
}
this.LogState();
}
//------------------------------------------------------------------------------------------
[RpcHandler(typeof(SyncGateServerOpen))]
public virtual void rpc_HandleSystem(SyncGateServerOpen notify)
{
this.ServerOpenFlag = notify.status;
}
[RpcHandler(typeof(SyncGateClientNumberLimit))]
public virtual void rpc_HandleClientLimit(SyncGateClientNumberLimit notify)
{
this.groupMap.SetClientLimit(notify);
}
[RpcHandler(typeof(SyncGateClientAccountExpire), ServerNames.LogicServiceType)]
public virtual void rpc_HandleClientLimit(SyncGateClientAccountExpire notify)
{
PushOtherAccountExpire(notify.accountUUid, notify.ExpectTime);
}
//------------------------------------------------------------------------------------------
///
/// 选择最优服务器
///
///
protected virtual async Task SelectConnectAsync(ClientEnterGateRequest login, ISession session)
{
//log.Log(login);
try
{
//账号/密码/客户端信息为空//
if (string.IsNullOrEmpty(login.c2s_account) || string.IsNullOrEmpty(login.c2s_token) || login.c2s_clientInfo == null)
{
log.Warn("账号/密码/客户端信息为空");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_ACCOUNT_OR_PASSWORD,
});
}
//login.c2s_serverID = "19";
//ServerGroup是否存在//
var serverGroupID = RPGServerTemplateManager.Instance.GetServerGroupID(login.c2s_serverID);
if (serverGroupID == null)
{
log.Warn("ServerGroup不存在");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_SERVER_NOT_OPEN,
});
}
//第三方/一号通验证//
var serverPassportResult = await RPGServerManager.Instance.Passport.VerifyAsync(login);
//保存渠道Account.
string platformAccount = login.c2s_account;
if (serverPassportResult.Verified == false)
{
log.Warn("一号通验证失败");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_ACCOUNT_OR_PASSWORD,
});
}
//统一登陆用户名,解决多渠道名称冲突//
var accountUUID = await RPGServerManager.Instance.Passport.FormatAccountAsync(login);
if (accountUUID == null)
{
log.Warn("AccountID不合法");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_ACCOUNT_OR_PASSWORD,
});
}
using (var saveAcc = new MappingReference(RPGServerPersistenceManager.TYPE_ACCOUNT_DATA, accountUUID, this))
{
var accountData = await RPGServerPersistenceManager.Instance.GetOrCreateAccountDataAsync(saveAcc, accountUUID, login.c2s_token);
if (accountData == null)
{
log.Warn("无法创建账号");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_NO_ACCOUNT,
});
}
//特殊密码进入游戏时,修改权限.
if (accountData.lastLoginServerID == null && serverPassportResult.Privilege != 0)
{
accountData.privilege = (RolePrivilege)serverPassportResult.Privilege;
saveAcc.SetField(nameof(AccountData.privilege), accountData.privilege);
}
//var privilege = accountData.privilege;
//是否有白名单权限.//
bool hasPrivilege = RPGServerTemplateManager.Instance.IsValidOfPrivilege((int)accountData.privilege, "white_list");
//服务器状态是否开启.//
if (!hasPrivilege && !ServerOpenFlag)
{
log.Warn("服务器未开启");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_SERVER_NOT_OPEN,
});
}
//获取Connector负载//
if (!groupMap.TryDispatchConnect(serverGroupID, accountData.lastLoginConnectAddress, out var group, out var connect, out var inQueue, out var queueCount, out var inMaxQueue))
{
log.Warn("没有可用服务器");
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = ClientEnterGateResponse.CODE_NO_CONNECT_SERVER,
});
}
var loginToken = CMD5.CalculateMD5(random.Next().ToString() + accountUUID);
saveAcc.SetField(nameof(AccountData.lastLoginRemoteAddress), session.RemoteAddress.ToString());
saveAcc.SetField(nameof(AccountData.lastLoginTime), DateTime.Now);
saveAcc.SetField(nameof(AccountData.lastLoginConnectAddress), connect.Sync.connectServiceAddress);
saveAcc.SetField(nameof(AccountData.lastLoginToken), loginToken);
saveAcc.SetField(nameof(AccountData.lastLoginServerID), login.c2s_serverID);
saveAcc.SetField(nameof(AccountData.lastLoginServerGroupID), serverGroupID);
await saveAcc.FlushAsync();
//角色列表//
List roleList = new List();
using (var accountRoleSnapSave = new MappingReference(RPGServerPersistenceManager.TYPE_ACCOUNT_ROLE_SNAP_DATA, accountUUID, this))
{
var accountRoleSnap = await accountRoleSnapSave.LoadOrCreateDataAsync(() => new AccountRoleSnap());
foreach (var item in accountRoleSnap.roleIDMap)
{
roleList.Add(item.Value);
}
}
//软性连接数限制//
var isContains = ContainsAccount(session, accountUUID);
var s2c_code = ClientEnterGateResponse.CODE_OK;
if (inQueue && isContains == false)
{
s2c_code = ClientEnterGateResponse.CODE_OK_IN_QUEUE;
}
//if (inMaxQueue && isContains == false)
//{
// s2c_code = ClientEnterGateResponse.CODE_SERVER_MAX_QUEUE;
//}
return new EnterToken(login, new ClientEnterGateResponse()
{
s2c_code = s2c_code,
s2c_accountUUID = accountUUID,
s2c_connectHost = connect.Sync.connectHost,
s2c_connectPort = connect.Sync.connectPort,
s2c_connectToken = connect.Sync.connectToken,
s2c_lastLoginToken = accountData.lastLoginToken,
s2c_lastLoginRoleID = accountData.lastLoginRoleID,
s2c_platformAccount = platformAccount,
s2c_roleIDList = roleList,
s2c_queueCount = queueCount,
s2c_queuetTime = TimeSpan.FromSeconds(10),
}, group, connect, saveAcc.Data);
}
}
catch (Exception err)
{
log.Error(err.Message, err);
throw;
}
}
//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------
public class ConnectorNodeMap : Disposable
{
protected Logger log;
private ReaderWriterLockSlim connect_lock = new ReaderWriterLockSlim();
// 强制ServerGroup进入指定Node
private ValueSortedMap groupMap;
// 用于记录老的Session重新连接后,匹配到之前进入的Node信息
private ValueSortedMap nodeMap;
// 所有Connector信息
private ValueSortedMap connectorMap;
public ConnectorNodeMap(Logger log)
{
this.log = log;
this.groupMap = new ValueSortedMap((a, b) => a.ClientNumber - b.ClientNumber);
this.nodeMap = new ValueSortedMap((a, b) => a.ClientNumber - b.ClientNumber);
this.connectorMap = new ValueSortedMap((a, b) => a.ClientNumber - b.ClientNumber);
this.ReloadServerGroups();
}
public void ReloadServerGroups()
{
log.Warn("ConnectorNodeMap: ReloadServerGroups");
using (connect_lock.EnterWrite())
{
foreach (var server in RPGServerTemplateManager.Instance.GetAllServers())
{
var group = groupMap.GetOrAdd(server.group, (g) => new GroupInfo(g));
if (server.nodes != null)
{
foreach (var node in server.nodes)
{
if (!string.IsNullOrEmpty(node))
{
var nodeConnectors = nodeMap.GetOrAdd(node, (name) => new NodeInfo(name));
group.BindNode(nodeConnectors);
}
}
}
}
}
}
protected override void Disposing()
{
connect_lock.Dispose();
}
public void SetClientLimit(SyncGateClientNumberLimit notify)
{
using (connect_lock.EnterWrite())
{
if (groupMap.TryGetValue(notify.serverGroupID, out var group))
{
// H.Q.Cai 修改开始
//group.SetClientLimit(notify.clientLimit);
group.SetClientLimit(notify.clientLimit, notify.clientSoftLimit, notify.queueMaxLimit, notify.queueAddTime);
// H.Q.Cai 修改结束
}
}
}
public bool SyncConnect(SyncConnectToGateNotify msg)
{
var msgAddr = RemoteAddress.Parse(msg.connectServiceAddress);
using (connect_lock.EnterWrite())
{
bool ret = false;
//纯数据同步//
{
var exist = connectorMap.TryGetOrCreate(msg.connectServiceAddress, out var conn, (addr) => new ConnectInfo(msg));
if (exist) { conn.Sync = (msg); }
var nodeConnectors = nodeMap.GetOrAdd(msgAddr.ServiceNode, (name) => new NodeInfo(name));
nodeConnectors.SyncConnect(msgAddr, conn);
ret = !exist;
}
//刷新每个Group用户数量//
{
foreach (var g in groupMap.Values)
{
g.Sync(connectorMap);
}
}
//刷新排序//
{
connectorMap.MarkSort();
nodeMap.MarkSort();
groupMap.MarkSort();
}
return ret;
}
}
public void UpdateInQueue(object state)
{
using (connect_lock.EnterWrite())
{
//处理ServerGroup中等待队列//
foreach (var g in groupMap.Values)
{
try
{
g.UpdateInQueue(state);
}
catch (Exception err)
{
log.Error(err.Message, err);
}
}
}
}
public bool TryDispatchConnect(string serverGroupID, string expectConnectAddress, out GroupInfo group, out ConnectInfo conn, out bool inQueue, out int queueCount, out bool inMaxQueue)
{
var expectAddr = RemoteAddress.Parse(expectConnectAddress);
using (connect_lock.EnterRead())
{
// 通过ServerGroupID匹配 //
if (groupMap.TryGetValue(serverGroupID, out group))
{
if (group.TryDispatchConnect(expectAddr, out conn))
{
inQueue = group.IsNeedQueue;
queueCount = group.QueueCount;
group.PushClientNumber();
inMaxQueue = group.IsMaxQueue;
return group.IsAllowHardEnter;
//return true;
}
else
{
// 如果预期进入场景 //
if (expectAddr.NotNull)
{
if (nodeMap.TryGetValue(expectAddr.ServiceNode, out var connectors))
{
if (connectors.TryDispatchConnect(expectAddr, out conn))
{
inQueue = group.IsNeedQueue;
queueCount = group.QueueCount;
group.PushClientNumber();
inMaxQueue = group.IsMaxQueue;
return group.IsAllowHardEnter;
//return true;
}
}
}
// 兜底取所有Connect //
if (connectorMap.TryGetRandomFirst(random, out conn))
{
inQueue = group.IsNeedQueue;
queueCount = group.QueueCount;
group.PushClientNumber();
inMaxQueue = group.IsMaxQueue;
return group.IsAllowHardEnter;
//return true;
}
}
}
}
inQueue = false;
queueCount = 0;
conn = null;
inMaxQueue = false;
return false;
}
public void WriteStatus(TextWriter sb)
{
using (connect_lock.EnterRead())
{
sb.WriteLine(CUtils.SequenceChar('-', 100));
sb.WriteLine("- Group Map -");
sb.WriteLine(CUtils.SequenceChar('-', 100));
foreach (var group in groupMap.ToSortedArray())
{
group.WriteStatus(sb, string.Empty);
}
sb.WriteLine(CUtils.SequenceChar('-', 100));
sb.WriteLine("- Node Map -");
sb.WriteLine(CUtils.SequenceChar('-', 100));
foreach (var conns in nodeMap.ToSortedArray())
{
conns.WriteStatus(sb, string.Empty);
}
sb.WriteLine(CUtils.SequenceChar('-', 100));
sb.WriteLine("- Connector Map -");
sb.WriteLine(CUtils.SequenceChar('-', 100));
foreach (var conn in connectorMap.ToSortedArray())
{
conn.WriteStatus(sb, string.Empty);
}
sb.WriteLine(CUtils.SequenceChar('-', 100));
}
}
///
/// 链接负载分组
///
public class GroupInfo
{
private readonly ValueSortedMap connectorMap;
private readonly LinkedList inQueueSessions = new LinkedList();
public int NodeCount { get => connectorMap.Count; }
public string GroupID { get; private set; }
public int QueueCount { get => inQueueSessions.Count; }
///
/// 当前连接数量
///
public int ClientNumber { get; private set; }
#region H.Q.Cai 代码添加
// H.Q.Cai 代码添加开始
///
/// 是否需要排队
///
//public bool IsNeedQueue { get => this.ClientNumberLimit > 0 && this.ClientNumber >= this.ClientNumberLimit; }
public bool IsNeedQueue => IsAllowSoftEnter == false;
//public bool IsNeedQueue => true;
//public bool IsNeedQueue => false;
private readonly HashSet checkInQueueSessions = new HashSet();
///
/// 是否已满最大的排队系统
///
public bool IsMaxQueue => QueueCount >= QUEUE_MAX_LIMIT;
///
/// 第一个进入列队的时间
///
public DateTime? FirstInQueueTime { get; set; }
///
/// 是否允许软进入
///
public bool IsAllowSoftEnter => CLIENT_NUMBER_SOFT_LIMIT <= 0 || ClientNumber < CLIENT_NUMBER_SOFT_LIMIT * SOFT_ENTER_PERCENTAGE;
///
/// 是否允许硬进入
///
public bool IsAllowHardEnter => CLIENT_NUMBER_HARD_LIMIT <= 0 || ClientNumber < CLIENT_NUMBER_HARD_LIMIT * HARD_ENTER_PERCENTAGE;
///
/// 是否超过硬上线
///
public bool IsExceedHardLine => CLIENT_NUMBER_HARD_LIMIT > 0 && ClientNumber > CLIENT_NUMBER_HARD_LIMIT * MAX_HARD_ENTER_PERCENTAGE;
///
/// 设置客户端限制
///
internal void SetClientLimit(int hardLimit, int softLimit, int queueMaxLimit, int queueAddTime)
{
if (softLimit < MIN_CLIENT_NUMBER_SOFT_LIMIT) softLimit = MIN_CLIENT_NUMBER_SOFT_LIMIT;
if (softLimit > MAX_CLIENT_NUMBER_SOFT_LIMIT) softLimit = MAX_CLIENT_NUMBER_SOFT_LIMIT;
CLIENT_NUMBER_HARD_LIMIT = hardLimit;
CLIENT_NUMBER_SOFT_LIMIT = softLimit;
QUEUE_MAX_LIMIT = queueMaxLimit;
QUEUE_ADD_TIME = queueAddTime;
}
// H.Q.Cai 代码添加结束
#endregion
public GroupInfo(string group)
{
this.GroupID = group;
this.connectorMap = new ValueSortedMap((a, b) =>
{
return a.ClientNumber - b.ClientNumber;
});
}
internal void BindNode(NodeInfo node)
{
connectorMap.Put(node.NodeName, node);
}
internal void Sync(IDictionary connectorMap)
{
// H.Q.Cai 添加代码开始
var oldClientNumber = ClientNumber;
// H.Q.Cai 添加代码结束
this.ClientNumber = 0;
foreach (var c in connectorMap.Values)
{
foreach (var gn in c.Sync.groupClientNumbers)
{
if (gn.Key == this.GroupID)
{
this.ClientNumber += gn.Value;
}
}
}
// H.Q.Cai 添加代码开始
if (oldClientNumber != ClientNumber)
{
var subtraction = oldClientNumber - ClientNumber;
if (subtraction > POST_SERVER_NUMBER_INTERVAL || subtraction < -POST_SERVER_NUMBER_INTERVAL)
RPGServerTemplateManager.Instance.PostGroupServerNumber(GroupID, ClientNumber);
}
// H.Q.Cai 添加代码结束
}
internal bool TryDispatchConnect(RemoteAddress addr, out ConnectInfo conn)
{
// 从当前分组里找到对应的Node链接负载 //
if (addr.NotNull && connectorMap.TryGetValue(addr.ServiceNode, out var node))
{
if (node.TryDispatchConnect(addr, out conn))
{
return true;
}
}
// 尝试从最小负载Node链接负载 //
if (connectorMap.TryGetRandomFirst(random, out node))
{
if (node.TryDispatchConnect(addr, out conn))
{
return true;
}
}
conn = null;
return false;
}
internal void WriteStatus(TextWriter sb, string prefix)
{
sb.WriteLine($"{prefix}{GetType().Name} : {GroupID}");
sb.WriteLine($"{prefix} ClientNumber={ClientNumber}");
sb.WriteLine($"{prefix} ClientInQueue={inQueueSessions.Count}");
foreach (var conn in connectorMap.ToSortedArray())
{
conn.WriteStatus(sb, prefix + " - ");
}
}
//开始排队等待//
public void PushInQueue(ViewSession session)
{
inQueueSessions.AddLast(session);
checkInQueueSessions.Add(session);
}
internal void PushClientNumber()
{
if (!IsNeedQueue)
{
this.ClientNumber += 1;
}
}
internal void UpdateInQueue(object state)
{
// H.Q.Cai 添加开始
var gateServer = state as GateServer;
if (gateServer == null) return;
DateTime nowTime = DateTime.Now;
TimeSpan constExpectTime = TimeSpan.FromSeconds(QUEUE_ADD_TIME);
TimeSpan constExpectHardTime = TimeSpan.FromSeconds(QUEUE_MAX_HARD_ADD_TIME);
int queueIndexNew = 0;
for (var it = inQueueSessions.First; it != null;)
{
var subTimeSpan = FirstInQueueTime.HasValue ? nowTime - FirstInQueueTime.Value : TimeSpan.Zero;
bool isEnter;
if (IsExceedHardLine)
isEnter = subTimeSpan >= constExpectHardTime;
else
isEnter = subTimeSpan >= constExpectTime;
if (gateServer.ContainsSession(it.Value.Session) == false)
{
var rm = it;
it = it.Next;
inQueueSessions.Remove(rm);
checkInQueueSessions.Remove(rm.Value);
if (it == null) FirstInQueueTime = null;
else FirstInQueueTime = nowTime;
}
else if (it.Value.IsConnected == false)
{
gateServer.RemoveSessionAccount(it.Value.Session);
var rm = it;
it = it.Next;
inQueueSessions.Remove(rm);
checkInQueueSessions.Remove(rm.Value);
if (it == null) FirstInQueueTime = null;
else FirstInQueueTime = nowTime;
}
else if (isEnter)
{
if (IsAllowHardEnter == false)
{
continue;
}
if (gateServer.ContainsSession(it.Value.Session) == false)
{
continue;
}
gateServer.PushAccountExpire(it.Value.Session, it.Value.Enter.response.s2c_accountUUID, nowTime + constExpectTime);
it.Value.UpdateInQueue(queueIndexNew, true, TimeSpan.Zero);
ClientNumber += 1;
var rm = it;
it = it.Next;
inQueueSessions.Remove(rm);
checkInQueueSessions.Remove(rm.Value);
if (it == null) FirstInQueueTime = null;
else FirstInQueueTime = nowTime;
}
else
{
if (gateServer.ContainsSession(it.Value.Session) == false)
{
continue;
}
subTimeSpan = constExpectTime - subTimeSpan;
TimeSpan expectTime = TimeSpan.FromSeconds(constExpectTime.TotalSeconds * queueIndexNew) + subTimeSpan;
it.Value.UpdateInQueue(queueIndexNew, false, expectTime);
it = it.Next;
queueIndexNew++;
}
//log.Warn("queueIndexNew : " + queueIndexNew);
}
return;
// H.Q.Cai 添加结束
/*
int allowCount = CLIENT_NUMBER_HARD_LIMIT > 0 ? CLIENT_NUMBER_HARD_LIMIT - ClientNumber : int.MaxValue;
int queueIndex = 0;
for (var it = inQueueSessions.First; it != null;)
{
var isEnter = allowCount > 0;
if (it.Value.IsConnected == false)
{
var rm = it;
it = it.Next;
inQueueSessions.Remove(rm);
}
else if (isEnter)
{
it.Value.UpdateInQueue(queueIndex, isEnter);
allowCount--;
this.ClientNumber += 1;
var rm = it;
it = it.Next;
inQueueSessions.Remove(rm);
}
else
{
it.Value.UpdateInQueue(queueIndex, isEnter);
it = it.Next;
queueIndex++;
}
}
*/
}
}
///
/// 链接负载
///
public class NodeInfo
{
private readonly ValueSortedMap connectorMap;
public int ConnectorCount { get => connectorMap.Count; }
public int ClientNumber { get; private set; }
public string NodeName { get; private set; }
public NodeInfo(string name)
{
this.NodeName = name;
this.connectorMap = new ValueSortedMap((a, b) =>
{
return a.ClientNumber - b.ClientNumber;
});
}
internal bool SyncConnect(RemoteAddress addr, ConnectInfo msg)
{
msg.Node = this;
var ret = this.connectorMap.TryAddOrUpdate(addr.ServiceName, msg);
this.ClientNumber = connectorMap.Sum(e => e.Value.ClientNumber);
connectorMap.MarkSort();
return ret;
}
internal bool TryDispatchConnect(RemoteAddress addr, out ConnectInfo conn)
{
//从指定的ServiceName,获得链接//
if (addr.NotNull && connectorMap.TryGetValue(addr.ServiceName, out conn))
{
return true;
}
// 尝试从最小负载获得链接 //
if (connectorMap.TryGetRandomFirst(random, out conn))
{
return true;
}
return false;
}
internal void WriteStatus(TextWriter sb, string prefix)
{
sb.WriteLine($"{prefix}{GetType().Name} : {NodeName}");
sb.WriteLine($"{prefix} ClientNumber={ClientNumber}");
foreach (var conn in connectorMap.ToSortedArray())
{
conn.WriteStatus(sb, prefix + " - ");
}
}
}
///
/// 连接服信息
///
public class ConnectInfo
{
public SyncConnectToGateNotify Sync
{
get; internal set;
}
public NodeInfo Node
{
get; internal set;
}
public int ClientNumber
{
get => Sync.clientNumber;
}
public ConnectInfo(SyncConnectToGateNotify sync)
{
this.Sync = sync;
}
internal void WriteStatus(TextWriter sb, string prefix)
{
sb.WriteLine($"{prefix}{GetType().Name} : {Sync.connectServiceAddress} ClientNumber={ClientNumber}");
}
}
}
//----------------------------------------------------------------------------------------------------------------------------------------------
///
/// 账号列队到期时间
///
private readonly HashMap inAccountExpire = new HashMap();
///
/// 账号列队到期时间(其它)
///
private readonly HashMap inAccountExpireOther = new HashMap();
///
/// 通过当前的Session获取账号Uuid
///
private readonly HashMap inSessionAccount = new HashMap();
///
/// 推入会议账号结束期
///
private void InsertSessionAccountExpire(ISession session, string account, DateTime expire)
{
inSessionAccount.TryAddOrUpdate(session, account);
inAccountExpire.TryAddOrUpdate(account, (expire, false, session));
}
///
/// 推入会议结束期
///
private void PushAccountExpire(ISession session, string account, DateTime expire)
{
inAccountExpire.TryAddOrUpdate(account, (expire, true, session));
}
///
/// 推入会议结束期
///
private void PushOtherAccountExpire(string account, DateTime expire)
{
if(expire == DateTime.MinValue)
inAccountExpireOther.RemoveByKey(account);
else
inAccountExpireOther.TryAddOrUpdate(account, expire);
}
///
/// 移除会议
///
///
private bool ContainsSession(ISession session)
{
return inSessionAccount.ContainsKey(session);
}
///
/// 移除账号
///
///
private void RemoveSessionAccount(ISession session)
{
if (inSessionAccount.ContainsKey(session))
{
var sessionAccount = inSessionAccount[session];
inSessionAccount.RemoveByKey(session);
if (inAccountExpire.ContainsKey(sessionAccount))
{
var dateTime = inAccountExpire[sessionAccount];
if (dateTime.IsEnetered == false)
inAccountExpire.RemoveByKey(sessionAccount);
}
}
}
///
/// 包含账号
///
///
///
private bool ContainsAccount(ISession session, string account)
{
if (inAccountExpire.ContainsKey(account))
{
var dateTime = inAccountExpire[account];
var result = dateTime.IsEnetered && dateTime.ExpectTime >= DateTime.Now;
return result;
}
if (inAccountExpireOther.ContainsKey(account))
return true;
return false;
}
///
///
///
///
private void UpdateInQueue(object state)
{
DateTime nowTime = DateTime.Now;
List delAccountList = new List();
foreach (var dateTime in inAccountExpire)
{
var dateTimeValue = dateTime.Value;
if (dateTimeValue.ExpectTime < nowTime)
{
delAccountList.Add(dateTime.Key);
}
}
foreach (var account in delAccountList)
{
inAccountExpire.Remove(account);
}
delAccountList.Clear();
foreach (var dateTime in inAccountExpireOther)
{
if (dateTime.Value < nowTime)
{
delAccountList.Add(dateTime.Key);
}
}
foreach (var account in delAccountList)
{
inAccountExpireOther.Remove(account);
}
groupMap.UpdateInQueue(state);
}
//----------------------------------------------------------------------------------------------------------------------------------------------
protected virtual void Acceptor_OnSessionConnected(ISession session)
{
//if (DeepCore.Log.Logger.SHOW_LOG)
{
log.Info("Acceptor_OnSessionConnected : " + session);
}
Acceptor_CreateViewSession(session);
}
protected virtual void Acceptor_OnSessionDisconnected(ISession session)
{
//if (DeepCore.Log.Logger.SHOW_LOG)
{
log.Info("Acceptor_OnSessionDisconnected : " + session);
}
// H.Q.Cai 添加开始
RemoveSessionAccount(session);
groupMap.UpdateInQueue(this);
// H.Q.Cai 添加结束
}
protected virtual void Acceptor_OnServerError(IServer server, Exception err)
{
log.Error("Acceptor_OnServerError : " + err.Message, err);
}
protected virtual ViewSession Acceptor_CreateViewSession(ISession session)
{
return new ViewSession(this, session, log);
}
//------------------------------------------------------------------------------------------
public class EnterToken
{
public readonly ClientEnterGateRequest request;
public readonly ClientEnterGateResponse response;
public readonly ConnectorNodeMap.GroupInfo group;
public readonly ConnectorNodeMap.ConnectInfo connect;
public readonly AccountData account;
public EnterToken(ClientEnterGateRequest request, ClientEnterGateResponse response, ConnectorNodeMap.GroupInfo group = null, ConnectorNodeMap.ConnectInfo connect = null, AccountData account = null)
{
this.request = request;
this.response = response;
this.group = group;
this.connect = connect;
this.account = account;
}
}
public class ViewSession
{
protected readonly Logger log;
protected readonly GateServer server;
protected readonly ISession session;
protected readonly DateTime loginTime;
protected EnterToken enter;
public ISession Session => session;
public EnterToken Enter => enter;
public bool IsConnected
{
get => session.IsConnected;
}
public ViewSession(GateServer server, ISession session, Logger log)
{
this.log = log;
this.server = server;
this.session = session;
this.session.OnValidateAsync += Session_OnValidateAsync;
this.session.OnError += Session_OnError;
this.loginTime = DateTime.Now;
}
protected virtual async Task> Session_OnValidateAsync(ISession session, ISerializable user)
{
if (user is ClientEnterGateRequest)
{
//TODO 尽量分配到之前登陆过的Connect
return await server.Provider.Execute(async () =>
{
this.enter = await server.SelectConnectAsync(user as ClientEnterGateRequest, session);
if (enter.response.s2c_code == ClientEnterGateResponse.CODE_OK_IN_QUEUE)
{
// H.Q.Cai 添加开始
var nowTime = DateTime.Now;
TimeSpan queueAddTime = TimeSpan.FromSeconds(QUEUE_ADD_TIME);
DateTime constExpectTime = nowTime + TimeSpan.FromMinutes(1.0f);
enter.group.PushInQueue(this);
server.InsertSessionAccountExpire(this.session, enter.response.s2c_accountUUID, constExpectTime);
if (enter.group.QueueCount == 1)
{
enter.group.FirstInQueueTime = nowTime;
}
Func getWaiteSecond = group =>
{
var subTimeSpan = group.FirstInQueueTime.HasValue ? nowTime - group.FirstInQueueTime.Value : TimeSpan.Zero;
var expectTime = TimeSpan.FromSeconds(queueAddTime.TotalSeconds * (enter.group.QueueCount - 1)) + subTimeSpan;
return expectTime;
};
ClientEnterGateInQueueNotify notify = new ClientEnterGateInQueueNotify()
{
IsEnetered = false,
QueueIndex = enter.group.QueueCount - 1,
ExpectTime = getWaiteSecond(enter.group)
};
//session.SendAsync(notify).NoWait();
session.Send(notify);
// H.Q.Cai 添加结束
var result = server.ServerCodec.CloneSerializable(enter.response);
result.s2c_connectHost = null;
result.s2c_connectPort = 0;
result.s2c_connectToken = null;
result.s2c_lastLoginToken = null;
return new Tuple(true, result);
}
else
{
return new Tuple(false, enter.response);
}
});
}
else
{
return new Tuple(false, null);
}
}
protected virtual void Session_OnError(ISession session, Exception err)
{
log.Error(err.Message, err);
}
public virtual void UpdateInQueue(int queueIndex, bool isEnter)
{
var notify = new ClientEnterGateInQueueNotify();
notify.IsEnetered = isEnter;
notify.QueueIndex = queueIndex;
if (isEnter)
{
notify.s2c_connectHost = enter.response.s2c_connectHost;
notify.s2c_connectPort = enter.response.s2c_connectPort;
notify.s2c_connectToken = enter.response.s2c_connectToken;
notify.s2c_lastLoginToken = enter.response.s2c_lastLoginToken;
session.Send(notify);
session.Disconnect("entered");
}
else
{
session.Send(notify);
}
}
// H.Q.Cai 添加开始
///
///
///
public virtual void UpdateInQueue(int queueIndex, bool isEnter, TimeSpan expectTime)
{
var notify = new ClientEnterGateInQueueNotify
{
IsEnetered = isEnter,
QueueIndex = queueIndex,
ExpectTime = expectTime
};
if (isEnter)
{
notify.s2c_connectHost = enter.response.s2c_connectHost;
notify.s2c_connectPort = enter.response.s2c_connectPort;
notify.s2c_connectToken = enter.response.s2c_connectToken;
notify.s2c_lastLoginToken = enter.response.s2c_lastLoginToken;
session.Send(notify);
session.Disconnect("entered");
}
else
{
session.Send(notify);
}
}
// H.Q.Cai 添加结束
}
//------------------------------------------------------------------------------------------
}
}