315 lines
15 KiB
C#
315 lines
15 KiB
C#
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Crypto.Signers;
|
|
using ServerCommon;
|
|
using System.Text;
|
|
using ServerCore; using ServerBase;
|
|
using System.Text.Json.Nodes;
|
|
using Newtonsoft.Json;
|
|
using MetaAssets;
|
|
using META_ID = System.UInt32;
|
|
|
|
namespace GameServer
|
|
{
|
|
static public class AIChatServerConnector
|
|
{
|
|
static string server_jwt = string.Empty;
|
|
static string? jwtAdminJson = null;
|
|
static string? jwtUserJson = null;
|
|
|
|
static public async Task onInit()
|
|
{
|
|
var messageBytes = MakeMessage("admin");
|
|
var signatureBytes = SignMessage(messageBytes);
|
|
|
|
AIChatJwt AIChatAdminJwt = new AIChatJwt();
|
|
AIChatAdminJwt.messageBase64 = Convert.ToBase64String(messageBytes);
|
|
AIChatAdminJwt.signatureBase64 = Convert.ToBase64String(signatureBytes);
|
|
|
|
jwtAdminJson = JsonConvert.SerializeObject(AIChatAdminJwt);
|
|
|
|
messageBytes = MakeMessage("user");
|
|
signatureBytes = SignMessage(messageBytes);
|
|
|
|
AIChatJwt AIChatUserJwt = new AIChatJwt();
|
|
AIChatUserJwt.messageBase64 = Convert.ToBase64String(messageBytes);
|
|
AIChatUserJwt.signatureBase64 = Convert.ToBase64String(signatureBytes);
|
|
|
|
jwtUserJson = JsonConvert.SerializeObject(AIChatUserJwt);
|
|
|
|
await serverJwtIssue();
|
|
|
|
await RegisterGeneralNPC();
|
|
}
|
|
|
|
static public string getUserJwtJson()
|
|
{
|
|
NullReferenceCheckHelper.throwIfNull(jwtUserJson, () => $"jwtUserJson is null !!!");
|
|
return jwtUserJson;
|
|
}
|
|
|
|
//서버의 JWT를 발행합니다.
|
|
static private async Task<Result> serverJwtIssue()
|
|
{
|
|
(var result, string resMsg) = await sendAIChatServer("POST", $"/api/auth/jwt/issue", null, jwtAdminJson);
|
|
if (result.isFail()) return result;
|
|
|
|
var jwt = JsonNode.Parse(resMsg)?["jwt"]?.ToString();
|
|
if (jwt != null)
|
|
{
|
|
server_jwt = jwt;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//전체 채팅량 랭킹 (매개변수인 languageType은 res로 받는 캐릭터 이름이나 owner의 이름의 번역 차이임.)
|
|
static public async Task<(Result, AIChatRanking?)> getAllRanking(LanguageType language, int page, int numPerPage)
|
|
{
|
|
(var result, string resMsg) = await sendAIChatServerWithServerJwt("GET", $"/api/ranking/all?lang={language.ToString().ToLower()}&page={page}&numPerPage={numPerPage}", null);
|
|
if (result.isFail()) return (result, null);
|
|
|
|
try
|
|
{
|
|
var aichat_ranking = JsonConvert.DeserializeObject<AIChatRanking>(resMsg);
|
|
return (result, aichat_ranking);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
|
|
return (result, null);
|
|
}
|
|
}
|
|
//최근 24시간 채팅량 랭킹 (매개변수인 languageType은 res로 받는 캐릭터 이름이나 owner의 이름의 번역 차이임.)
|
|
static public async Task<(Result, AIChatRanking?)> getTodayRanking(LanguageType language, int page, int numPerPage)
|
|
{
|
|
(var result, string resMsg) = await sendAIChatServerWithServerJwt("GET", $"/api/ranking/today?lang={language.ToString().ToLower()}&page={page}&numPerPage={numPerPage}", null);
|
|
if (result.isFail()) return (result, null);
|
|
|
|
try
|
|
{
|
|
var aichat_ranking = JsonConvert.DeserializeObject<AIChatRanking>(resMsg);
|
|
return (result, aichat_ranking);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
|
|
return (result, null);
|
|
}
|
|
}
|
|
|
|
//특정 캐릭터 조회
|
|
static public async Task<(Result, AIChatCharacter?)> getCharacterByTargetGuid(string target_guid)
|
|
{
|
|
(var result, string resMsg) = await sendAIChatServerWithServerJwt("GET", $"/api/character/{target_guid}", null);
|
|
if (result.isFail()) return (result, null);
|
|
|
|
try
|
|
{
|
|
var aichat_character = JsonConvert.DeserializeObject<AIChatCharacter>(resMsg);
|
|
return (result, aichat_character);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
|
|
return (result, null);
|
|
}
|
|
}
|
|
|
|
static private byte[] MakeMessage(string role)
|
|
{
|
|
var message = "{\"role\":\"" + role + "\"}";
|
|
var messageBytes = Encoding.UTF8.GetBytes(message);
|
|
return messageBytes;
|
|
}
|
|
|
|
static private byte[] SignMessage(byte[] messageBytes)
|
|
{
|
|
var privateKey = Convert.FromBase64String(GameServerApp.getServerLogic().getServerConfig().AIChatConfig.PrivateKey);
|
|
var privateKeyParams = new Ed25519PrivateKeyParameters(privateKey, 0);
|
|
|
|
// 서명합니다.
|
|
var signer = new Ed25519Signer();
|
|
signer.Init(true, privateKeyParams);
|
|
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
|
|
var signature = signer.GenerateSignature();
|
|
return signature;
|
|
}
|
|
|
|
static public async Task<(Result, string)> sendAIChatServerWithServerJwt(string httpMethod, string url, string? bodyJson)
|
|
{
|
|
var result = new Result();
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
if (server_logic.getServerConfig().OfflineMode == true)
|
|
{
|
|
result.setFail(ServerErrorCode.AiChatServerInactive);
|
|
return (result, string.Empty);
|
|
}
|
|
|
|
var fullUrl = makeAiChatServerURL(url);
|
|
|
|
(var IsSuccessStatusCode, var readMsg) = await HttpClientHelper.sendHttpRequest( httpMethod
|
|
, fullUrl, server_jwt, bodyJson
|
|
, "application/json"
|
|
, "caliverse", "1.0" );
|
|
if (IsSuccessStatusCode == false)
|
|
{
|
|
Log.getLogger().info($"sendAIChatServer Failed. fullUrl : {fullUrl}, return msg : {readMsg} !!!");
|
|
|
|
result = ErrorHelper(readMsg, fullUrl);
|
|
if (result.ErrorCode == ServerErrorCode.AiChatServerTokenExpired)
|
|
{
|
|
result = await serverJwtIssue();
|
|
if (result.isSuccess())
|
|
{
|
|
(IsSuccessStatusCode, readMsg) = await HttpClientHelper.sendHttpRequest( httpMethod
|
|
, fullUrl, server_jwt, bodyJson
|
|
, "application/json"
|
|
, "caliverse", "1.0" );
|
|
if (IsSuccessStatusCode == false)
|
|
result.setFail(ServerErrorCode.AiChatServerTokenExpired);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (result, readMsg);
|
|
}
|
|
|
|
static public async Task<(Result, string)> sendAIChatServer(string httpMethod, string url, string? jwt, string? bodyJson)
|
|
{
|
|
var result = new Result();
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
if (server_logic.getServerConfig().OfflineMode == true)
|
|
{
|
|
result.setFail(ServerErrorCode.AiChatServerInactive);
|
|
return (result, string.Empty);
|
|
}
|
|
|
|
var fullUrl = makeAiChatServerURL(url);
|
|
|
|
(var IsSuccessStatusCode, var readMsg) = await HttpClientHelper.sendHttpRequest( httpMethod
|
|
, fullUrl, jwt, bodyJson
|
|
, "application/json"
|
|
, "caliverse", "1.0" );
|
|
if (IsSuccessStatusCode == false)
|
|
{
|
|
Log.getLogger().info($"sendAIChatServer Failed. fullUrl : {fullUrl}, return msg : {readMsg} !!!");
|
|
|
|
result = ErrorHelper(readMsg, fullUrl);
|
|
return (result, readMsg);
|
|
}
|
|
|
|
return (result, readMsg);
|
|
}
|
|
|
|
static public string makeAiChatServerURL(string url)
|
|
{
|
|
return $"{GameServerApp.getServerLogic().getServerConfig().AIChatConfig.BaseAddress}{url}";
|
|
}
|
|
|
|
static private Result ErrorHelper(string errorMsg, string fullUrl)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
try
|
|
{
|
|
AIChatError? error = JsonConvert.DeserializeObject<AIChatError>(errorMsg);
|
|
NullReferenceCheckHelper.throwIfNull(error, () => $"error is null !!!");
|
|
|
|
switch (error.code)
|
|
{
|
|
case 998: result.setFail(ServerErrorCode.AiChatServerBadrequest, err_msg); break;
|
|
case 999: result.setFail(ServerErrorCode.AiChatServerForbidden, err_msg); break;
|
|
case 1000: result.setFail(ServerErrorCode.AiChatServerUnauthorized, err_msg); break;
|
|
case 1001: result.setFail(ServerErrorCode.AiChatServerUserNotFound, err_msg); break;
|
|
case 1002: result.setFail(ServerErrorCode.AiChatServerCharacterNotFound, err_msg); break;
|
|
case 1003: result.setFail(ServerErrorCode.AiChatServerReactionNotFound, err_msg); break;
|
|
case 1004: result.setFail(ServerErrorCode.AiChatServerExampleDialongNotFound, err_msg); break;
|
|
case 1005: result.setFail(ServerErrorCode.AiChatServerSessionNotFound, err_msg); break;
|
|
case 1006: result.setFail(ServerErrorCode.AiChatServerModelNotFound, err_msg); break;
|
|
case 1007: result.setFail(ServerErrorCode.AiChatServerNotEnoughPoint, err_msg); break;
|
|
case 1008: result.setFail(ServerErrorCode.AiChatServerInvalidParameters, err_msg); break;
|
|
case 1009: result.setFail(ServerErrorCode.AiChatServerSessionLimitExceeded, err_msg); break;
|
|
case 1010: result.setFail(ServerErrorCode.AiChatServerInvalidSignature, err_msg); break;
|
|
case 1011: result.setFail(ServerErrorCode.AiChatServerUserAlreadyExists, err_msg); break;
|
|
case 1012: result.setFail(ServerErrorCode.AiChatServerRemoveFailed, err_msg); break;
|
|
case 1013: result.setFail(ServerErrorCode.AiChatServerDuplicateGuid, err_msg); break;
|
|
case 1014: result.setFail(ServerErrorCode.AiChatServerDuplicateId, err_msg); break;
|
|
case 1015: result.setFail(ServerErrorCode.AiChatServerChatNotFound, err_msg); break;
|
|
case 1016: result.setFail(ServerErrorCode.AiChatServerTokenExpired, err_msg); break;
|
|
case 1017: result.setFail(ServerErrorCode.AiChatServerInternalServer, err_msg); break;
|
|
case 1018: result.setFail(ServerErrorCode.AiChatServerInvalidMessage, err_msg); break;
|
|
case 1019: result.setFail(ServerErrorCode.AiChatServerUserOnlyFeature, err_msg); break;
|
|
case 1020: result.setFail(ServerErrorCode.AiChatServerOwnershipError, err_msg); break;
|
|
|
|
case 1024: result.setFail(ServerErrorCode.AiChatServerChargeOrderNotFoundError, err_msg); break;
|
|
default:
|
|
{
|
|
err_msg = $"sendAIChatServer Failed. fullUrl : {fullUrl}, error code : {error.code}, error name : {error.name}, error message : {error.message} !!!";
|
|
result.setFail(ServerErrorCode.AiChatServerReqFailed, err_msg);
|
|
Log.getLogger().info(err_msg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
err_msg = $"AiChat Exception message : {ex.Message}";
|
|
result.setFail(ServerErrorCode.AiChatServerReqFailed, err_msg);
|
|
Log.getLogger().info(err_msg);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static private async Task<Result> RegisterGeneralNPC()
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
List<string> npclist = new();
|
|
|
|
var npcGeneralMetaDatas = MetaData.Instance.NpcGeneralMetaData;
|
|
|
|
foreach (var generalNpc in npcGeneralMetaDatas)
|
|
{
|
|
(result, var ai_chat_character) = await getCharacterByTargetGuid(generalNpc.Value.Npc_id.ToString());
|
|
if (result.isSuccess())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
EGenderType gender = EGenderType.MALE;
|
|
if(generalNpc.Value.Gender == EGenderType.ALL)
|
|
gender = EGenderType.MALE;
|
|
|
|
AIChatRegisterCharacter to_register_ai_chat_server = new();
|
|
to_register_ai_chat_server.guid = generalNpc.Value.Npc_id.ToString();
|
|
to_register_ai_chat_server.ownerUserGuid = string.Empty;
|
|
to_register_ai_chat_server.lang = generalNpc.Value.Language.ToString().ToLower();
|
|
to_register_ai_chat_server.name = generalNpc.Value.Name;
|
|
to_register_ai_chat_server.persona = UgcNpcHelper.toPersonaWithJsonString(generalNpc.Value.WorldScenario, generalNpc.Value.Description);
|
|
to_register_ai_chat_server.firstMes = generalNpc.Value.FirstMes;
|
|
to_register_ai_chat_server.shortDesc = generalNpc.Value.ShortDesc;
|
|
to_register_ai_chat_server.tags = generalNpc.Value.Tags.Select(x => (META_ID)x).ToList();
|
|
to_register_ai_chat_server.isOfficial = true;
|
|
to_register_ai_chat_server.socialActionConfig = UgcNpcHelper.toSocialActionConfigWithAIChatServer((META_ID)generalNpc.Value.SocialAction_default, generalNpc.Value.SocialAction_habit.Select(x => (META_ID)x).ToList());
|
|
to_register_ai_chat_server.attributes.gender = (int)gender;
|
|
|
|
string json = JsonConvert.SerializeObject(to_register_ai_chat_server);
|
|
var bodyParam = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
(result, string resMsg) = await sendAIChatServerWithServerJwt("POST", $"/api/character", json);
|
|
if (result.isFail())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|