초기커밋
This commit is contained in:
14
GameServer/P2P/IHostMigrator.cs
Normal file
14
GameServer/P2P/IHostMigrator.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Nettention.Proud;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public interface IHostMigrator
|
||||
{
|
||||
public Result defineHost(HostID p2pGroupId, SuperPeerSelectionPolicy policy, HostID[] excludees);
|
||||
public Result modifyHost(string userGuid);
|
||||
public Result removeHost();
|
||||
public string getHostUserGuid();
|
||||
public (Result, bool) migrateCheck(bool ignoreInterval = false);
|
||||
public void setGroupHostId(HostID groupId);
|
||||
}
|
||||
|
||||
19
GameServer/P2P/IP2PDataLogState.cs
Normal file
19
GameServer/P2P/IP2PDataLogState.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace GameServer;
|
||||
|
||||
public interface IP2PDataLogState
|
||||
{
|
||||
public void enter()
|
||||
{
|
||||
//상태에 처음 진입할 때 실행되는 코드
|
||||
}
|
||||
public Task update()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public void exit()
|
||||
{
|
||||
// 마무리 필요할때 처리해주는 로직
|
||||
}
|
||||
|
||||
public bool getActive();
|
||||
}
|
||||
90
GameServer/P2P/P2PDataAction.cs
Normal file
90
GameServer/P2P/P2PDataAction.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class P2PDataAction : EntityActionBase
|
||||
{
|
||||
//단순 p2p 데이터 기록을 위한 Action
|
||||
public ConcurrentDictionary<UInt32, P2PPacketSummery> m_data { get; set; } = new();
|
||||
public DateTime m_next_logging_time { get; set; } = DateTimeHelper.Current;
|
||||
public DateTime m_last_update_time { get; set; } = DateTimeHelper.Current;
|
||||
readonly Int32 m_logging_time_interval_sec;
|
||||
|
||||
public P2PDataAction(Player owner) : base(owner)
|
||||
{
|
||||
m_logging_time_interval_sec = 30;
|
||||
}
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> accumulateP2PData(UInt32 packetId, byte[] array)
|
||||
{
|
||||
if (false == m_data.TryGetValue(packetId, out var summery))
|
||||
{
|
||||
summery = new P2PPacketSummery(array.Length);
|
||||
}
|
||||
summery.accumulateData(array.Length);
|
||||
|
||||
m_data[packetId] = summery;
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
m_last_update_time = now;
|
||||
if (m_next_logging_time <= now)
|
||||
{
|
||||
Log.getLogger().info($"P2P Packet Data received total : {JsonConvert.SerializeObject(m_data)}");
|
||||
m_next_logging_time = m_next_logging_time.AddSeconds(m_logging_time_interval_sec);
|
||||
}
|
||||
|
||||
if (P2PDataLogManager.It.logActive() == false)
|
||||
{
|
||||
await P2PDataLogManager.It.activeMonitoring();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class P2PPacketSummery
|
||||
{
|
||||
public long m_packet_count { get; set; } = 0;
|
||||
public long m_total_packet_size { get; set; } = 0;
|
||||
|
||||
public P2PPacketSummery(long packetSize)
|
||||
{
|
||||
m_packet_count = 1;
|
||||
m_total_packet_size = packetSize;
|
||||
}
|
||||
|
||||
public P2PPacketSummery(long packetCount, long packetSize)
|
||||
{
|
||||
m_packet_count = packetCount;
|
||||
m_total_packet_size = packetSize;
|
||||
}
|
||||
|
||||
public void accumulateData(long packetSize)
|
||||
{
|
||||
m_packet_count += 1;
|
||||
m_total_packet_size += packetSize;
|
||||
}
|
||||
}
|
||||
63
GameServer/P2P/P2PDataLogManager.cs
Normal file
63
GameServer/P2P/P2PDataLogManager.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Concurrent;
|
||||
using NeoSmart.AsyncLock;
|
||||
using ServerCore;
|
||||
using ServerCommon;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class P2PDataInfoLog
|
||||
{
|
||||
public long m_total_packet_count { get; set; } = 0;
|
||||
public long m_total_packet_size { get; set; } = 0;
|
||||
|
||||
public DateTime m_last_recorded_time { get; set; } = DateTimeHelper.Current;
|
||||
}
|
||||
|
||||
public class P2PDataLogManager : Singleton<P2PDataLogManager>
|
||||
{
|
||||
public DateTime m_last_check_time { get; set; } = DateTimeHelper.Current;
|
||||
private AsyncLock m_async_lock = new(); //state 바꿀때 사용
|
||||
|
||||
private IP2PDataLogState m_current_log_state;
|
||||
|
||||
public P2PDataLogManager()
|
||||
{
|
||||
m_current_log_state = new P2PDataWriteIdleState();
|
||||
m_current_log_state.enter();
|
||||
|
||||
}
|
||||
|
||||
public void changeLogWriteState(IP2PDataLogState nextState)
|
||||
{
|
||||
m_current_log_state.exit();
|
||||
m_current_log_state = nextState;
|
||||
m_current_log_state.enter();
|
||||
}
|
||||
|
||||
public async Task activeMonitoring()
|
||||
{
|
||||
if (m_current_log_state.getActive()) return;
|
||||
|
||||
using (var _ = await getAsyncLock())
|
||||
{
|
||||
if (m_current_log_state.getActive()) return;
|
||||
changeLogWriteState(new P2PDataWriteState());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task inactiveMonitoring()
|
||||
{
|
||||
if (m_current_log_state.getActive() == false) return;
|
||||
|
||||
using (var releaser = await getAsyncLock())
|
||||
{
|
||||
if (m_current_log_state.getActive() == false) return;
|
||||
changeLogWriteState(new P2PDataWriteIdleState());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<IDisposable> getAsyncLock() => await m_async_lock.LockAsync();
|
||||
|
||||
public bool logActive() => m_current_log_state.getActive();
|
||||
}
|
||||
16
GameServer/P2P/P2PDataLogStateBase.cs
Normal file
16
GameServer/P2P/P2PDataLogStateBase.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace GameServer;
|
||||
|
||||
public abstract class P2PDataLogStateBase : IP2PDataLogState
|
||||
{
|
||||
protected readonly bool m_is_active = false;
|
||||
public P2PDataLogStateBase(bool isActive)
|
||||
{
|
||||
m_is_active = isActive;
|
||||
}
|
||||
|
||||
public abstract void enter();
|
||||
public abstract Task update();
|
||||
public abstract void exit();
|
||||
|
||||
public bool getActive() => m_is_active;
|
||||
}
|
||||
27
GameServer/P2P/P2PDataWriteIdleState.cs
Normal file
27
GameServer/P2P/P2PDataWriteIdleState.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using ServerCore;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class P2PDataWriteIdleState : P2PDataLogStateBase
|
||||
{
|
||||
public P2PDataWriteIdleState() : base(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void enter()
|
||||
{
|
||||
Log.getLogger().debug("P2PDataWriteIdleState enter");
|
||||
}
|
||||
public override Task update()
|
||||
{
|
||||
//update 로직.
|
||||
Log.getLogger().debug("P2PDataWriteIdleState update");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public override void exit()
|
||||
{
|
||||
// 마무리 필요할때 처리해주는 로직
|
||||
Log.getLogger().debug("P2PDataWriteIdleState exit");
|
||||
}
|
||||
}
|
||||
186
GameServer/P2P/P2PDataWriteState.cs
Normal file
186
GameServer/P2P/P2PDataWriteState.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using System.Collections.Concurrent;
|
||||
using ServerCommon;
|
||||
using ServerCore;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class P2PDataWriteState : P2PDataLogStateBase
|
||||
{
|
||||
private ConcurrentDictionary<string /*user_guid*/, P2PDataInfoLog> m_all_user_p2p_packet_infos = new();
|
||||
private CancellationTokenSource m_cancel_token = new();
|
||||
public DateTime m_last_check_time { get; set; } = DateTimeHelper.Current;
|
||||
readonly int m_record_check_time_min = 1;
|
||||
private PeriodicTaskTimer? m_task_nullable = null;
|
||||
public P2PDataWriteState() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void enter()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_cancel_token = new();
|
||||
m_task_nullable = new PeriodicTaskTimer( GetType().Name, Constant.P2P_PACKET_DATA_CHECK_INTERVAL_MSEC, m_cancel_token, onTaskTick);
|
||||
Log.getLogger().debug("activeMonitoring task created");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
var err_msg = $"Exception !!!, new PeriodicTaskTimer() : exception:{e}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task update()
|
||||
{
|
||||
//if (m_check_active == false) return;
|
||||
|
||||
Log.getLogger().debug("p2p monitoring update start");
|
||||
|
||||
var users = GameServerApp.getServerLogic().getPlayerManager().getUsers();
|
||||
foreach (var player in users.Values)
|
||||
{
|
||||
if (player is null) continue;
|
||||
|
||||
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
||||
if (false == user_create_or_load_action.isCompletedLoadUser())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dataAccumulate(player);
|
||||
}
|
||||
|
||||
recordDataTotalInfo();
|
||||
|
||||
|
||||
//더이상 패킷이 들어오지 않는 데이터는 삭제 처리
|
||||
deleteOldData();
|
||||
await dataAccumulateStateCheck();
|
||||
Log.getLogger().debug("p2p monitoring update done");
|
||||
}
|
||||
|
||||
public override async void exit()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_cancel_token != null && !m_cancel_token.IsCancellationRequested)
|
||||
{
|
||||
m_cancel_token.Cancel();
|
||||
}
|
||||
|
||||
if (m_task_nullable != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await m_task_nullable.getTask();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.getLogger().warn($"Task 예외 발생 (무시됨): {ex}");
|
||||
}
|
||||
|
||||
m_task_nullable = null;
|
||||
}
|
||||
|
||||
m_cancel_token?.Dispose();
|
||||
//m_cancel_token = null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.getLogger().error($"Exception !!!, stopTaskSafelyAsync() : exception:{e}");
|
||||
}
|
||||
|
||||
ServerBase.Monitor.It.setReceivedP2PDataInfo();
|
||||
Log.getLogger().debug("p2p monitoring exit");
|
||||
}
|
||||
|
||||
private async Task dataAccumulateStateCheck()
|
||||
{
|
||||
if (m_all_user_p2p_packet_infos.Keys.Count == 0)
|
||||
{
|
||||
await P2PDataLogManager.It.inactiveMonitoring();
|
||||
Log.getLogger().debug("p2p incactive monitoring");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task onTaskTick()
|
||||
{
|
||||
await update();
|
||||
}
|
||||
|
||||
public void deleteOldData()
|
||||
{
|
||||
var now = DateTimeHelper.Current;
|
||||
|
||||
var delete_users = new List<string>();
|
||||
foreach (var infos in m_all_user_p2p_packet_infos)
|
||||
{
|
||||
var user_guid = infos.Key;
|
||||
var info = infos.Value;
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (player_manager.tryGetUserByPrimaryKey(user_guid, out var found_user) == false) continue;
|
||||
|
||||
var p2p_data_action = found_user.getEntityAction<P2PDataAction>();
|
||||
if (p2p_data_action is null)
|
||||
{
|
||||
m_all_user_p2p_packet_infos.TryRemove(user_guid, out _);
|
||||
continue;
|
||||
}
|
||||
|
||||
var elapsed_update_time = p2p_data_action.m_last_update_time.AddMinutes(m_record_check_time_min);
|
||||
|
||||
if (elapsed_update_time < now)
|
||||
{
|
||||
delete_users.Add(user_guid);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var user_guid in delete_users)
|
||||
{
|
||||
m_all_user_p2p_packet_infos.TryRemove(user_guid, out _);
|
||||
Log.getLogger().debug($"delete old p2p packet data userGuid : {user_guid}");
|
||||
}
|
||||
}
|
||||
|
||||
public void dataAccumulate(Player player)
|
||||
{
|
||||
if (false == m_all_user_p2p_packet_infos.TryGetValue(player.getUserGuid(), out var info_log))
|
||||
{
|
||||
info_log = new P2PDataInfoLog();
|
||||
m_all_user_p2p_packet_infos.TryAdd(player.getUserGuid(), info_log);
|
||||
}
|
||||
var p2p_data_action = player.getEntityAction<P2PDataAction>();
|
||||
var now = DateTimeHelper.Current;
|
||||
foreach (var data in p2p_data_action.m_data)
|
||||
{
|
||||
var id = data.Key;
|
||||
var packet_count = data.Value.m_packet_count;
|
||||
var packet_size = data.Value.m_total_packet_size;
|
||||
|
||||
if (packet_count == info_log.m_total_packet_count) continue;
|
||||
|
||||
info_log.m_total_packet_count = packet_count;
|
||||
info_log.m_total_packet_size = packet_size;
|
||||
info_log.m_last_recorded_time = now;
|
||||
m_last_check_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
public void recordDataTotalInfo()
|
||||
{
|
||||
|
||||
var user_count = m_all_user_p2p_packet_infos.Keys.Count;
|
||||
long total_count = 0;
|
||||
long total_size = 0;
|
||||
foreach (var info in m_all_user_p2p_packet_infos.Values)
|
||||
{
|
||||
total_count += info.m_total_packet_count;
|
||||
total_size += info.m_total_packet_size;
|
||||
}
|
||||
ServerBase.Monitor.It.setReceivedP2PDataInfo(total_size, total_count, user_count);
|
||||
Log.getLogger().debug($"recordDataTotalInfo data send total_size : {total_size}, total_count : {total_count}, user_count : {user_count}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
64
GameServer/P2P/P2PPacketHandler.cs
Normal file
64
GameServer/P2P/P2PPacketHandler.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Nettention.Proud;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class P2PPacketHandler : P2PPacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessP2PPacket(ISession session, ByteArray receivedBytes)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
try
|
||||
{
|
||||
var bytes = receivedBytes.data;
|
||||
if(bytes is null) return result;
|
||||
|
||||
if (receivedBytes.Count < 4)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
// var byte_json = receivedBytes.ToJson();
|
||||
// Log.getLogger().debug($"p2p packet process packet json : {byte_json}");
|
||||
|
||||
byte[] headerBytes = bytes.Take(4).ToArray(); // 첫 4바이트만 추출
|
||||
uint packet_id = BitConverter.ToUInt32(headerBytes, 0);
|
||||
//Log.getLogger().debug($"Extracted header value: {packet_id}");
|
||||
|
||||
var player = session as Player;
|
||||
if (player is null)
|
||||
{
|
||||
Log.getLogger().debug($"player is nulll: {session.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
var p2p_data_action = player.getEntityAction<P2PDataAction>();
|
||||
if (p2p_data_action is null)
|
||||
{
|
||||
Log.getLogger().debug($"p2p_data_action is null !!: {player.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
await p2p_data_action.accumulateP2PData(packet_id, bytes);
|
||||
|
||||
//이부분은 고도화 될때 별도 처리
|
||||
//패킷 단위로 로직 처리 분류 필요할 경우 고도화 처리 한다.
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.getLogger().info($"p2p packet process error {ex.Message}");
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user