mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
Feature:Asynchronous Operation & Formatting Code
- Now the async operation is enabled! - Code formatted by Resharper plugin <3
This commit is contained in:
@@ -1,31 +1,28 @@
|
||||
using EggLink.DanhengServer.Command;
|
||||
|
||||
namespace EggLink.DanhengServer.WebServer.Server
|
||||
namespace EggLink.DanhengServer.WebServer.Server;
|
||||
|
||||
public class MuipCommandSender(MuipSession session, Action<string> action) : ICommandSender
|
||||
{
|
||||
public class MuipCommandSender(MuipSession session, Action<string> action) : ICommandSender
|
||||
public MuipSession Session { get; } = session;
|
||||
public Action<string> MsgAction { get; } = action;
|
||||
public int SenderUid { get; set; } = session.Account?.Uid ?? 0;
|
||||
|
||||
public bool HasPermission(string permission)
|
||||
{
|
||||
public MuipSession Session { get; } = session;
|
||||
public Action<string> MsgAction { get; } = action;
|
||||
public int SenderUid { get; set; } = session.Account?.Uid ?? 0;
|
||||
if (Session.IsAdmin) return true;
|
||||
|
||||
public bool HasPermission(string permission)
|
||||
{
|
||||
if (Session.IsAdmin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Session.Account?.Permissions?.Contains(permission) ?? false;
|
||||
}
|
||||
|
||||
public void SendMsg(string msg)
|
||||
{
|
||||
MsgAction(msg);
|
||||
}
|
||||
|
||||
public int GetSender()
|
||||
{
|
||||
return SenderUid;
|
||||
}
|
||||
return Session.Account?.Permissions?.Contains(permission) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask SendMsg(string msg)
|
||||
{
|
||||
MsgAction(msg);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public int GetSender()
|
||||
{
|
||||
return SenderUid;
|
||||
}
|
||||
}
|
||||
@@ -1,475 +1,437 @@
|
||||
using EggLink.DanhengServer.Util;
|
||||
using EggLink.DanhengServer.WebServer.Response;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using System.Numerics;
|
||||
using System.Diagnostics;
|
||||
using System.Management;
|
||||
using System.Security.Cryptography;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.X509;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using EggLink.DanhengServer.Database.Player;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using EggLink.DanhengServer.Data;
|
||||
using EggLink.DanhengServer.Database;
|
||||
using EggLink.DanhengServer.Database.Avatar;
|
||||
using EggLink.DanhengServer.Database.Mission;
|
||||
using EggLink.DanhengServer.Enums;
|
||||
using Spectre.Console;
|
||||
using EggLink.DanhengServer.Database.Lineup;
|
||||
using EggLink.DanhengServer.Data;
|
||||
namespace EggLink.DanhengServer.WebServer.Server
|
||||
using EggLink.DanhengServer.Database.Mission;
|
||||
using EggLink.DanhengServer.Database.Player;
|
||||
using EggLink.DanhengServer.Enums;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using EggLink.DanhengServer.WebServer.Response;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.X509;
|
||||
|
||||
namespace EggLink.DanhengServer.WebServer.Server;
|
||||
|
||||
public static class MuipManager
|
||||
{
|
||||
public static class MuipManager
|
||||
public delegate void ExecuteCommandDelegate(string message, MuipCommandSender sender);
|
||||
|
||||
public delegate void GetPlayerStatusDelegate(int uid, out PlayerStatusEnum status,
|
||||
out PlayerSubStatusEnum subStatus);
|
||||
|
||||
public delegate void ServerInformationDelegate(Dictionary<int, PlayerData> resultData);
|
||||
|
||||
private static readonly Logger logger = Logger.GetByClassName();
|
||||
|
||||
public static string RsaPublicKey { get; private set; } = "";
|
||||
public static string RsaPrivateKey { get; private set; } = "";
|
||||
|
||||
public static Dictionary<string, MuipSession> Sessions { get; } = [];
|
||||
public static event ExecuteCommandDelegate? OnExecuteCommand;
|
||||
public static event ServerInformationDelegate? OnGetServerInformation;
|
||||
public static event GetPlayerStatusDelegate? OnGetPlayerStatus;
|
||||
|
||||
public static AuthAdminKeyData? AuthAdminAndCreateSession(string key, string key_type)
|
||||
{
|
||||
private static readonly Logger logger = Logger.GetByClassName();
|
||||
public delegate void ExecuteCommandDelegate(string message, MuipCommandSender sender);
|
||||
public static event ExecuteCommandDelegate? OnExecuteCommand;
|
||||
public delegate void ServerInformationDelegate(Dictionary<int, PlayerData> resultData);
|
||||
public static event ServerInformationDelegate? OnGetServerInformation;
|
||||
public delegate void GetPlayerStatusDelegate(int uid, out PlayerStatusEnum status, out PlayerSubStatusEnum subStatus);
|
||||
public static event GetPlayerStatusDelegate? OnGetPlayerStatus;
|
||||
if (ConfigManager.Config.MuipServer.AdminKey == "" ||
|
||||
ConfigManager.Config.MuipServer.AdminKey != key) return null;
|
||||
|
||||
public static string RsaPublicKey { get; private set; } = "";
|
||||
public static string RsaPrivateKey { get; private set; } = "";
|
||||
|
||||
public static Dictionary<string, MuipSession> Sessions { get; } = [];
|
||||
|
||||
public static AuthAdminKeyData? AuthAdminAndCreateSession(string key, string key_type)
|
||||
var session = new MuipSession
|
||||
{
|
||||
if (ConfigManager.Config.MuipServer.AdminKey == "" || ConfigManager.Config.MuipServer.AdminKey != key)
|
||||
SessionId = Guid.NewGuid().ToString(),
|
||||
RsaPublicKey = GetRsaKeyPair().Item1,
|
||||
ExpireTimeStamp = DateTime.Now.AddMinutes(15).ToUnixSec(),
|
||||
IsAdmin = true
|
||||
};
|
||||
|
||||
if (key_type == "PEM")
|
||||
// convert to PEM
|
||||
session.RsaPublicKey = XMLToPEM_Pub(session.RsaPublicKey);
|
||||
|
||||
Sessions.Add(session.SessionId, session);
|
||||
|
||||
var data = new AuthAdminKeyData
|
||||
{
|
||||
RsaPublicKey = session.RsaPublicKey,
|
||||
SessionId = session.SessionId,
|
||||
ExpireTimeStamp = session.ExpireTimeStamp
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static MuipSession? GetSession(string sessionId)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out var value))
|
||||
{
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
var session = new MuipSession()
|
||||
{
|
||||
SessionId = Guid.NewGuid().ToString(),
|
||||
RsaPublicKey = GetRsaKeyPair().Item1,
|
||||
ExpireTimeStamp = DateTime.Now.AddMinutes(15).ToUnixSec(),
|
||||
IsAdmin = true,
|
||||
};
|
||||
|
||||
if (key_type == "PEM")
|
||||
{
|
||||
// convert to PEM
|
||||
session.RsaPublicKey = XMLToPEM_Pub(session.RsaPublicKey);
|
||||
}
|
||||
|
||||
Sessions.Add(session.SessionId, session);
|
||||
|
||||
var data = new AuthAdminKeyData
|
||||
{
|
||||
RsaPublicKey = session.RsaPublicKey,
|
||||
SessionId = session.SessionId,
|
||||
ExpireTimeStamp = session.ExpireTimeStamp,
|
||||
};
|
||||
|
||||
return data;
|
||||
return session;
|
||||
}
|
||||
|
||||
public static MuipSession? GetSession(string sessionId)
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ExecuteCommandResponse ExecuteCommand(string sessionId, string command, int targetUid)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out var value))
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out MuipSession? value))
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return null;
|
||||
}
|
||||
return session;
|
||||
Sessions.Remove(sessionId);
|
||||
return new ExecuteCommandResponse(1, "Session has expired!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ExecuteCommandResponse ExecuteCommand(string sessionId, string command, int targetUid)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out MuipSession? value))
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
rsa.FromXmlString(GetRsaKeyPair().Item2);
|
||||
byte[] decrypted;
|
||||
|
||||
try
|
||||
{
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return new(1, "Session has expired!");
|
||||
}
|
||||
decrypted = rsa.Decrypt(Convert.FromBase64String(command), RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ExecuteCommandResponse(3, "Wrong encrypted key");
|
||||
}
|
||||
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
rsa.FromXmlString(GetRsaKeyPair().Item2);
|
||||
byte[] decrypted;
|
||||
var commandStr = Encoding.UTF8.GetString(decrypted);
|
||||
logger.Info($"SessionId: {sessionId}, UID: {targetUid}, ExecuteCommand: {commandStr}");
|
||||
var returnStr = "";
|
||||
|
||||
try
|
||||
var sync = Task.Run(() => OnExecuteCommand?.Invoke(commandStr,
|
||||
new MuipCommandSender(session, msg => { returnStr += msg + "\r\n"; })
|
||||
{
|
||||
decrypted = rsa.Decrypt(Convert.FromBase64String(command), RSAEncryptionPadding.Pkcs1);
|
||||
} catch
|
||||
{
|
||||
return new(3, "Wrong encrypted key");
|
||||
}
|
||||
|
||||
var commandStr = Encoding.UTF8.GetString(decrypted);
|
||||
logger.Info($"SessionId: {sessionId}, UID: {targetUid}, ExecuteCommand: {commandStr}");
|
||||
var returnStr = "";
|
||||
|
||||
var sync = Task.Run(() => OnExecuteCommand?.Invoke(commandStr, new MuipCommandSender(session, (msg) =>
|
||||
{
|
||||
returnStr += msg + "\r\n";
|
||||
})
|
||||
{
|
||||
SenderUid = targetUid,
|
||||
SenderUid = targetUid
|
||||
}));
|
||||
|
||||
sync.Wait();
|
||||
sync.Wait();
|
||||
|
||||
return new(0, "Success", new()
|
||||
{
|
||||
SessionId = sessionId,
|
||||
Message = Convert.ToBase64String(Encoding.UTF8.GetBytes(returnStr)),
|
||||
});
|
||||
}
|
||||
return new(2, "Session not found!");
|
||||
return new ExecuteCommandResponse(0, "Success", new ExecuteCommandData
|
||||
{
|
||||
SessionId = sessionId,
|
||||
Message = Convert.ToBase64String(Encoding.UTF8.GetBytes(returnStr))
|
||||
});
|
||||
}
|
||||
|
||||
public static ServerInformationResponse GetInformation(string sessionId)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out MuipSession? value))
|
||||
{
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return new(1, "Session has expired!", null);
|
||||
}
|
||||
Process currentProcess = Process.GetCurrentProcess();
|
||||
return new ExecuteCommandResponse(2, "Session not found!");
|
||||
}
|
||||
|
||||
long currentProcessMemory = currentProcess.WorkingSet64;
|
||||
|
||||
// get system info
|
||||
var totalMemory = -1f;
|
||||
var availableMemory = -1f;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
totalMemory = GetTotalMemoryWindows();
|
||||
availableMemory = GetAvailableMemoryWindows();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
totalMemory = GetTotalMemoryLinux();
|
||||
availableMemory = GetAvailableMemoryLinux();
|
||||
}
|
||||
|
||||
var result = new Dictionary<int, PlayerData>();
|
||||
var sync = Task.Run(() => OnGetServerInformation?.Invoke(result));
|
||||
|
||||
sync.Wait();
|
||||
|
||||
return new(0, "Success", new()
|
||||
{
|
||||
ServerTime = DateTime.Now.ToUnixSec(),
|
||||
MaxMemory = totalMemory,
|
||||
ProgramUsedMemory = currentProcessMemory / 1024 / 1024,
|
||||
UsedMemory = totalMemory - availableMemory,
|
||||
OnlinePlayers = result.Values.Select(x => new SimplePlayerInformationData()
|
||||
{
|
||||
Name = x.Name ?? "",
|
||||
HeadIconId = x.HeadIcon,
|
||||
Uid = x.Uid
|
||||
}).ToList(),
|
||||
});
|
||||
}
|
||||
return new(2, "Session not found!", null);
|
||||
}
|
||||
|
||||
public static PlayerInformationResponse GetPlayerInformation(string sessionId, int uid)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out MuipSession? value))
|
||||
{
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return new(1, "Session has expired!", null);
|
||||
}
|
||||
|
||||
var result = new Dictionary<int, PlayerData>();
|
||||
var player = DatabaseHelper.Instance?.GetInstance<PlayerData>(uid);
|
||||
if (player == null) return new(2, "Player not exist!", null);
|
||||
|
||||
var status = PlayerStatusEnum.Offline;
|
||||
var subStatus = PlayerSubStatusEnum.None;
|
||||
|
||||
var statusSync = Task.Run(() => OnGetPlayerStatus?.Invoke(player.Uid, out status, out subStatus));
|
||||
|
||||
statusSync.Wait();
|
||||
|
||||
var avatarData = DatabaseHelper.Instance!.GetInstance<AvatarData>(player.Uid)!;
|
||||
var lineupData = DatabaseHelper.Instance!.GetInstance<LineupData>(player.Uid)!;
|
||||
var missionData = DatabaseHelper.Instance!.GetInstance<MissionData>(player.Uid)!;
|
||||
|
||||
var curLineupAvatars = new List<int>();
|
||||
var index = lineupData.CurExtraLineup > 0 ? lineupData.CurExtraLineup : lineupData.CurLineup;
|
||||
|
||||
lineupData.Lineups.TryGetValue(index, out var lineup);
|
||||
|
||||
if (lineup != null)
|
||||
{
|
||||
foreach (var avatar in lineup.BaseAvatars ?? [])
|
||||
{
|
||||
GameData.AvatarConfigData.TryGetValue(avatar.BaseAvatarId, out var excel);
|
||||
if (excel != null)
|
||||
{
|
||||
curLineupAvatars.Add(avatar.BaseAvatarId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new(0, "Success", new()
|
||||
{
|
||||
Uid = player.Uid,
|
||||
Name = player.Name ?? "",
|
||||
Signature = player.Signature ?? "",
|
||||
Stamina = player.Stamina,
|
||||
RecoveryStamina = (int)player.StaminaReserve,
|
||||
HeadIconId = player.HeadIcon,
|
||||
CurFloorId = player.FloorId,
|
||||
CurPlaneId = player.PlaneId,
|
||||
AssistAvatarList = avatarData.AssistAvatars,
|
||||
DisplayAvatarList = avatarData.DisplayAvatars,
|
||||
AcceptedSubMissionIdList = missionData.RunningSubMissionIds,
|
||||
AcceptedMainMissionIdList = missionData.RunningMainMissionIds,
|
||||
FinishedMainMissionIdList = missionData.FinishedMainMissionIds,
|
||||
FinishedSubMissionIdList = missionData.FinishedSubMissionIds,
|
||||
PlayerStatus = status,
|
||||
PlayerSubStatus = subStatus,
|
||||
Credit = player.Scoin,
|
||||
Jade = player.Hcoin,
|
||||
LineupBaseAvatarIdList = curLineupAvatars
|
||||
});
|
||||
}
|
||||
return new(3, "Session not found!", null);
|
||||
}
|
||||
|
||||
#region Tools
|
||||
|
||||
/// <summary>
|
||||
/// get rsa key pair
|
||||
/// </summary>
|
||||
/// <returns>item 1 is public key, item 2 is private key</returns>
|
||||
public static (string, string) GetRsaKeyPair()
|
||||
{
|
||||
if (string.IsNullOrEmpty(RsaPublicKey) || string.IsNullOrEmpty(RsaPrivateKey))
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider(2048);
|
||||
RsaPublicKey = rsa.ToXmlString(false);
|
||||
RsaPrivateKey = rsa.ToXmlString(true);
|
||||
}
|
||||
return (RsaPublicKey, RsaPrivateKey);
|
||||
}
|
||||
|
||||
|
||||
public static string XMLToPEM_Pub(string xmlpubkey)
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
rsa.FromXmlString(xmlpubkey);
|
||||
var p = rsa.ExportParameters(false);
|
||||
RsaKeyParameters key = new RsaKeyParameters(false, new Org.BouncyCastle.Math.BigInteger(1, p.Modulus), new Org.BouncyCastle.Math.BigInteger(1, p.Exponent));
|
||||
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(key);
|
||||
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
|
||||
string publicKey = Convert.ToBase64String(serializedPublicBytes);
|
||||
return Format(publicKey, true);
|
||||
}
|
||||
|
||||
|
||||
private static string Format(string key, bool type)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
int length = key.Length / 64;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int start = i * 64;
|
||||
result = result + key.Substring(start, 64) + "\r\n";
|
||||
}
|
||||
|
||||
result = result + key.Substring(length * 64);
|
||||
if (type)
|
||||
{
|
||||
result = result.Insert(0, "-----BEGIN PUBLIC KEY-----\r\n");
|
||||
result += "\r\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.Insert(0, "-----BEGIN PRIVATE KEY-----\r\n");
|
||||
result += "\r\n-----END PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float GetTotalMemoryWindows()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
|
||||
foreach (var obj in searcher.Get())
|
||||
{
|
||||
var memory = Convert.ToUInt64(obj["TotalPhysicalMemory"]);
|
||||
return memory / 1024 / 1024;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetAvailableMemoryWindows()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var pc = new PerformanceCounter("Memory", "Available MBytes");
|
||||
return pc.NextValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetTotalMemoryLinux()
|
||||
{
|
||||
string[] lines = File.ReadAllLines("/proc/meminfo");
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.StartsWith("MemTotal"))
|
||||
{
|
||||
return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetAvailableMemoryLinux()
|
||||
{
|
||||
string[] lines = File.ReadAllLines("/proc/meminfo");
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.StartsWith("MemAvailable"))
|
||||
{
|
||||
return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public static float GetCpuUsage()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return GetCpuUsageLinux();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return GetCpuUsageWindows();
|
||||
}
|
||||
throw new NotSupportedException("Unsupported OS platform");
|
||||
}
|
||||
|
||||
private static float GetCpuUsageLinux()
|
||||
{
|
||||
string[] lines = File.ReadAllLines("/proc/stat");
|
||||
string[] cpuInfo = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
float idleTime = float.Parse(cpuInfo[4]);
|
||||
float totalTime = 0;
|
||||
|
||||
for (int i = 1; i < cpuInfo.Length; i++)
|
||||
{
|
||||
totalTime += float.Parse(cpuInfo[i]);
|
||||
}
|
||||
|
||||
return 100 * (1 - idleTime / totalTime);
|
||||
}
|
||||
|
||||
private static float GetCpuUsageWindows()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
throw new PlatformNotSupportedException("PerformanceCounter is only supported on Windows");
|
||||
}
|
||||
|
||||
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
||||
cpuCounter.NextValue();
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
return cpuCounter.NextValue();
|
||||
}
|
||||
|
||||
public static (string ModelName, int Cores, float Frequency) GetCpuDetails()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return GetCpuDetailsLinux();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return GetCpuDetailsWindows();
|
||||
}
|
||||
throw new NotSupportedException("Unsupported OS platform");
|
||||
}
|
||||
|
||||
private static (string ModelName, int Cores, float Frequency) GetCpuDetailsLinux()
|
||||
{
|
||||
string[] lines = File.ReadAllLines("/proc/cpuinfo");
|
||||
string modelName = "";
|
||||
int cores = 0;
|
||||
float frequency = 0;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.StartsWith("model name"))
|
||||
{
|
||||
modelName = line.Split(':')[1].Trim();
|
||||
}
|
||||
if (line.StartsWith("cpu cores"))
|
||||
{
|
||||
cores = int.Parse(line.Split(':')[1].Trim());
|
||||
}
|
||||
if (line.StartsWith("cpu MHz"))
|
||||
{
|
||||
frequency = float.Parse(line.Split(':')[1].Trim());
|
||||
}
|
||||
}
|
||||
|
||||
return (modelName, cores, frequency);
|
||||
}
|
||||
|
||||
private static (string ModelName, int Cores, float Frequency) GetCpuDetailsWindows()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
throw new PlatformNotSupportedException("ManagementObjectSearcher is only supported on Windows");
|
||||
}
|
||||
|
||||
string modelName = "";
|
||||
int cores = 0;
|
||||
float frequency = 0;
|
||||
|
||||
var searcher = new ManagementObjectSearcher("select * from Win32_Processor");
|
||||
foreach (var item in searcher.Get())
|
||||
{
|
||||
modelName = item["Name"]?.ToString() ?? "Unknown";
|
||||
cores = int.Parse(item["NumberOfCores"]?.ToString() ?? "0");
|
||||
frequency = float.Parse(item["MaxClockSpeed"]?.ToString() ?? "0") / 1000; // MHz to GHz
|
||||
}
|
||||
|
||||
return (modelName, cores, frequency);
|
||||
}
|
||||
public static string GetSystemVersion()
|
||||
public static ServerInformationResponse GetInformation(string sessionId)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
if (Sessions.TryGetValue(sessionId, out var value))
|
||||
{
|
||||
return GetWindowsVersion();
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return new ServerInformationResponse(1, "Session has expired!");
|
||||
}
|
||||
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
|
||||
var currentProcessMemory = currentProcess.WorkingSet64;
|
||||
|
||||
// get system info
|
||||
var totalMemory = -1f;
|
||||
var availableMemory = -1f;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
totalMemory = GetTotalMemoryWindows();
|
||||
availableMemory = GetAvailableMemoryWindows();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
totalMemory = GetTotalMemoryLinux();
|
||||
availableMemory = GetAvailableMemoryLinux();
|
||||
}
|
||||
|
||||
var result = new Dictionary<int, PlayerData>();
|
||||
var sync = Task.Run(() => OnGetServerInformation?.Invoke(result));
|
||||
|
||||
sync.Wait();
|
||||
|
||||
return new ServerInformationResponse(0, "Success", new ServerInformationData
|
||||
{
|
||||
ServerTime = DateTime.Now.ToUnixSec(),
|
||||
MaxMemory = totalMemory,
|
||||
ProgramUsedMemory = currentProcessMemory / 1024 / 1024,
|
||||
UsedMemory = totalMemory - availableMemory,
|
||||
OnlinePlayers = result.Values.Select(x => new SimplePlayerInformationData
|
||||
{
|
||||
Name = x.Name ?? "",
|
||||
HeadIconId = x.HeadIcon,
|
||||
Uid = x.Uid
|
||||
}).ToList()
|
||||
});
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
|
||||
return new ServerInformationResponse(2, "Session not found!");
|
||||
}
|
||||
|
||||
public static PlayerInformationResponse GetPlayerInformation(string sessionId, int uid)
|
||||
{
|
||||
if (Sessions.TryGetValue(sessionId, out var value))
|
||||
{
|
||||
return GetLinuxVersion();
|
||||
var session = value;
|
||||
if (session.ExpireTimeStamp < DateTime.Now.ToUnixSec())
|
||||
{
|
||||
Sessions.Remove(sessionId);
|
||||
return new PlayerInformationResponse(1, "Session has expired!");
|
||||
}
|
||||
|
||||
var result = new Dictionary<int, PlayerData>();
|
||||
var player = DatabaseHelper.Instance?.GetInstance<PlayerData>(uid);
|
||||
if (player == null) return new PlayerInformationResponse(2, "Player not exist!");
|
||||
|
||||
var status = PlayerStatusEnum.Offline;
|
||||
var subStatus = PlayerSubStatusEnum.None;
|
||||
|
||||
var statusSync = Task.Run(() => OnGetPlayerStatus?.Invoke(player.Uid, out status, out subStatus));
|
||||
|
||||
statusSync.Wait();
|
||||
|
||||
var avatarData = DatabaseHelper.Instance!.GetInstance<AvatarData>(player.Uid)!;
|
||||
var lineupData = DatabaseHelper.Instance!.GetInstance<LineupData>(player.Uid)!;
|
||||
var missionData = DatabaseHelper.Instance!.GetInstance<MissionData>(player.Uid)!;
|
||||
|
||||
var curLineupAvatars = new List<int>();
|
||||
var index = lineupData.CurExtraLineup > 0 ? lineupData.CurExtraLineup : lineupData.CurLineup;
|
||||
|
||||
lineupData.Lineups.TryGetValue(index, out var lineup);
|
||||
|
||||
if (lineup != null)
|
||||
foreach (var avatar in lineup.BaseAvatars ?? [])
|
||||
{
|
||||
GameData.AvatarConfigData.TryGetValue(avatar.BaseAvatarId, out var excel);
|
||||
if (excel != null) curLineupAvatars.Add(avatar.BaseAvatarId);
|
||||
}
|
||||
|
||||
|
||||
return new PlayerInformationResponse(0, "Success", new PlayerInformationData
|
||||
{
|
||||
Uid = player.Uid,
|
||||
Name = player.Name ?? "",
|
||||
Signature = player.Signature ?? "",
|
||||
Stamina = player.Stamina,
|
||||
RecoveryStamina = (int)player.StaminaReserve,
|
||||
HeadIconId = player.HeadIcon,
|
||||
CurFloorId = player.FloorId,
|
||||
CurPlaneId = player.PlaneId,
|
||||
AssistAvatarList = avatarData.AssistAvatars,
|
||||
DisplayAvatarList = avatarData.DisplayAvatars,
|
||||
AcceptedSubMissionIdList = missionData.RunningSubMissionIds,
|
||||
AcceptedMainMissionIdList = missionData.RunningMainMissionIds,
|
||||
FinishedMainMissionIdList = missionData.FinishedMainMissionIds,
|
||||
FinishedSubMissionIdList = missionData.FinishedSubMissionIds,
|
||||
PlayerStatus = status,
|
||||
PlayerSubStatus = subStatus,
|
||||
Credit = player.Scoin,
|
||||
Jade = player.Hcoin,
|
||||
LineupBaseAvatarIdList = curLineupAvatars
|
||||
});
|
||||
}
|
||||
|
||||
return new PlayerInformationResponse(3, "Session not found!");
|
||||
}
|
||||
|
||||
#region Tools
|
||||
|
||||
/// <summary>
|
||||
/// get rsa key pair
|
||||
/// </summary>
|
||||
/// <returns>item 1 is public key, item 2 is private key</returns>
|
||||
public static (string, string) GetRsaKeyPair()
|
||||
{
|
||||
if (string.IsNullOrEmpty(RsaPublicKey) || string.IsNullOrEmpty(RsaPrivateKey))
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider(2048);
|
||||
RsaPublicKey = rsa.ToXmlString(false);
|
||||
RsaPrivateKey = rsa.ToXmlString(true);
|
||||
}
|
||||
|
||||
return (RsaPublicKey, RsaPrivateKey);
|
||||
}
|
||||
|
||||
|
||||
public static string XMLToPEM_Pub(string xmlpubkey)
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
rsa.FromXmlString(xmlpubkey);
|
||||
var p = rsa.ExportParameters(false);
|
||||
var key = new RsaKeyParameters(false, new BigInteger(1, p.Modulus), new BigInteger(1, p.Exponent));
|
||||
var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(key);
|
||||
var serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
|
||||
var publicKey = Convert.ToBase64String(serializedPublicBytes);
|
||||
return Format(publicKey, true);
|
||||
}
|
||||
|
||||
|
||||
private static string Format(string key, bool type)
|
||||
{
|
||||
var result = string.Empty;
|
||||
|
||||
var length = key.Length / 64;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var start = i * 64;
|
||||
result = result + key.Substring(start, 64) + "\r\n";
|
||||
}
|
||||
|
||||
result = result + key.Substring(length * 64);
|
||||
if (type)
|
||||
{
|
||||
result = result.Insert(0, "-----BEGIN PUBLIC KEY-----\r\n");
|
||||
result += "\r\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("This method only supports Windows and Linux.");
|
||||
result = result.Insert(0, "-----BEGIN PRIVATE KEY-----\r\n");
|
||||
result += "\r\n-----END PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float GetTotalMemoryWindows()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
|
||||
foreach (var obj in searcher.Get())
|
||||
{
|
||||
var memory = Convert.ToUInt64(obj["TotalPhysicalMemory"]);
|
||||
return memory / 1024 / 1024;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetAvailableMemoryWindows()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var pc = new PerformanceCounter("Memory", "Available MBytes");
|
||||
return pc.NextValue();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetTotalMemoryLinux()
|
||||
{
|
||||
var lines = File.ReadAllLines("/proc/meminfo");
|
||||
foreach (var line in lines)
|
||||
if (line.StartsWith("MemTotal"))
|
||||
return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetAvailableMemoryLinux()
|
||||
{
|
||||
var lines = File.ReadAllLines("/proc/meminfo");
|
||||
foreach (var line in lines)
|
||||
if (line.StartsWith("MemAvailable"))
|
||||
return float.Parse(line.Split(':')[1].Trim().Split(' ')[0]) / 1024;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float GetCpuUsage()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
return GetCpuUsageLinux();
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return GetCpuUsageWindows();
|
||||
throw new NotSupportedException("Unsupported OS platform");
|
||||
}
|
||||
|
||||
private static float GetCpuUsageLinux()
|
||||
{
|
||||
var lines = File.ReadAllLines("/proc/stat");
|
||||
var cpuInfo = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
var idleTime = float.Parse(cpuInfo[4]);
|
||||
float totalTime = 0;
|
||||
|
||||
for (var i = 1; i < cpuInfo.Length; i++) totalTime += float.Parse(cpuInfo[i]);
|
||||
|
||||
return 100 * (1 - idleTime / totalTime);
|
||||
}
|
||||
|
||||
private static float GetCpuUsageWindows()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
throw new PlatformNotSupportedException("PerformanceCounter is only supported on Windows");
|
||||
|
||||
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
||||
cpuCounter.NextValue();
|
||||
Thread.Sleep(1000);
|
||||
return cpuCounter.NextValue();
|
||||
}
|
||||
|
||||
public static (string ModelName, int Cores, float Frequency) GetCpuDetails()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
return GetCpuDetailsLinux();
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return GetCpuDetailsWindows();
|
||||
throw new NotSupportedException("Unsupported OS platform");
|
||||
}
|
||||
|
||||
private static (string ModelName, int Cores, float Frequency) GetCpuDetailsLinux()
|
||||
{
|
||||
var lines = File.ReadAllLines("/proc/cpuinfo");
|
||||
var modelName = "";
|
||||
var cores = 0;
|
||||
float frequency = 0;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("model name")) modelName = line.Split(':')[1].Trim();
|
||||
if (line.StartsWith("cpu cores")) cores = int.Parse(line.Split(':')[1].Trim());
|
||||
if (line.StartsWith("cpu MHz")) frequency = float.Parse(line.Split(':')[1].Trim());
|
||||
}
|
||||
|
||||
return (modelName, cores, frequency);
|
||||
}
|
||||
|
||||
private static (string ModelName, int Cores, float Frequency) GetCpuDetailsWindows()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
throw new PlatformNotSupportedException("ManagementObjectSearcher is only supported on Windows");
|
||||
|
||||
var modelName = "";
|
||||
var cores = 0;
|
||||
float frequency = 0;
|
||||
|
||||
var searcher = new ManagementObjectSearcher("select * from Win32_Processor");
|
||||
foreach (var item in searcher.Get())
|
||||
{
|
||||
modelName = item["Name"]?.ToString() ?? "Unknown";
|
||||
cores = int.Parse(item["NumberOfCores"]?.ToString() ?? "0");
|
||||
frequency = float.Parse(item["MaxClockSpeed"]?.ToString() ?? "0") / 1000; // MHz to GHz
|
||||
}
|
||||
|
||||
return (modelName, cores, frequency);
|
||||
}
|
||||
|
||||
public static string GetSystemVersion()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
return GetWindowsVersion();
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
return GetLinuxVersion();
|
||||
throw new PlatformNotSupportedException("This method only supports Windows and Linux.");
|
||||
}
|
||||
|
||||
private static string GetWindowsVersion()
|
||||
@@ -479,26 +441,24 @@ namespace EggLink.DanhengServer.WebServer.Server
|
||||
|
||||
private static string GetLinuxVersion()
|
||||
{
|
||||
string version = string.Empty;
|
||||
var version = string.Empty;
|
||||
if (File.Exists("/etc/os-release"))
|
||||
{
|
||||
var lines = File.ReadAllLines("/etc/os-release");
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("PRETTY_NAME"))
|
||||
{
|
||||
version = line.Split('=')[1].Trim('"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (File.Exists("/proc/version"))
|
||||
{
|
||||
version = File.ReadAllText("/proc/version");
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using EggLink.DanhengServer.Database.Account;
|
||||
|
||||
namespace EggLink.DanhengServer.WebServer.Server
|
||||
{
|
||||
public class MuipSession
|
||||
{
|
||||
public string RsaPublicKey { get; set; } = "";
|
||||
public string SessionId { get; set; } = "";
|
||||
public long ExpireTimeStamp { get; set; } = 0;
|
||||
namespace EggLink.DanhengServer.WebServer.Server;
|
||||
|
||||
public bool IsAdmin { get; set; } = false;
|
||||
public AccountData? Account { get; set; } = null;
|
||||
}
|
||||
}
|
||||
public class MuipSession
|
||||
{
|
||||
public string RsaPublicKey { get; set; } = "";
|
||||
public string SessionId { get; set; } = "";
|
||||
public long ExpireTimeStamp { get; set; } = 0;
|
||||
|
||||
public bool IsAdmin { get; set; } = false;
|
||||
public AccountData? Account { get; set; } = null;
|
||||
}
|
||||
Reference in New Issue
Block a user