[성현모] Config 기능 추가, Socket Recv Json, string 기능 분리

This commit is contained in:
SHM
2025-04-21 12:00:24 +09:00
parent a12a3949bf
commit aaf104a915
21 changed files with 550 additions and 156 deletions

Binary file not shown.

View File

@ -0,0 +1,32 @@
{
"Server": {
"Address": "https://*",
"Port": 9000,
"IIS": false
},
"Socket": {
"Address": "*",
"Port": 9010,
"IIS": false
},
"DataBase": [
{
"IP": "127.0.0.1",
"Port": 1433,
"DBName": "HubX",
"DBID": 1,
"DBContext": "HubXContext",
"UserID": "alis",
"Password": "Kefico!@34"
},
{
"IP": "127.0.0.1",
"Port": 1433,
"DBName": "HubX_DEV",
"DBID": 2,
"DBContext": "HubXContext",
"UserID": "alis",
"Password": "Kefico!@34"
}
]
}

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
<root>
<level value="ALL"/>
<appender-ref ref="Console"/>
<appender-ref ref="file"/>
<appender-ref ref="fatal_file"/>
</root>
<appender name="Console" type="log4net.Appender.ManagedColoredConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date] [%thread] %-6level: %message%newline" />
</layout>
<mapping>
<level value="FATAL" />
<foreColor value="White" />
<backColor value="Red" />
</mapping>
<mapping>
<level value="ERROR" />
<foreColor value="Red" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="Blue" />
</mapping>
<mapping>
<level value="DB" />
<foreColor value="DarkMagenta" />
</mapping>
<mapping>
<level value="HTTP" />
<foreColor value="DarkYellow" />
</mapping>
<mapping>
<level value="SOCKET" />
<foreColor value="DarkCyan" />
</mapping>
</appender>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="log/" />
<datepattern value="yyyy////MM////yyyy-MM-dd'.log'"/>
<appendToFile value="true" />
<rollingStyle value="Date" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date] [%thread] %level %logger - %message%newline" />
</layout>
</appender>
<appender name="fatal_file" type="log4net.Appender.RollingFileAppender">
<file value="log/" />
<datepattern value="yyyy////MM////yyyy-MM-dd'_fatal.log'"/>
<appendToFile value="true" />
<rollingStyle value="Date" />
<staticLogFileName value="false" />
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="FATAL" />
<param name="LevelMax" value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date] [%thread] %level %logger - %message%newline" />
</layout>
</appender>
</log4net>
</configuration>

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using SystemX.Core.Config;
using SystemX.Core.Config.Model;
namespace HubX.Library.Config
{
public class WebApiConfig : WebCommonConfig
{
[JsonPropertyName("DataBase")]
public List<SystemX.Core.Config.Model.DataBase>? DataBase { get; set; }
[JsonPropertyName("Socket")]
public Server Socket { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using Azure.Core;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HubX.Library.DataBase
{
public class DBManager
{
public DBManager()
{
}
public async Task Insert<T>(T context) where T : DbContext
{
//using (var transaction = await context.CreateTransactionAsync())
//{
// if (context.TCertificates.ToList().Exists(x => x.CCuid == tbscsr.CCuid) == false)
// {
// await context.AddAsync(certificate);
// }
// transactionResult = await context.CloseTransactionAsync(transaction);
//}
}
}
}

View File

@ -13,31 +13,37 @@ namespace HubX.Library.Socket.Packet
public class PacketHandler
{
public static void C2S_INSERT_UniqueKeyHandler(PacketSession session, IMessage packet)
public static void C2S_INSERT_UniqueKeyHandler(PacketSession session, ArraySegment<byte> buffer)
{
C2S_INSERT_UniqueKey movePacket = packet as C2S_INSERT_UniqueKey;
ClientSession clientSession = session as ClientSession;
var recvData = Encoding.UTF8.GetString(buffer);
//convert to object
var jsonObject = recvData.ToObject<C2S_INSERT_UniqueKey>();
if (jsonObject == null)
{
var recvDataList = recvData.Split(",");
jsonObject = new C2S_INSERT_UniqueKey
{
Identity = recvDataList[0],
Data1 = recvDataList[1],
Data2 = recvDataList[2],
Data3 = recvDataList[3],
Data4 = recvDataList[4],
Data5 = recvDataList[5],
};
}
//insert DB
if(jsonObject != null)
{
}
ClientSession clientSession = session as ClientSession;
Client client = clientSession.Client;
if (client == null)
return;
}
public static void C_SkillHandler(PacketSession session, IMessage packet)
{
//C_Skill skillPacket = packet as C_Skill;
//ClientSession clientSession = session as ClientSession;
//Player player = clientSession.MyPlayer;
//if (player == null)
// return;
//GameRoom room = player.Room;
//if (room == null)
// return;
//room.Push(room.HandleSkill, player, skillPacket);
}
}
}

View File

@ -12,12 +12,12 @@ namespace HubX.Library.Socket.Packet
public class C2S : IMessage
{
public EnumMessageId MessageId { get; set; }
// public EnumMessageId MessageId { get; set; }
}
public class S2C : IMessage
{
public EnumMessageId MessageId { get; set; }
// public EnumMessageId MessageId { get; set; }
public EnumMessageResult Result { get; set; }
}

View File

@ -20,9 +20,9 @@ namespace HubX.Library.Socket.Packet
}
Dictionary<ushort, Action<PacketSession, ArraySegment<byte>, ushort>> _onRecv = new Dictionary<ushort, Action<PacketSession, ArraySegment<byte>, ushort>>();
Dictionary<ushort, Action<PacketSession, IMessage>> _handler = new Dictionary<ushort, Action<PacketSession, IMessage>>();
Dictionary<ushort, Action<PacketSession, ArraySegment<byte>>> _handler = new Dictionary<ushort, Action<PacketSession, ArraySegment<byte>>>();
public Action<PacketSession, IMessage, ushort> CustomHandler { get; set; }
public Action<PacketSession, ArraySegment<byte>, ushort> CustomHandler { get; set; }
public void Register()
{
@ -39,31 +39,34 @@ namespace HubX.Library.Socket.Packet
ushort id = BitConverter.ToUInt16(buffer.Array, buffer.Offset + count);
count += 2;
Action<PacketSession, ArraySegment<byte>, ushort> action = null;
if (_onRecv.TryGetValue(id, out action))
action.Invoke(session, buffer, id);
ushort packetSize = (ushort)(buffer.Count - count);
byte[] packet = new byte[packetSize];
Array.Copy(buffer.ToArray(), count, packet, 0, packetSize);
if (_onRecv.TryGetValue(id, out var action))
action.Invoke(session, packet, id);
}
void MakePacket<T>(PacketSession session, ArraySegment<byte> buffer, ushort id) where T : IMessage, new()
void MakePacket<T>(PacketSession session, ArraySegment<byte> buffer, ushort id) where T : new()
{
T pkt = new T();
// T pkt = new T();
//pkt.MergeFrom(buffer.Array, buffer.Offset + 4, buffer.Count - 4);
if (CustomHandler != null)
{
CustomHandler.Invoke(session, pkt, id);
CustomHandler.Invoke(session, buffer, id);
}
else
{
Action<PacketSession, IMessage> action = null;
Action<PacketSession, ArraySegment<byte>> action = null;
if (_handler.TryGetValue(id, out action))
action.Invoke(session, pkt);
action.Invoke(session, buffer);
}
}
public Action<PacketSession, IMessage> GetPacketHandler(ushort id)
public Action<PacketSession, ArraySegment<byte>> GetPacketHandler(ushort id)
{
Action<PacketSession, IMessage> action = null;
Action<PacketSession, ArraySegment<byte>> action = null;
if (_handler.TryGetValue(id, out action))
return action;
return null;

View File

@ -1,7 +1,23 @@
using HubX.Library.Config;
using HubX.Library.Socket.Session;
using HubX.Server;
using HubX.Server.TaskManager;
using System.Net;
using System.Net.Sockets;
using SystemX.Core.Communication;
using SystemX.Core.Services;
string configDir = @"../Config";
//raed log4net config
if (Log4net.IsConfigLoad == true)
{
Log4net.WriteLine("Log4net Init Success");
}
else
{
Log4net.WriteLine("Log4net Init Failed", LogType.Error);
}
var builder = WebApplication.CreateBuilder(args);
@ -12,41 +28,61 @@ builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//singleton
builder.Services.AddSingleton<ConfigService<WebApiConfig>>();
//config preload
ConfigService<WebApiConfig> preloadConfig = new ConfigService<WebApiConfig>();
if (preloadConfig.OpenConfig($@"{configDir}/HubX.WebApiConfig.json") == true)
{
var config = preloadConfig.GetConfig();
}
else
{
Console.WriteLine("Config Preload Load Error.");
return;
}
var app = builder.Build();
//read api config and set
string serverUrl = string.Empty;
var configService = app.Services.GetService<ConfigService<WebApiConfig>>();
bool isIIS = false;
int socketPort = 0;
if (configService?.OpenConfig($@"{configDir}/HubX.WebApiConfig.json") == true)
{
Log4net.WriteLine("WebApi Config Success.");
var apiConfig = ConfigService<WebApiConfig>.Config;
if (apiConfig != null)
{
serverUrl = $"{apiConfig.Server.Address}:{apiConfig.Server.Port}";
isIIS = apiConfig.Server.IIS;
//socket
socketPort = apiConfig.Socket.Port;
}
}
else
{
Log4net.WriteLine("WebApi Config Error.");
return;
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
Log4net.WriteLine($"IsDevelopment:{app.Environment.IsDevelopment()}");
Log4net.WriteLine($"Swagger Url: {serverUrl}/swagger");
app.UseSwagger();
app.UseSwaggerUI();
}
Log4net.WriteLine("Run");
Log4net.WriteLine("Custom LogLevel",LogType.DB);
WeatherForecast weatherForecast = new WeatherForecast();
weatherForecast.Summary = "so hot";
var strJson = weatherForecast.ToJson();
var deep = weatherForecast.DeepCopy();
deep.Summary = "so cool";
var rr = strJson.ToObject<WeatherForecast>();
Task.Run(async() =>
{
await Task.Delay(2000);
Listener _listener = new Listener();
// string host = Dns.GetHostName();
IPHostEntry ipHost = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
_listener.Init(endPoint, () => { return SessionManager.Instance.Generate(); });
Console.WriteLine("Listening...");
});
TaskSocket taskSocket = new TaskSocket();
taskSocket?.Run(socketPort);
app.UseHttpsRedirection();
@ -54,4 +90,12 @@ app.UseAuthorization();
app.MapControllers();
if (isIIS == true)
{
app.Run();
}
else
{
Log4net.WriteLine($"Operation Url: {serverUrl}");
app.Run($"{serverUrl}");
}

View File

@ -0,0 +1,29 @@
using HubX.Library.Socket.Session;
using System.Net;
using SystemX.Core.Communication;
namespace HubX.Server.TaskManager
{
public class TaskSocket
{
public async Task Run(int socketPort = 7777)
{
try
{
await Task.Delay(1000);
Listener _listener = new Listener();
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, socketPort);
_listener.Init(endPoint, () => { return SessionManager.Instance.Generate(); });
Log4net.WriteLine($"Address:{endPoint.Address}, Port:{socketPort}", LogType.SOCKET);
Log4net.WriteLine($"Socket Listening Start", LogType.SOCKET);
}
catch (Exception e)
{
Log4net.WriteLine("Socket Run Failed",LogType.Error);
Log4net.WriteLine(e);
}
}
}
}

View File

@ -7,9 +7,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HubX.Server", "HubX.Server\
EndProject
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "HubX.DB", "HubX.DB\HubX.DB.sqlproj", "{514DDCCF-6B50-49F8-B212-70498396CF19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HubX.Library", "HubX.Library\HubX.Library.csproj", "{E6FA1D27-A644-4E50-BF16-DCCA59AA378D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HubX.Library", "HubX.Library\HubX.Library.csproj", "{E6FA1D27-A644-4E50-BF16-DCCA59AA378D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HubX.Library.DB", "HubX.Library.DB\HubX.Library.DB.csproj", "{C43CF1F1-9CB0-44DC-89D7-3514F18EAD46}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HubX.Library.DB", "HubX.Library.DB\HubX.Library.DB.csproj", "{C43CF1F1-9CB0-44DC-89D7-3514F18EAD46}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{18B1BDDB-B76F-43A4-BBE8-805CEEF35CE0}"
ProjectSection(SolutionItems) = preProject
Config\HubX.WebApiConfig.json = Config\HubX.WebApiConfig.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -42,6 +42,8 @@ namespace SystemX.Core.Communication
}
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
try
{
if (args.SocketError == SocketError.Success)
{
@ -53,6 +55,11 @@ namespace SystemX.Core.Communication
{
Log4net.WriteLine(args.SocketError.ToString(), LogType.Error);
}
}
catch(Exception e)
{
Log4net.WriteLine(e, LogType.Error);
}
RegisterAccept(args);
}

View File

@ -5,7 +5,7 @@ using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SystemX.Core.DB
namespace SystemX.Core.Config.Model
{
public class DataBase
{

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SystemX.Core.Config.Model
{
public class Server
{
[JsonPropertyName("Address")]
public string? Address { get; set; }
[JsonPropertyName("Port")]
public int Port { get; set; }
[JsonPropertyName("IIS")]
public bool IIS { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using SystemX.Core.Config.Model;
namespace SystemX.Core.Config
{
public class WebCommonConfig
{
[JsonPropertyName("Server")]
public Server Server { get; set; } = new();
}
}

View File

@ -0,0 +1,107 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Core.Config.Model;
namespace SystemX.Core.DB
{
public static class DBTransaction
{
/// <summary>
/// Get SqlServer Connection String
/// </summary>
public static string ConvertToConnectionString(this DataBase dbConfig)
{
return $"server={dbConfig.IP},{dbConfig.Port}; user id={dbConfig.UserID}; password={dbConfig.Password}; database={dbConfig.DBName}; TrustServerCertificate=true;";
}
public static IEnumerable<TEntity>? GetEntity<TEntity>(this DbContext dbContext) where TEntity : class
{
IEnumerable<TEntity>? entity = default;
var type = dbContext.GetType();
try
{
foreach (var prop in type.GetProperties())
{
string propertyFullName = $"{prop.PropertyType.FullName}";
if (propertyFullName.ToLower().Contains(typeof(TEntity).Name.ToLower()))
{
entity = prop.GetValue(dbContext) as IEnumerable<TEntity>;
break;
}
}
}
catch (Exception ex)
{
Log4net.WriteLine(ex);
}
return entity;
}
#region Transaction
public static IDbContextTransaction CreateTransaction(this DbContext dbContext)
{
return dbContext.Database.BeginTransaction();
}
public static bool CloseTransaction(this DbContext dbContext, IDbContextTransaction transaction)
{
bool result = false;
try
{
dbContext.SaveChanges();
transaction.Commit();
result = true;
Log4net.WriteLine("Transaction Commit", LogType.Debug);
}
catch (Exception ex)
{
transaction.Rollback();
Log4net.WriteLine("Transaction Rollback", LogType.Error);
Log4net.WriteLine(ex);
}
transaction.Dispose();
return result;
}
#endregion
#region Transaction Async
public static async Task<IDbContextTransaction> CreateTransactionAsync(this DbContext dbContext)
{
return await dbContext.Database.BeginTransactionAsync();
}
public static async Task<bool> CloseTransactionAsync(this DbContext dbContext, IDbContextTransaction transaction)
{
bool result = false;
try
{
await dbContext.SaveChangesAsync();
await transaction.CommitAsync();
result = true;
Log4net.WriteLine("Transaction Commit", LogType.Debug);
}
catch (Exception ex)
{
await transaction.RollbackAsync();
Log4net.WriteLine("Transaction Rollback", LogType.Error);
Log4net.WriteLine(ex);
}
await transaction.DisposeAsync();
return result;
}
#endregion
}
}

View File

@ -1,106 +1,64 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Core.Config.Model;
namespace SystemX.Core.DB
{
public static class EFCore
public class EFCore
{
/// <summary>
/// Get SqlServer Connection String
/// </summary>
public static string ConvertToConnectionString(this DataBase dbConfig)
private readonly Dictionary<string, DbContext> DicDbContext = new Dictionary<string, DbContext>();
public EFCore()
: base()
{
return $"server={dbConfig.IP},{dbConfig.Port}; user id={dbConfig.UserID}; password={dbConfig.Password}; database={dbConfig.DBName}; TrustServerCertificate=true;";
}
public static IEnumerable<TEntity>? GetEntity<TEntity>(this DbContext dbContext) where TEntity : class
#region Initialize DBContext
private void InitializeDB<TDBContext>() where TDBContext : DbContext, new()
{
IEnumerable<TEntity>? entity = default;
var type = dbContext.GetType();
try
{
foreach (var prop in type.GetProperties())
{
string propertyFullName = $"{prop.PropertyType.FullName}";
if (propertyFullName.ToLower().Contains(typeof(TEntity).Name.ToLower()))
{
entity = prop.GetValue(dbContext) as IEnumerable<TEntity>;
break;
}
}
}
catch (Exception ex)
{
Log4net.WriteLine(ex);
//if (dbList is not null)
//{
// foreach (var db in dbList)
// {
// if (typeof(VpkiAccountDbContext).Name == db.DBContext)
// {
// CreateDBContext<TDBContext>(db);
// }
// else if (typeof(VpkiDataDbContext).Name == db.DBContext)
// {
// CreateDBContext<VpkiDataDbContext>(db);
// }
// }
//}
}
return entity;
}
#region Transaction
public static IDbContextTransaction CreateTransaction(this DbContext dbContext)
private void CreateDBContext<TDBContext>(DataBase? dbConfig) where TDBContext : DbContext, new()
{
return dbContext.Database.BeginTransaction();
}
//var connectionString = dbConfig?.ConvertToConnectionString();
public static bool CloseTransaction(this DbContext dbContext, IDbContextTransaction transaction)
{
bool result = false;
try
{
dbContext.SaveChanges();
transaction.Commit();
result = true;
//var dbContext = new TDBContext();
//dbContext.Database.SetConnectionString($"{connectionString}");
Log4net.WriteLine("Transaction Commit", LogType.Debug);
}
catch (Exception ex)
{
transaction.Rollback();
Log4net.WriteLine("Transaction Rollback", LogType.Error);
Log4net.WriteLine(ex);
}
transaction.Dispose();
return result;
//if (dbContext is not null)
// DicDbContext.Add($"{dbConfig?.DBContext}_{dbConfig?.DBID}", dbContext);
}
#endregion
#region Transaction Async
public static async Task<IDbContextTransaction> CreateTransactionAsync(this DbContext dbContext)
public TDBContext? GetDBContext<TDBContext>(int dbID = 1) where TDBContext : DbContext
{
return await dbContext.Database.BeginTransactionAsync();
}
TDBContext? dBContext = default;
public static async Task<bool> CloseTransactionAsync(this DbContext dbContext, IDbContextTransaction transaction)
var dbContextType = typeof(TDBContext);
if (DicDbContext.TryGetValue($"{dbContextType.Name}_{dbID}", out var context) == true)
{
bool result = false;
try
{
await dbContext.SaveChangesAsync();
await transaction.CommitAsync();
result = true;
Log4net.WriteLine("Transaction Commit", LogType.Debug);
}
catch (Exception ex)
{
await transaction.RollbackAsync();
Log4net.WriteLine("Transaction Rollback", LogType.Error);
Log4net.WriteLine(ex);
}
await transaction.DisposeAsync();
return result;
}
#endregion
dBContext = context as TDBContext;
}
return dBContext;
}
}
}

View File

@ -54,13 +54,15 @@ public static class Log4net
static Log4net()
{
Console.WriteLine("log4net constructor");
if (File.Exists("./log4net.config") == false)
string log4netConfigPath = @"../Config/log4net.config";
if (File.Exists(log4netConfigPath) == false)
{
File.WriteAllText("log4net.config", Config);
Console.WriteLine($"create log4netConfig: {log4netConfigPath}");
File.WriteAllText(log4netConfigPath, Config);
}
IsConfigLoad = OpenConfig(@"./log4net.config");
IsConfigLoad = OpenConfig(log4netConfigPath);
}
private static bool OpenConfig(string path)

View File

@ -0,0 +1,39 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Core.Config;
namespace SystemX.Core.Services
{
public class ConfigService<T> where T : WebCommonConfig
{
public static T? Config { get; set; }
public bool OpenConfig(string path)
{
bool result = true;
try
{
string clientConfigJson = File.ReadAllText(path);
Config = JsonConvert.DeserializeObject<T>(clientConfigJson);
}
catch (Exception e)
{
Console.WriteLine("Config Init Error");
Console.WriteLine(e.Message);
result = false;
}
return result;
}
public T? GetConfig()
{
return Config;
}
}
}

View File

@ -32,8 +32,7 @@ public static class JsonUtils
}
catch(Exception e)
{
Log4net.WriteLine("JsonUtils.ToObject()", LogType.Error);
Log4net.WriteLine(e);
Log4net.WriteLine("JsonUtils.ToObject()", LogType.Warn);
}
return result;