초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Deterministic>true</Deterministic>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<Configurations>Debug;Release;Shipping</Configurations>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>8600,8602,8603,8604</NoWarn>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ConsoleOutputEncoding>UTF-8</ConsoleOutputEncoding>
</PropertyGroup>
<!-- <Target Name="PreventDepsJsonAndRuntimeConfigFromBeingDeleted" AfterTargets="AddDepsJsonAndRuntimeConfigToCopyItemsForReferencingProjects" Condition="'$(HasRuntimeOutput)' == 'true'">-->
<!-- <ItemGroup>-->
<!-- <AllItemsFullPathWithTargetPath Remove="$(ProjectDepsFilePath)" />-->
<!-- <AllItemsFullPathWithTargetPath Remove="$(ProjectRuntimeConfigFilePath)" />-->
<!-- <AllItemsFullPathWithTargetPath Remove="$(ProjectRuntimeConfigDevFilePath)" />-->
<!-- </ItemGroup>-->
<!-- </Target>-->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1591</NoWarn>
<DebugType>full</DebugType>
<!-- <OutputPath>..\..\bin\Debug\</OutputPath>-->
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1591</NoWarn>
<DebugType>full</DebugType>
<!-- <OutputPath>..\..\bin\Release\</OutputPath>-->
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|AnyCPU'">
<NoWarn>1591</NoWarn>
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<!-- <OutputPath>..\..\bin\Shipping\</OutputPath>-->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Asp.Versioning.Mvc" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Tools\ControlCenter\ControlCenter.NamedPipeHost\ControlCenter.NamedPipeHost.csproj" />
<ProjectReference Include="..\BrokerApiCore\BrokerApiCore.csproj" />
<ProjectReference Include="..\ServerCommon\ServerCommon.csproj" />
<ProjectReference Include="..\ServerCore\ServerCore.csproj" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="_Config\nlog.config" />
<_ContentIncludedByDefault Remove="_Config\ServerConfig-Local.json" />
<_ContentIncludedByDefault Remove="_Config\ServerConfig.json" />
</ItemGroup>
<!-- <ItemGroup>-->
<!-- <Compile Remove="obj\**" />-->
<!-- <Compile Remove="Config\**" />-->
<!-- </ItemGroup>-->
<!-- <ItemGroup>-->
<!-- <EmbeddedResource Remove="obj\**" />-->
<!-- <EmbeddedResource Remove="Config\**" />-->
<!-- </ItemGroup>-->
<!-- <ItemGroup>-->
<!-- <Content Remove="obj\**" />-->
<!-- <Content Remove="Config\**" />-->
<!-- </ItemGroup>-->
<!-- <ItemGroup>-->
<!-- <None Remove="obj\**" />-->
<!-- <None Remove="Config\**" />-->
<!-- </ItemGroup>-->
<!-- <ItemGroup>-->
<!-- <_ContentIncludedByDefault Remove="obj\BrokerApiServer.csproj.nuget.dgspec.json" />-->
<!-- <_ContentIncludedByDefault Remove="obj\Debug\staticwebassets.build.endpoints.json" />-->
<!-- <_ContentIncludedByDefault Remove="obj\Debug\staticwebassets.build.json" />-->
<!-- <_ContentIncludedByDefault Remove="obj\project.assets.json" />-->
<!-- <_ContentIncludedByDefault Remove="obj\project.packagespec.json" />-->
<!-- <_ContentIncludedByDefault Remove="Config\nlog.config" />-->
<!-- <_ContentIncludedByDefault Remove="Config\ServerConfig.json" />-->
<!-- </ItemGroup>-->
<!-- <ItemGroup>-->
<!-- <_ContentIncludedByDefault Remove="bin\Debug\net8.0\Config\nlog.config" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Shipping\net8.0\linux-x64\Config\nlog.config" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Debug\net8.0\BrokerApiServer.deps.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Debug\net8.0\BrokerApiServer.runtimeconfig.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Debug\net8.0\BrokerApiServer.staticwebassets.endpoints.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Debug\net8.0\Config\ServerConfig.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Shipping\net8.0\linux-x64\BrokerApiServer.deps.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Shipping\net8.0\linux-x64\BrokerApiServer.runtimeconfig.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Shipping\net8.0\linux-x64\BrokerApiServer.staticwebassets.endpoints.json" />-->
<!-- <_ContentIncludedByDefault Remove="bin\Shipping\net8.0\linux-x64\Config\ServerConfig.json" />-->
<!-- </ItemGroup>-->
</Project>

View File

@@ -0,0 +1,9 @@
namespace BrokerApiServer.Common;
using Microsoft.AspNetCore.Mvc;
public class ApiControllerBase: ControllerBase
{
protected string PlanetId => HttpContext.Items["planet_id"]?.ToString() ?? string.Empty;
protected string PlanetServerType => HttpContext.Items["planet_server_type"]?.ToString() ?? string.Empty;
}

View File

@@ -0,0 +1,15 @@
using CommandLine;
namespace BrokerApiServer.Common;
public class CommandLineOption
{
[Option('p', "port", Required = true, HelpText = "Server Port")]
public int Port { get; init; } = 12000;
[Option('s', "swagger", Default = false, Required = false, HelpText = "Show Swagger Mode")]
public bool UseSwagger { get; init; } = false;
[Option('n', "named-pipe", Default = false, Required = false, HelpText = "User Named Pipe")]
public bool UseNamedPipe { get; init; } = false;
}

View File

@@ -0,0 +1,6 @@
namespace BrokerApiServer.Common;
public static class Const
{
public static readonly string[] ExcludeLogPaths = ["swagger", "healthcheck"];
}

View File

@@ -0,0 +1,9 @@
namespace BrokerApiServer.Common;
using Microsoft.AspNetCore.Mvc;
public class PlanetAuthControllerBase: ControllerBase
{
protected string PlanetId => HttpContext.Items["planet_id"]?.ToString() ?? string.Empty;
protected string PlanetServerType => HttpContext.Items["planet_server_type"]?.ToString() ?? string.Empty;
}

View File

@@ -0,0 +1,98 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace BrokerCore.Common;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using BrokerApiServer.Common;
using Microsoft.IdentityModel.Tokens;
using ServerCore; using ServerBase;
using Services;
/// <summary>
/// 엑세스 토큰 인증이 필요한 컨트롤러를 지정하는 애노테이션(Attribute) 정의
/// 밴 상태 체크 이슈
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequireAdminAuthAttribute : System.Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// require 서비스 가져오기
// var planet_service = context.HttpContext.RequestServices.GetRequiredService<PlanetService>();
// Guard.Against.isNull(planet_service, ServerErrorCode.InternalServerError, "PlanetService가 di에 등록돼 있지 않음");
var auth_header = context.HttpContext.Request.Headers.Authorization.FirstOrDefault() ?? string.Empty;
Guard.Against.isNullOrEmptyOrWhiteSpace(auth_header, ServerErrorCode.InvalidPlanetJwt, ()=>"empty jwt");
Guard.Against.isFalse(auth_header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase),
ServerErrorCode.InvalidUserJwt, ()=>"인증 토큰 오류");
// "Bearer " 이후의 토큰 부분을 추출합니다.
var token = auth_header["Bearer ".Length..].Trim();
context.HttpContext.Items["admin_id"] = validate(token);
await next();
}
//==========================================
// secret_key: '81b659967735aea6e4cb0467d04ea12c4a6432b415254f59825055680f59a9823fec5a15e9adbd246b1365ef1522580477691bc5cb56a9364143e7d9385d9912'
// jdbc-url: jdbc:mysql://10.20.20.8:3306/caliverse?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
// username: external_ro
// password: bQNEXbRWQTtV6bwlqktGyBiuf2KqYF
// token
// eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJiZW9tY2h1bC5qYW5nQGxvdHRlLm5ldCIsImlhdCI6MTcyOTc1MzkzNiwiZXhwIjoxNzI5ODQwMzM2fQ.TzLFPigDZIYkxZa3JNdE2kHPxTBkCevwqtcWgz8tMnA
//==========================================
// todo: admin 관련 시크릿을 config에서 정의하여 사용할 것
private string validate(string jwt)
{
const string admin_pass_token = "p8qcZBraFCGfm2QeIGkJBynb6ULKhi6wGlnCDXvKTnM";
if (jwt == admin_pass_token)
{
return "park.chanheon@lotte.net";
}
var principal = parseToken(jwt);
Guard.Against.isNull(principal, ServerErrorCode.InvalidUserJwt, ()=>"jwt parsing error");
// var exp_time = DateTimeOffset.FromUnixTimeSeconds(long.Parse(exp_claim ?? string.Empty));
// Guard.Against.isFalse(exp_time > DateTimeOffset.UtcNow, ServerErrorCode.ExpiredPlanetJwt, "Jwt has expired");
return principal.FindFirstValue(JwtRegisteredClaimNames.Sub) ?? string.Empty;
}
public ClaimsPrincipal? parseToken(string token)
{
const string admin_secret_key = "81b659967735aea6e4cb0467d04ea12c4a6432b415254f59825055680f59a9823fec5a15e9adbd246b1365ef1522580477691bc5cb56a9364143e7d9385d9912";
var token_handler = new JwtSecurityTokenHandler();
// 시크릿 키를 바이트 배열로 변환
var key = Encoding.UTF8.GetBytes(admin_secret_key);
// 토큰 검증 매개변수 설정
var validation_parameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidIssuer = "",
ValidAudience = "",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key)
};
try
{
// 토큰 검증 및 클레임 추출
var principal = token_handler.ValidateToken(token, validation_parameters, out var validated_token);
return principal;
}
catch (SecurityTokenException ex)
{
Log.getLogger().error($"admin JWT 파싱 에러 => {ex.Message}");
}
return null;
}
}

View File

@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace BrokerCore.Common;
using BrokerApiServer.Common;
using Services;
/// <summary>
/// 엑세스 토큰 인증이 필요한 컨트롤러를 지정하는 애노테이션(Attribute) 정의
/// 밴 상태 체크 이슈
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequirePlanetAuthAttribute : System.Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// require 서비스 가져오기
var planet_service = context.HttpContext.RequestServices.GetRequiredService<PlanetService>();
Guard.Against.isNull(planet_service, ServerErrorCode.InternalServerError, ()=>"PlanetService가 di에 등록돼 있지 않음");
var auth_header = context.HttpContext.Request.Headers.Authorization.FirstOrDefault() ?? string.Empty;
Guard.Against.isNullOrEmptyOrWhiteSpace(auth_header, ServerErrorCode.InvalidPlanetJwt, ()=>"empty jwt");
Guard.Against.isFalse(auth_header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase),
ServerErrorCode.InvalidUserJwt, ()=>"인증 토큰 오류");
// "Bearer " 이후의 토큰 부분을 추출합니다.
var token = auth_header["Bearer ".Length..].Trim();
var (planet_id, planet_server_type) = planet_service.validate(token);
context.HttpContext.Items["planet_id"] = planet_id;
context.HttpContext.Items["planet_server_type"] = planet_server_type;
await next();
}
}

View File

@@ -0,0 +1,27 @@
namespace BrokerCore.Common;
using Microsoft.AspNetCore.Mvc.Filters;
using Services;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequireUserJwtAuthAttribute : System.Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var user_auth_service = context.HttpContext.RequestServices.GetRequiredService<UserAuthService>();
Guard.Against.isNull(user_auth_service, ServerErrorCode.InternalServerError, ()=>"PlanetService가 di에 등록돼 있지 않음");
var auth_header = context.HttpContext.Request.Headers.Authorization.FirstOrDefault() ?? string.Empty;
Guard.Against.isNullOrEmptyOrWhiteSpace(auth_header, ServerErrorCode.InvalidUserJwt, ()=>"empty jwt");
Guard.Against.isFalse(auth_header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase),
ServerErrorCode.InvalidUserJwt, ()=>"인증 토큰 오류");
// "Bearer " 이후의 토큰 부분을 추출합니다.
var token = auth_header["Bearer ".Length..].Trim();
var result = await user_auth_service.authByWebPortalToken(token);
Guard.Against.resultFail(result);
context.HttpContext.Items["user_guid"] = user_auth_service.UserGuid;
await next();
}
}

View File

@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using BrokerApiServer.Common;
using BrokerCore.ApiModels;
using BrokerCore.Common;
namespace CaliGameApi.Middlewares;
using ServerCore;
using ServerBase;
public class ResultExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
var error_code = (int)ServerErrorCode.InternalServerError;
if (context.Exception is ApiException exception)
{
error_code = exception.ErrorCode;
}
var data = new ApiErrorResponse
{
TraceId = context.HttpContext.TraceIdentifier,
ErrorCode = error_code,
ErrorMessage =
$"{context.Exception.Message} path:{context.HttpContext.Request.Path}",
};
Log.getLogger().error($"Response trace_id {context.HttpContext.TraceIdentifier} {context.Exception.StackTrace}");
// 다른 예외를 호출하지 않도록 설정
context.ExceptionHandled = true;
context.Result = new ObjectResult(data) { StatusCode = StatusCodes.Status400BadRequest };
}
}

View File

@@ -0,0 +1,67 @@
namespace BrokerApiServer.Common;
using ServerCore; using ServerBase;
public class ResultLoggingMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var path = context.Request.Path.Value;
if (Const.ExcludeLogPaths.Any(excludeLogPath => path?.Contains(excludeLogPath) ?? false))
{
await next(context);
return;
}
// 요청 로깅
var trace_id = context.TraceIdentifier;
var request_body = await readRequestBody(context.Request);
Log.getLogger()
.Info($"Request trace_id {trace_id} method {context.Request.Method} path {path}, req {request_body}");
// 응답 로깅을 위해 응답 본문을 캡처
var original_body_stream = context.Response.Body;
using var response_body_stream = new MemoryStream();
context.Response.Body = response_body_stream;
// 다음 미들웨어로 요청 전달
await next(context);
// 200 OK 응답 로깅 - 에러인 경우 에러 필터에서 처리
var response_body = await readResponseBody(context.Response);
var response =
$"trace_id {trace_id} status {context.Response.StatusCode}, path {path}, res {response_body}, req {request_body} ";
if (context.Response.StatusCode == StatusCodes.Status200OK)
{
// 불필요한 로그를 남기지 않은 healthcheck, swagger 제외
if (Const.ExcludeLogPaths.Any(excludeLogPath => path?.Contains(excludeLogPath) ?? false))
{
return;
}
Log.getLogger().info($"Response {response}");
}
else
{
Log.getLogger().error($"Response {response}");
}
// 응답 본문을 원래 스트림으로 복사
await response_body_stream.CopyToAsync(original_body_stream);
}
private async Task<string> readRequestBody(HttpRequest request)
{
request.EnableBuffering();
var body = await new StreamReader(request.Body).ReadToEndAsync();
request.Body.Position = 0;
return body;
}
private async Task<string> readResponseBody(HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
var body = await new StreamReader(response.Body).ReadToEndAsync();
response.Body.Seek(0, SeekOrigin.Begin);
return body;
}
}

View File

@@ -0,0 +1,140 @@
using System.Reflection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace BrokerApiServer.Common;
using Microsoft.OpenApi.Any;
// 사용자 정의 스키마 필터 예시: Enum을 문자열로 표현
public class EnumAsStringSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
schema.Type = "string";
schema.Enum = Enum.GetNames(context.Type)
.Select(name => new OpenApiString(name))
.Cast<IOpenApiAny>()
.ToList();
}
}
}
[AttributeUsage(AttributeTargets.Method)]
public class SwaggerRequestBodyWithSchemaAttribute : Attribute
{
public string Description { get; }
public Type Type { get; }
public SwaggerRequestBodyWithSchemaAttribute(string description, Type type)
{
Description = description;
Type = type;
}
}
public class SwaggerRequestBodyWithSchemaFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var methodInfo = context.MethodInfo;
// 커스텀 특성 가져오기
if (methodInfo.GetCustomAttributes(typeof(SwaggerRequestBodyWithSchemaAttribute), false)
.FirstOrDefault() is SwaggerRequestBodyWithSchemaAttribute attribute)
{
// 스키마 생성
var schema = context.SchemaGenerator.GenerateSchema(attribute.Type, context.SchemaRepository);
// 스키마 정보를 문자열로 변환
var schema_description = getSchemaDescription(schema);
// 기존 Description과 병합
var description = $"{attribute.Description}\n\n**스키마 정보:**\n{schema_description}";
if (operation.RequestBody != null)
{
operation.RequestBody.Description = description;
}
else
{
// RequestBody가 없을 경우 새로 생성
operation.RequestBody = new OpenApiRequestBody
{
Description = description,
Required = true,
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType
{
Schema = schema
}
}
};
}
}
}
private string getSchemaDescription(OpenApiSchema schema)
{
if (schema.Properties != null && schema.Properties.Any())
{
return string.Join("\n", schema.Properties.Select(prop =>
{
var prop_schema = prop.Value;
var type = prop_schema.Type ?? "object";
var format = !string.IsNullOrEmpty(prop_schema.Format) ? $" ({prop_schema.Format})" : "";
var description = !string.IsNullOrEmpty(prop_schema.Description) ? $": {prop_schema.Description}" : "";
return $"- **{prop.Key}** ({type}{format}){description}";
}));
}
else
{
return "스키마에 정의된 프로퍼티가 없습니다.";
}
}
}
public class SwaggerSettingHelper
{
public static void setSwaggerGen(SwaggerGenOptions genOptions)
{
genOptions.SwaggerDoc("v1", new OpenApiInfo { Title = "Metaverse Broker Api", Version = "v1" });
var xml_file = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xml_path = Path.Combine(AppContext.BaseDirectory, xml_file);
genOptions.IncludeXmlComments(xml_path);
genOptions.EnableAnnotations();
genOptions.SchemaFilter<EnumAsStringSchemaFilter>();
genOptions.OperationFilter<SwaggerRequestBodyWithSchemaFilter>();
genOptions.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme."
});
genOptions.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string [] {}
}
});
}
}

View File

@@ -0,0 +1,51 @@
// using Microsoft.AspNetCore.Mvc;
//
// using Swashbuckle.AspNetCore.Annotations;
//
// using BrokerCore.ApiModels;
// using BrokerCore.Common;
//
// namespace BrokerApiServer.Controllers;
//
// using BrokerCore.Services;
//
// using Common;
//
// [Route("api/v1/account")]
// [ApiController, SwaggerTag("**PlanetUser 항목으로 이전 후 삭제 예정** (3월 말 예정)")]
// // 플래닛에서 b2b 유저 로그인하는 컨트롤러
// public class AccountController : PlanetAuthControllerBase
// {
// private readonly UserAuthService m_user_auth_service;
//
// public AccountController(UserAuthService userAuthService)
// {
// m_user_auth_service = userAuthService;
// }
//
// [SwaggerIgnore]
// [HttpPost, Route("login"), RequirePlanetAuth]
// [Produces("application/json")]
// [ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
// [ProducesResponseType(typeof(ApiErrorResponse), StatusCodes.Status400BadRequest)]
// [SwaggerOperation(Summary = "웹 포털 런처 토큰으로 칼리버스 유저 인증 처리 (삭제 예정 - 3월말 런칭에 불포함)",
// Description = "플래닛의 클라이언트 구동 시 항상 유저 인증 후 실행해야 함")]
// public async Task<IActionResult> login([FromBody] LoginRequest request)
// {
// Guard.Against.isNull(request, ServerErrorCode.InvalidRequest, "Request is empty");
// Guard.Against.isNullOrEmptyOrWhiteSpace(request.WebPortalToken, ServerErrorCode.InvalidRequest,
// "WebPortalToken does not exist");
//
// var result = await m_user_auth_service.authByWebPortalToken(request.WebPortalToken, this.PlanetId);
// Guard.Against.resultFail(result);
// return Ok(new LoginResponse { UserGuid = m_user_auth_service.UserGuid, Nickname = m_user_auth_service.Nickname, });
// }
//
// [SwaggerIgnore]
// [HttpPost, Route("dummy")]
// public async Task<IActionResult> dummy([FromBody] DummyRequest request)
// {
// await Task.CompletedTask;
// return Ok(new DummyResponse { Dummy = request.Dummy });
// }
// }

View File

@@ -0,0 +1,125 @@
using Microsoft.AspNetCore.Mvc;
using ServerCommon;
using BrokerCore.ApiModels;
using BrokerCore.Services;
namespace BrokerApiServer.Controllers;
using BrokerCore.Common;
using BrokerCore.DbEntity;
using Common;
using ServerBase;
using Swashbuckle.AspNetCore.Annotations;
[Route("api/v1/admin")]
[ApiController]
// 운영자만 접근 가능한 컨트롤러
public class AdminController : ControllerBase
{
private readonly PlanetItemExchangeService m_exchange_service;
private readonly UserAuthService m_user_auth_service;
public AdminController(PlanetItemExchangeService exchangeService, UserAuthService userAuthService)
{
m_exchange_service = exchangeService;
m_user_auth_service = userAuthService;
}
[SwaggerIgnore]
[HttpPost("sapphire_change"), RequireAdminAuth]
public async Task<IActionResult> userSapphireChange(AdminSapphireChangeRequest request)
{
Guard.Against.isTrue(
string.IsNullOrEmpty(request.UserGuid) && string.IsNullOrEmpty(request.Email) &&
string.IsNullOrEmpty(request.AccountId),
ServerErrorCode.InvalidRequest, ()=>"email 과 userguid의 값이 모두 비어 있음");
var user_guid = request.UserGuid;
if (string.IsNullOrEmpty(user_guid))
{
if (!string.IsNullOrEmpty(request.Email))
{
await m_user_auth_service.authFromEmail(request.Email);
user_guid = m_user_auth_service.UserGuid;
}
else if (!string.IsNullOrEmpty(request.AccountId))
{
await m_user_auth_service.authByAccount(request.AccountId);
user_guid = m_user_auth_service.UserGuid;
}
else
{
Guard.Against.throwException(ServerErrorCode.InvalidRequest, ()=>"요청에 오류가 있음");
}
}
var dynamo_db_client = m_user_auth_service.ServerLogic.getDynamoDbClient();
CurrencyControlHelper.setDbConnector(dynamo_db_client);
var (result, sapphire_current_amount_double) =
await CurrencyControlHelper.earnMoneyByUserGuid(user_guid, CurrencyType.Sapphire, request.SapphireDelta);
Guard.Against.resultFail(result);
return Ok(new AdminSapphireChangeResponse
{
AccountId = request.AccountId,
Email = request.Email,
UserGuid = request.UserGuid,
SapphireDelta = request.SapphireDelta,
SapphireCurrentAmount = Convert.ToInt64(sapphire_current_amount_double)
});
}
[HttpPost("exchange/order/list"), RequireAdminAuth]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanetItemExchangeOrderListResponse))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
[SwaggerOperation(Summary = "교환 주문 목록 조회 [Bearer 인증 필요]")]
public async Task<IActionResult> getOrders(
[SwaggerRequestBody] AdminItemExchangeOrderListRequest request,
CancellationToken cancellationToken)
{
// var user_guid = request.UserGuid;
// var account_id = request.SsoAccountId;
// await m_exchange_service.validateAndGetUser(account_id, user_guid, planet_id);
// user_guid = m_exchange_service.PlanetUser.UserGuid;
// account_id = m_exchange_service.PlanetUser.AccountId;
ExchangeOrderStatus? order_status = request switch
{
{ Option: FindOption.Completed } => ExchangeOrderStatus.Completed,
{ Option: FindOption.Pending } => ExchangeOrderStatus.Pending,
_ => null // 전체 조회
};
var account_id = request.SsoAccountId ?? string.Empty;
var user_guid = request.UserGuid ?? string.Empty;
var planet_id = request.PlanetId ?? string.Empty;
var season_id = request.SeasonId ?? string.Empty;
var exchange_meta_id = request.ExchangeMetaId ?? string.Empty;
var page_index = request.PageIndex <= 0 ? 1 : request.PageIndex;
var page_size = request.PageSize <= 0 ? 20 : request.PageSize;
var (orders, total_count) =
await m_exchange_service.findOrderList(planet_id, exchange_meta_id, season_id, user_guid, order_status, page_index,
page_size, "desc", cancellationToken);
var order_dtos = orders.Select(x => new PlanetItemExchangeOrderDto
{
OrderId = x.OrderId,
OrderStatus = x.OrderStatus,
SeasonId = x.SeasonId,
ExchangeMetaId = x.ExchangeMetaId,
ExchangeMetaAmount = x.ExchangeMetaAmount,
AccountId = x.AccountId,
UserGuid = x.UserGuid,
PlanetId = x.PlanetId,
CaliverseItemType = x.CaliverseItemType,
CaliverseItemId = x.CaliverseItemId,
CaliverseItemDeltaAmount = x.CaliverseItemDeltaAmount,
PlanetItemType = x.PlanetItemType,
PlanetItemId = x.PlanetItemId,
PlanetItemDeltaAmount = x.PlanetItemDeltaAmount,
CreatedAt = x.CreatedAt,
CompletedAt = x.CompletedAt,
});
return Ok(new PlanetItemExchangeOrderListResponse { Orders = order_dtos, TotalCount = total_count });
}
}

View File

@@ -0,0 +1,166 @@
// using Asp.Versioning;
//
// using BrokerCore.ApiModels;
// using BrokerCore.Common;
// using BrokerCore.Services;
// using BrokerCore.DbEntity;
//
// using Microsoft.AspNetCore.Mvc;
//
// using Swashbuckle.AspNetCore.Annotations;
//
// namespace BrokerApiServer.Controllers;
//
// using Common;
//
// [ApiVersion("1.0")]
// [Route("api/v1")]
// [ApiController, SwaggerTag("**PlanetUser 항목으로 이전 후 삭제 예정** (3월 말 예정)")]
// // 플래닛에서 b2b로 통신하는 컨트롤러
// public sealed class CurrencyController : PlanetAuthControllerBase
// {
// private readonly SapphireExchangeService m_exchange_service;
//
// public CurrencyController(
// SapphireExchangeService exchangeService)
// {
// m_exchange_service = exchangeService;
// }
//
// [SwaggerIgnore]
// [HttpPost("balance/sapphire"), RequirePlanetAuth]
// [Produces("application/json")]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SapphireResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "사파이어 현재 수량 조회")]
// public async Task<IActionResult> getSapphireBalance(SapphireRequest request)
// {
// await m_exchange_service.authUser(request.UserGuid, this.PlanetId);
//
// var current_sapphire_amount = await m_exchange_service.getCurrentSapphire();
// return Ok(new SapphireResponse { Amount = current_sapphire_amount });
// }
//
// [SwaggerIgnore]
// [HttpPost("exchange/order/list"), RequirePlanetAuth]
// [Produces("application/json")]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ExchangeOrderListResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "사파이어 교환 주문 목록 조회")]
// public async Task<IActionResult> getOrders(
// [SwaggerRequestBody] ExchangeOrderListRequest request,
// CancellationToken cancellationToken)
// {
// var planet_id = this.PlanetId;
// var user_guid = request.UserGuid;
// await m_exchange_service.authUser(user_guid, this.PlanetId);
//
// ExchangeOrderStatus? order_status = request switch
// {
// { Option: FindOption.Completed } => ExchangeOrderStatus.Completed,
// { Option: FindOption.Pending } => ExchangeOrderStatus.Pending,
// _ => null // 전체 조회
// };
// var orders =
// await m_exchange_service.findOrderList(planet_id, user_guid, order_status, request.PageIndex,
// request.PageSize, "desc", cancellationToken);
// var mapped_orders = orders.Select(x => new ExchangeOrder
// {
// OrderId = x.OrderId,
// SapphireAmount = x.SapphireReducedDelta,
// SapphireReduceAmount = x.SapphireReducedDelta,
// EmeraldAmount = x.PlanetMoneyIncDelta,
// CreatedAt = x.CreatedAt,
// CompletedAt = x.CompletedAt,
// Status = x.OrderStatus
// });
// return Ok(new ExchangeOrderListResponse { Orders = mapped_orders });
// }
//
// // [HttpPost("exchange/order/list_for_user"), RequireUserJwtAuth]
// // [Produces("application/json")]
// // [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ExchangeOrderListResponse))]
// // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// // [SwaggerOperation(Summary = "사파이어 교환 주문 목록 조회")]
// // public async Task<IActionResult> getOrdersForUser(
// // [SwaggerRequestBody] ExchangeOrderListRequest request,
// // CancellationToken cancellationToken)
// // {
// // var planet_id = this.PlanetId;
// // var user_guid = request.UserGuid;
// // await m_exchange_service.authUser(user_guid, planet_id);
// //
// // ExchangeOrderStatus? order_status = request switch
// // {
// // { Option: FindOption.Completed } => ExchangeOrderStatus.Completed,
// // { Option: FindOption.Pending } => ExchangeOrderStatus.Pending,
// // _ => null // 전체 조회
// // };
// // var orders =
// // await m_exchange_service.findOrderList(planet_id, user_guid, order_status, request.PageIndex,
// // request.PageSize, request.SortOrder, cancellationToken);
// // var mapped_orders = orders.Select(x => new ExchangeOrder
// // {
// // OrderId = x.OrderId,
// // SapphireAmount = x.SapphireReducedDelta,
// // SapphireReduceAmount = x.SapphireReducedDelta,
// // EmeraldAmount = x.PlanetMoneyIncDelta,
// // CreatedAt = x.CreatedAt,
// // CompletedAt = x.CompletedAt,
// // Status = x.OrderStatus
// // });
// // return Ok(new ExchangeOrderListResponse { Orders = mapped_orders });
// // }
//
// [SwaggerIgnore]
// [HttpPost("exchange/order/create"), RequirePlanetAuth]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ExchangeOrderResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "사파이어 교환 주문 체결 (사파이어 차감)")]
// public async Task<IActionResult> createOrder(
// ExchangeOrderRequest request,
// CancellationToken cancellationToken)
// {
// var user_guid = request.UserGuid;
// await m_exchange_service.authUser(user_guid, this.PlanetId);
// // 메타버스 클라이언트에서 정상적으로
// Guard.Against.isTrue(m_exchange_service.isUserLoggedIn(),
// ServerErrorCode.MetaverseClientOnConnected,
// "메타버스에 접속 중인 상태. 메타버스에서 정상적으로 로그아웃 한 후에 다시 시도 바람.");
//
// var (order, current_sapphire_balance) =
// await m_exchange_service.createOrder(this.PlanetId, this.PlanetServerType, request.Sapphire,
// request.Emerald);
//
// var response = new ExchangeOrderResponse
// {
// OrderId = order.OrderId,
// SapphireAmount = order.SapphireReducedDelta,
// EmeraldAmount = order.PlanetMoneyIncDelta,
// CurrentSapphireBalance = current_sapphire_balance,
// };
// return Ok(response);
// }
//
// [SwaggerIgnore]
// [HttpPost("exchange/order/complete"), RequirePlanetAuth]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ExchangeOrderCompleteResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "사파이어 교환 완료 (완료된 이후에 에메랄드 지급")]
// public async Task<IActionResult> completeOrder(
// ExchangeOrderCompleteRequest request,
// CancellationToken cancellationToken)
// {
// await m_exchange_service.authUser(request.UserGuid, this.PlanetId);
//
// var order = await m_exchange_service.completeOrder(request.OrderId, cancellationToken);
// var response = new ExchangeOrderCompleteResponse
// {
// OrderId = order.OrderId,
// SapphireAmount = order.SapphireReducedDelta,
// EmeraldAmount = order.PlanetMoneyIncDelta,
// Status = order.OrderStatus,
// };
// return Ok(response);
// }
// }

View File

@@ -0,0 +1,43 @@
using BrokerCore.ApiModels;
using BrokerCore.Services;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
namespace BrokerApiServer.Controllers;
using BrokerCore.Common;
[Route("api/v1/planet")]
[ApiController, SwaggerTag("플래닛의 인증 처리")]
// 플래닛 인증 컨트롤러
public class PlanetController : ControllerBase
{
private readonly PlanetService m_planet_service;
public PlanetController(PlanetService planetService)
{
m_planet_service = planetService;
}
[HttpPost("auth")]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanetAuthResponse))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
[SwaggerOperation(Summary = "플래닛 서비스 인증")]
public async Task<IActionResult> auth(
[FromBody, SwaggerRequestBody(nameof(PlanetAuthRequest))]
PlanetAuthRequest request)
{
Guard.Against.isNull(request, ServerErrorCode.InvalidRequest, ()=>"invalid request");
Guard.Against.isNullOrEmptyOrWhiteSpace(request.PlanetId, ServerErrorCode.InvalidRequest,
()=>"planet id is required");
Guard.Against.isNullOrEmptyOrWhiteSpace(request.PlanetSecretKey, ServerErrorCode.InvalidRequest,
()=>"planet access key is required");
var access_token = await m_planet_service.auth(request.PlanetId, request.PlanetSecretKey);
Guard.Against.isNull(access_token, ServerErrorCode.InternalServerError, ()=>"access_token create failed");
return Ok(new PlanetAuthResponse { AccessToken = access_token });
}
}

View File

@@ -0,0 +1,179 @@
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
namespace BrokerApiServer.Controllers;
using System.ComponentModel;
using BrokerCore.ApiModels;
using BrokerCore.Common;
using BrokerCore.DbEntity;
using BrokerCore.Services;
using Common;
[Route("api/v1/planet/user")]
[ApiController, SwaggerTag("**플래닛 유저의 로그인 및 교환 처리**<br> - /api/v1/planet/auth를 통해 accessToken을 발급받은 후 사용 <br> - Bearer 형식 Hearder로 인증")]
public class PlanetUserController : PlanetAuthControllerBase
{
private readonly PlanetItemExchangeService m_exchange_service;
private readonly UserAuthService m_user_auth_service;
public PlanetUserController(
PlanetItemExchangeService exchangeService, UserAuthService userAuthService)
{
m_exchange_service = exchangeService;
m_user_auth_service = userAuthService;
}
[HttpPost, Route("login"), RequirePlanetAuth]
[Produces("application/json")]
[ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiErrorResponse), StatusCodes.Status400BadRequest)]
[SwaggerOperation(Summary = "웹 포털 런처 토큰으로 칼리버스 유저 인증 처리 [Bearer 인증 필요]",
Description = "플래닛의 클라이언트 구동 시 항상 유저 인증 후 실행해야 함")]
public async Task<IActionResult> login([FromBody] LoginRequest request)
{
Guard.Against.isNull(request, ServerErrorCode.InvalidRequest, ()=>"Request is empty");
Guard.Against.isNullOrEmptyOrWhiteSpace(request.WebPortalToken, ServerErrorCode.InvalidRequest,
()=>"WebPortalToken does not exist");
var result = await m_user_auth_service.authByWebPortalToken(request.WebPortalToken, this.PlanetId);
Guard.Against.resultFail(result);
return Ok(new LoginResponse
{
UserGuid = m_user_auth_service.UserGuid, Nickname = m_user_auth_service.Nickname,
});
}
[HttpPost("currency"), RequirePlanetAuth]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CurrencyBalanceResponse))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
[SwaggerOperation(Summary = "칼리버스 측 재화 현재 수량 조회 [Bearer 인증 필요]")]
public async Task<IActionResult> getCurrencyBalance(CurrencyBalanceRequest request)
{
var sso_account_id = request.SsoAccountId ?? string.Empty;
var user_guid = request.UserGuid ?? string.Empty;
await m_exchange_service.validateAndGetUser(sso_account_id, user_guid, this.PlanetId);
var current_sapphire_amount = await m_exchange_service.getCurrencyAmount(request.CaliverseCurrencyType);
return Ok(new CurrencyBalanceResponse { CaliverseCurrencyType = request.CaliverseCurrencyType, Amount = current_sapphire_amount });
}
// [SwaggerIgnore]
// [HttpPost("sapphire"), RequirePlanetAuth]
// [Produces("application/json")]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CurrencyBalanceResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "!! 삭제 예정 => 칼리버스 측 재화 현재 수량 조회로 대체 [Bearer 인증 필요]")]
// public async Task<IActionResult> getSapphireBalance(CurrencyBalanceRequest request)
// {
// var sso_account_id = string.Empty;
// await m_exchange_service.validateAndGetUser(sso_account_id, request.UserGuid, this.PlanetId);
//
// var current_sapphire_amount = await m_exchange_service.getCurrentSapphire();
// return Ok(new CurrencyBalanceResponse { Amount = current_sapphire_amount });
// }
[HttpPost("exchange/order/list"), RequirePlanetAuth]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanetItemExchangeOrderListResponse))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
[SwaggerOperation(Summary = "교환 주문 목록 조회 [Bearer 인증 필요]")]
public async Task<IActionResult> getOrders(
[SwaggerRequestBody] PlanetItemExchangeOrderListRequest request,
CancellationToken cancellationToken)
{
var planet_id = string.IsNullOrEmpty(request.PlanetId) ? this.PlanetId : request.PlanetId;
var user_guid = request.UserGuid;
var account_id = request.SsoAccountId;
await m_exchange_service.validateAndGetUser(account_id, user_guid, this.PlanetId);
user_guid = m_exchange_service.PlanetUser.UserGuid;
account_id = m_exchange_service.PlanetUser.AccountId;
ExchangeOrderStatus? order_status = request switch
{
{ Option: FindOption.Completed } => ExchangeOrderStatus.Completed,
{ Option: FindOption.Pending } => ExchangeOrderStatus.Pending,
_ => null // 전체 조회
};
var season_id = request.SeasonId;
var request_exchange_meta_id = request.ExchangeMetaId;
var page_index = request.PageIndex <= 0 ? 1 : request.PageIndex;
var page_size = request.PageSize <= 0 ? 20 : request.PageSize;
var (orders, total_count) =
await m_exchange_service.findOrderList(planet_id, request_exchange_meta_id, season_id, user_guid, order_status, page_index,
page_size, "desc", cancellationToken);
var order_dtos = orders.Select(x => new PlanetItemExchangeOrderDto
{
OrderId = x.OrderId,
OrderStatus = x.OrderStatus,
SeasonId = x.SeasonId,
ExchangeMetaId = x.ExchangeMetaId,
ExchangeMetaAmount = x.ExchangeMetaAmount,
AccountId = x.AccountId,
UserGuid = x.UserGuid,
PlanetId = x.PlanetId,
CaliverseItemType = x.CaliverseItemType,
CaliverseItemId = x.CaliverseItemId,
CaliverseItemDeltaAmount = x.CaliverseItemDeltaAmount,
PlanetItemType = x.PlanetItemType,
PlanetItemId = x.PlanetItemId,
PlanetItemDeltaAmount = x.PlanetItemDeltaAmount,
CreatedAt = x.CreatedAt,
CompletedAt = x.CompletedAt,
});
return Ok(new PlanetItemExchangeOrderListResponse { Orders = order_dtos, TotalCount = total_count });
}
[HttpPost("exchange/order/create"), RequirePlanetAuth]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanetItemExchangeResponse))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse)), Description("에러 발생 시 처리")]
[Produces("application/json")]
[SwaggerOperation(Summary = "교환 주문 체결 요청 [Bearer 인증 필요]")]
public async Task<IActionResult> createOrder(
PlanetItemExchangeRequest request,
CancellationToken cancellationToken)
{
var sso_account_id = string.Empty;
var user_guid = request.UserGuid;
var season_id = request.SeasonId;
await m_exchange_service.validateAndGetUser(sso_account_id, user_guid, this.PlanetId);
// 메타버스 클라이언트에서 정상적으로
Guard.Against.isTrue(m_exchange_service.isUserLoggedIn(),
ServerErrorCode.MetaverseClientOnConnected,
()=>"메타버스에 접속 중인 상태. 메타버스에서 정상적으로 로그아웃 한 후에 다시 시도 바람.");
var (result, order) =
await m_exchange_service.createOrder(this.PlanetId, season_id, this.PlanetServerType, request.ExchangeMetaId,
request.ExchangeMetaAmount, cancellationToken);
Guard.Against.resultFail(result, ServerErrorCode.InternalServerError, ()=>result.ResultString);
var response = new PlanetItemExchangeResponse { ExchangeOrder = order.toDto(), };
return Ok(response);
}
[HttpPost("exchange/order/complete"), RequirePlanetAuth]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlanetItemExchangeResponse))]
[SwaggerResponse(StatusCodes.Status400BadRequest, "교환 주문 완료 실패<br>실패 사유를 확인하세요.",
typeof(ApiErrorResponse))]
[SwaggerOperation(Summary = "교환 주문 완료 요청 [Bearer 인증 필요]")]
public async Task<IActionResult> completeOrder(
PlanetItemExchangeCompleteRequest request,
CancellationToken cancellationToken)
{
var sso_account_id = string.Empty;
await m_exchange_service.validateAndGetUser(sso_account_id, request.UserGuid, this.PlanetId);
// 메타버스 클라이언트에서 정상적으로
Guard.Against.isTrue(m_exchange_service.isUserLoggedIn(),
ServerErrorCode.MetaverseClientOnConnected,
()=>"메타버스에 접속 중인 상태. 메타버스에서 정상적으로 로그아웃 한 후에 다시 시도 바람.");
var order = await m_exchange_service.completeOrder(request.ExchangeOrderId, cancellationToken);
var response = new PlanetItemExchangeResponse { ExchangeOrder = order.toDto() };
return Ok(response);
}
}

View File

@@ -0,0 +1,93 @@
//
// using Asp.Versioning;
//
// using BrokerCore.ApiModels;
// using BrokerCore.Common;
// using BrokerCore.DbEntity;
// using BrokerCore.Services;
//
// using Microsoft.AspNetCore.Mvc;
//
// using ServerCommon;
//
// using Swashbuckle.AspNetCore.Annotations;
//
// namespace BrokerApiServer.Controllers;
//
// [ApiVersion("1.0")]
// [Route("api/v1/user")]
// [ApiController, SwaggerTag("**PlanetUser 항목으로 이전 후 삭제 예정** (3월 말 예정)")]
// // 특별한 인증 없이 런처 토큰만으로도 사용 가능한 컨트롤러
// public class UserController : ControllerBase
// {
// private readonly SapphireExchangeService m_exchange_service;
// private readonly IServerLogic m_server_logic;
//
// public UserController(
// IServerLogic serverLogic,
// SapphireExchangeService exchangeService)
// {
// m_server_logic = serverLogic;
// m_exchange_service = exchangeService;
// }
//
// [SwaggerIgnore]
// [HttpPost("balance/sapphire"), RequireUserJwtAuth]
// [Produces("application/json")]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UserSapphireResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "유저 사파이어 현재 수량 조회 (유저 sso jwt bearer header 필요)",
// Description = "웹 런처에서 발급한 토큰을 header의 authorization에 bearer 형식으로 넣어주세요.")]
// public async Task<IActionResult> getSapphireBalance(UserSapphireRequest _)
// {
// var dynamo_db_client = m_server_logic.getDynamoDbClient();
// var user_guid = this.HttpContext.Items["user_guid"] as string ?? string.Empty;
// CurrencyControlHelper.setDbConnector(dynamo_db_client);
// var (result, current_sapphire_amount_double) =
// await CurrencyControlHelper.getMoneyByUserGuid(user_guid, CurrencyType.Sapphire);
// Guard.Against.resultFail(result);
//
// var current_sapphire_amount = Convert.ToInt64(current_sapphire_amount_double);
// return Ok(new UserSapphireResponse { SapphireAmount = current_sapphire_amount });
// }
//
// [SwaggerIgnore]
// [HttpPost("exchange/order/list"), RequireUserJwtAuth]
// [Produces("application/json")]
// [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UserExchangeOrderListResponse))]
// [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
// [SwaggerOperation(Summary = "유저 사파이어 교환 주문 목록 조회 (유저 sso jwt bearer header 필요)",
// Description = "웹 런처에서 발급한 토큰을 header의 authorization에 bearer 형식으로 넣어주세요.\n 이기몹의 PlanetId는 igm26_iggymob 입니다.")]
// public async Task<IActionResult> getOrdersForUser(
// [SwaggerRequestBody] UserExchangeOrderListRequest request,
// CancellationToken cancellationToken)
// {
// var planet_id = request.PlanetId;
// var user_guid = this.HttpContext.Items["user_guid"]?.ToString() ?? string.Empty;
// Guard.Against.isNullOrEmptyOrWhiteSpace(user_guid,
// ServerErrorCode.AccountNotFound, "해당 유저를 찾을 수 없음");
// await m_exchange_service.authUser(user_guid, string.Empty);
//
// ExchangeOrderStatus? order_status = request switch
// {
// { Option: FindOption.Completed } => ExchangeOrderStatus.Completed,
// { Option: FindOption.Pending } => ExchangeOrderStatus.Pending,
// _ => null // 전체 조회
// };
// var orders =
// await m_exchange_service.findOrderList(planet_id, user_guid, order_status,
// request.PageIndex, request.PageSize, request.SortOrder,
// cancellationToken);
// var mapped_orders = orders.Select(x => new ExchangeOrder
// {
// OrderId = x.OrderId,
// SapphireAmount = x.SapphireReducedDelta,
// SapphireReduceAmount = x.SapphireReducedDelta,
// EmeraldAmount = x.PlanetMoneyIncDelta,
// CreatedAt = x.CreatedAt,
// CompletedAt = x.CompletedAt,
// Status = x.OrderStatus
// });
// return Ok(new UserExchangeOrderListResponse { Orders = mapped_orders });
// }
// }

View File

@@ -0,0 +1,8 @@
<Project>
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<BaseIntermediateOutputPath>..\..\obj\AnyCPU\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<BaseOutputPath>..\..\bin\</BaseOutputPath>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,285 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using ServerCore;
using ServerBase;
using ServerCommon;
using BrokerCore;
using BrokerCore.Repository;
using BrokerCore.Repository.Context;
using BrokerCore.Services;
using BrokerCore.Common;
namespace BrokerApiServer.Extensions;
using BrokerCore.Meta;
using Common;
using NLog.Config;
public static class AppBuilderExtensions
{
public static void initGlobalNlog()
{
// nlog 설정
var nlog_config_path = "./Config/nlog.config";
var full_path = Path.GetFullPath(nlog_config_path);
if (!File.Exists(full_path))
{
full_path = Path.GetFullPath(nlog_config_path, AppContext.BaseDirectory);
if (!File.Exists(full_path))
{
throw new ApplicationException($"nlog.config 파일을 찾을 수 없음 => {full_path}");
}
}
Log.NLogFileName = full_path;
}
public static ServerConfigMetaverseBroker initBrokerServerConfig()
{
// 서버 설정
var server_config = new ServerConfigMetaverseBroker();
var server_config_path = "./Config/ServerConfig.json";
var full_path = Path.GetFullPath(server_config_path);
if (!File.Exists(full_path))
{
full_path = Path.GetFullPath(server_config_path, AppContext.BaseDirectory);
if (!File.Exists(full_path))
{
throw new ApplicationException("ServerConfig.json 파일을 찾을 수 없음");
}
}
server_config.setConfigFilePath(full_path);
var result = server_config.tryLoadConfig().GetAwaiter().GetResult();
Guard.Against.resultFail(result);
return server_config;
}
public static void addBrokerServerLogic(this IServiceCollection services,
ServerConfigMetaverseBroker serverConfig)
{
var broker_logic = new BrokerServerLogic(serverConfig);
var result = broker_logic.onInit().GetAwaiter().GetResult();
if (result.isFail())
{
Log.getLogger().error($"BrokerServerLogic Init Failed => {result}");
throw new ApplicationException($"BrokerServerLogic Init Failed => {result}");
}
ServerLogicApp.setServerLogicApp(broker_logic);
services.AddSingleton<IServerLogic>(broker_logic);
}
public static void addCoreServices(this IServiceCollection services,
ServerConfigMetaverseBroker serverConfig)
{
services.AddSingleton(serverConfig);
var broker_logic = new BrokerServerLogic(serverConfig);
var result = broker_logic.onInit().GetAwaiter().GetResult();
services.AddSingleton<IServerLogic>(broker_logic);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(serverConfig.MetaverseBroker?.JwtSecretKey ?? String.Empty))
};
});
services.AddScoped<UserAuthService>();
services.addExchangeServices();
// 메타데이터 관련 서비스 등록
services.AddSingleton<BrokerApiMetaLoader>();
services.AddScoped<BrokerMetaTableRef>( provider =>
{
var meta_loader = provider.GetRequiredService<BrokerApiMetaLoader>();
return new BrokerMetaTableRef(meta_loader.getMetaTable());
});
services.AddHostedService<MetaDataReloadScheduler>();
var jwt_option = new JwtOption
{
Secret = serverConfig.MetaverseBroker?.JwtSecretKey ?? String.Empty,
TokenValidityInMinutes = serverConfig.MetaverseBroker?.ExpireMinutes ?? 1
};
services.AddSingleton(jwt_option);
services.AddScoped<JwtGenerator>(provider =>
{
return new JwtGenerator(jwt_option);
});
services.AddScoped<JwtParser>(provider =>
{
return new JwtParser(jwt_option);
});
services.AddScoped<PlanetService>();
// 미들웨어 설정
services.AddScoped<ResultLoggingMiddleware>();
}
public static void addInfraServices(this IServiceCollection services, ServerConfigMetaverseBroker serverConfig)
{
// 코어 리파지토리 서비스 설정
services.AddScoped<SsoAccountRepo>();
services.AddScoped<PlanetInfoRepo>();
services.AddScoped<PlanetItemExchangeOrderRepo>();
services.AddScoped<PlanetItemExchangeOrderAmountTotalLimitRepo>();
services.AddScoped<PlanetItemExchangeOrderAmountUserLimitRepo>();
services.AddDbContext<SsoAccountDbContext>(options =>
{
var connection_string = serverConfig.SsoAccountDb;
options.UseMySql(connection_string, ServerVersion.AutoDetect(connection_string), mySqlOptions =>
{
mySqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null
);
mySqlOptions.CommandTimeout(60);
mySqlOptions.MaxBatchSize(20);
});
});
services.AddDbContext<MetaverseBrokerDbContext>(options =>
{
var connection_string = serverConfig.MetaverseBroker?.MetaverseBrokerDb;
options.UseMySql(connection_string, ServerVersion.AutoDetect(connection_string), my_sql_options =>
{
my_sql_options.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null
);
my_sql_options.CommandTimeout(60);
my_sql_options.MaxBatchSize(20);
});
});
}
// todo: isLocal 삭제 예정
public static void addAppServices(this WebApplicationBuilder builder)
{
initGlobalNlog();
var server_config = initBrokerServerConfig();
builder.Services.addBrokerServerLogic(server_config);
builder.Services.addCoreServices(server_config);
builder.Services.addInfraServices(server_config);
}
public static void brokerServerLogicInit(this IApplicationBuilder app)
{
var server_logic = app.ApplicationServices.GetRequiredService<IServerLogic>() as BrokerServerLogic;
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"BrokerServerLogic is null");
server_logic.onInit().Wait();
}
public static void metadataMangerInit(this IApplicationBuilder app, string? dataPath = null)
{
var meta_loader = app.ApplicationServices.GetRequiredService<BrokerApiMetaLoader>();
var result = meta_loader.load(dataPath);
if (result.isFail())
{
Log.getLogger().error($"MetaDataManager Init Failed => {result}");
throw new ApplicationException($"MetaDataManager Init Failed => {result}");
}
}
public static void validateRepoConnections(this IApplicationBuilder app)
{
var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
// db 접속 유무 검사
using var scope = app.ApplicationServices.CreateScope();
var services = scope.ServiceProvider;
validateSsoAccountDb().Wait();
validateMetaverseBrokerDb().Wait();
migrateMetaverseBrokerDbForDevelopment().Wait();
return;
async Task validateSsoAccountDb()
{
var context = services.GetRequiredService<SsoAccountDbContext>();
try
{
if (await context.Database.CanConnectAsync())
{
Log.getLogger().info($"Sso Account DB Connection OK => {context.Database.GetConnectionString()}");
return;
}
Log.getLogger().error($"Sso Account DB Connection Failed => {context.Database.GetConnectionString()}");
}
catch (Exception ex)
{
Log.getLogger()
.error(
$"Sso Account DB Connection Failed => {ex.Message}, {context.Database.GetConnectionString()}");
}
throw new ApplicationException($"Failed to connect Sso Account Db !!!");
}
async Task validateMetaverseBrokerDb()
{
var context = services.GetRequiredService<MetaverseBrokerDbContext>();
try
{
if (await context.Database.CanConnectAsync())
{
Log.getLogger()
.info($"Metaverse-Broker DB Connection OK => {context.Database.GetConnectionString()}");
var pending_migrations = await context.Database.GetPendingMigrationsAsync();
var migrations = pending_migrations as string[] ?? pending_migrations.ToArray();
if (migrations.Any())
{
Log.getLogger().error($"{context.Database.ToString()} 마이그레션이 필요함 !!!");
migrations.Select( x => x.ToString()).ToList().ForEach(x => Log.getLogger().warn(x));
}
return;
}
}
catch (Exception ex)
{
Log.getLogger()
.error($"Metaverse-Broker DB 접속 예외 발생 => {ex.Message}, {context.Database.GetConnectionString()}");
}
throw new ApplicationException($"Failed to connect Broker Db !!!");
}
async Task migrateMetaverseBrokerDbForDevelopment()
{
// if (!env.IsDevelopment())
// {
// return;
// }
var context = services.GetRequiredService<MetaverseBrokerDbContext>();
try
{
await context.Database.MigrateAsync();
}
catch (Exception ex)
{
Log.getLogger().error($"Metaverse-Broker DB Migrate 실패 => {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,39 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ControlCenter.NamedPipe;
using ControlCenter.NamedPipeHost.Manager;
using ServerControlCenter;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace BrokerApiServer.NamedPipePacketHandler;
public class ForceStopServerMessageReceiver : NamedPipeReceiver<A2S_REQ_FORCE_STOP_SERVER>
{
private readonly ServerInfoManager m_info_manager;
public ForceStopServerMessageReceiver(ServerInfoManager infoManager)
{
m_info_manager = infoManager;
}
public override async Task Handle(A2S_REQ_FORCE_STOP_SERVER message, string message_id)
{
Log.getLogger().debug($"{nameof(ForceStopServerMessageReceiver)}: Receive - message_id[{message_id}] / message[{message}]");
m_info_manager.setServerStatus(ServerStatus.Stop);
// 정보 전달 대기
await Task.Delay(1_000);
// process 종료
Environment.Exit(0);
}
}

View File

@@ -0,0 +1,29 @@
using ControlCenter.NamedPipeHost.Manager;
using ControlCenter.NamedPipeHost.NamedPipe;
using ServerControlCenter;
using ServerCore; using ServerBase;
namespace BrokerApiServer.NamedPipePacketHandler;
public class StopServerMessageReceiver : NamedPipeReceiver<A2S_REQ_STOP_SERVER>
{
private readonly ServerInfoManager m_info_manager;
public StopServerMessageReceiver(ServerInfoManager infoManager)
{
m_info_manager = infoManager;
}
public override async Task Handle(A2S_REQ_STOP_SERVER message, string message_id)
{
Log.getLogger().debug($"{nameof(StopServerMessageReceiver)}: Receive - message_id[{message_id}] / message[{message}]");
m_info_manager.setServerStatus(ServerStatus.Stop);
// 정보 전달 대기
await Task.Delay(1_000);
// process 종료
Environment.Exit(0);
}
}

View File

@@ -0,0 +1,77 @@
using System.Reflection;
using ServerCore;
using ServerBase;
using ServerCommon;
using BrokerApiServer.Common;
using BrokerApiServer.Extensions;
using CaliGameApi.Middlewares;
using CommandLine;
using ControlCenter.NamedPipeHost.Extensions;
//=============================================================================
// 인자 설정
//=============================================================================
var port = 12000;
var use_swagger = false;
var use_named_pipe = false;
var parsed_arguments = Parser.Default.ParseArguments<CommandLineOption>(args);
if (parsed_arguments is Parsed<CommandLineOption> parsed)
{
port = parsed.Value.Port;
use_swagger = parsed.Value.UseSwagger ? true : false;
use_named_pipe = parsed.Value.UseNamedPipe ? true : false;
}
var cmd_options = new string[] { "--urls", $"http://*:{port}" };
var builder = WebApplication.CreateBuilder(cmd_options);
builder.addAppServices();
builder.Services.AddHttpContextAccessor();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllers(options => { options.Filters.Add(new ResultExceptionFilter()); });
builder.Services.AddHealthChecks();
builder.Services.AddSwaggerGen(SwaggerSettingHelper.setSwaggerGen);
var assemblies = new List<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
if (use_named_pipe)
{
builder.Services.AddNamedPipelineClientManager(assemblies, ServerControlCenter.ServerType.BrokerApi,
ServiceCategory.Caliverse.ToString(), NetworkHelper.getEthernetLocalIPv4(), port);
}
var app = builder.Build();
app.UseCors("Everything");
app.UseHttpsRedirection();
app.UseMiddleware<ResultLoggingMiddleware>();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();
if (use_swagger)
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapHealthChecks("/healthcheck");
app.validateRepoConnections();
app.brokerServerLogicInit();
// todo: 스키마 변경 시 자동으로 앱에서 마이그레이션 하지 않고, dotnet ef 툴을 사용할 것
// app.metadataMangerInit();
app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.Register(() =>
{
Log.getLogger().info($"Env : {app.Environment.EnvironmentName}");
Log.getLogger().info($"BrokerApiServer started {app.Urls}");
});
app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStopped.Register(Log.shutdown);
if (use_named_pipe)
{
app.UseNamedPipelineClientManager();
}
app.Run();

View File

@@ -0,0 +1,15 @@
{
"profiles": {
"http": {
"commandName": "Project",
"commandLineArgs": "-p 12000 -s",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:12000"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\user\.nuget\packages\</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.10.1</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\user\.nuget\packages\" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Configuration.UserSecrets.props" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Configuration.UserSecrets.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.2\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.2\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgAWSSDK_Core Condition=" '$(PkgAWSSDK_Core)' == '' ">C:\Users\user\.nuget\packages\awssdk.core\3.7.400</PkgAWSSDK_Core>
<PkgAWSSDK_S3 Condition=" '$(PkgAWSSDK_S3)' == '' ">C:\Users\user\.nuget\packages\awssdk.s3\3.7.400</PkgAWSSDK_S3>
<PkgAWSSDK_OpenSearchService Condition=" '$(PkgAWSSDK_OpenSearchService)' == '' ">C:\Users\user\.nuget\packages\awssdk.opensearchservice\3.7.400</PkgAWSSDK_OpenSearchService>
<PkgAWSSDK_DynamoDBv2 Condition=" '$(PkgAWSSDK_DynamoDBv2)' == '' ">C:\Users\user\.nuget\packages\awssdk.dynamodbv2\3.7.400</PkgAWSSDK_DynamoDBv2>
<PkgAWSSDK_CloudWatchLogs Condition=" '$(PkgAWSSDK_CloudWatchLogs)' == '' ">C:\Users\user\.nuget\packages\awssdk.cloudwatchlogs\3.7.305.15</PkgAWSSDK_CloudWatchLogs>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)system.text.json\8.0.0\buildTransitive\net6.0\System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json\8.0.0\buildTransitive\net6.0\System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Configuration.UserSecrets.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Configuration.UserSecrets.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.0\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
</ImportGroup>
</Project>

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]

View File

@@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("BrokerApiServer")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("BrokerApiServer")]
[assembly: System.Reflection.AssemblyTitleAttribute("BrokerApiServer")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// MSBuild WriteCodeFragment 클래스에서 생성되었습니다.

View File

@@ -0,0 +1 @@
f42f565cd904b4b097fb70fdee38c8e886209a12f509c9e7c43b23319c324d43

View File

@@ -0,0 +1,19 @@
is_global = true
build_property.TargetFramework = net8.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb = true
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = BrokerApiServer
build_property.RootNamespace = BrokerApiServer
build_property.ProjectDir = D:\03.SVN\03.caliverse\Server\CaliServer\BrokerApiServer\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 8.0
build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = D:\03.SVN\03.caliverse\Server\CaliServer\BrokerApiServer
build_property._RazorSourceGeneratorDebug =

View File

@@ -0,0 +1,17 @@
// <auto-generated/>
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
global using global::Microsoft.AspNetCore.Http;
global using global::Microsoft.AspNetCore.Routing;
global using global::Microsoft.Extensions.Configuration;
global using global::Microsoft.Extensions.DependencyInjection;
global using global::Microsoft.Extensions.Hosting;
global using global::Microsoft.Extensions.Logging;
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Net.Http.Json;
global using global::System.Threading;
global using global::System.Threading.Tasks;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
{
"version": 2,
"dgSpecHash": "FdIgw7z7uM0=",
"success": true,
"projectFilePath": "D:\\03.SVN\\03.caliverse\\Server\\CaliServer\\BrokerApiServer\\BrokerApiServer.csproj",
"expectedPackageFiles": [
"C:\\Users\\user\\.nuget\\packages\\asp.versioning.abstractions\\8.1.0\\asp.versioning.abstractions.8.1.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\asp.versioning.http\\8.1.0\\asp.versioning.http.8.1.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\asp.versioning.mvc\\8.1.0\\asp.versioning.mvc.8.1.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\asyncstatemachine\\1.3.2\\asyncstatemachine.1.3.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\aws.logger.core\\3.3.3\\aws.logger.core.3.3.3.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\aws.logger.nlog\\3.3.4\\aws.logger.nlog.3.3.4.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\awssdk.cloudwatchlogs\\3.7.305.15\\awssdk.cloudwatchlogs.3.7.305.15.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\awssdk.core\\3.7.400\\awssdk.core.3.7.400.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\awssdk.dynamodbv2\\3.7.400\\awssdk.dynamodbv2.3.7.400.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\awssdk.opensearchservice\\3.7.400\\awssdk.opensearchservice.3.7.400.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\awssdk.s3\\3.7.400\\awssdk.s3.3.7.400.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\axion.concurrenthashset\\1.0.0\\axion.concurrenthashset.1.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\commandlineparser\\2.9.1\\commandlineparser.2.9.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\dotnet.multimap\\2.2.1\\dotnet.multimap.2.2.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\dumpextensions\\2.0.0\\dumpextensions.2.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\google.protobuf\\3.27.1\\google.protobuf.3.27.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.aspnetcore\\2.63.0\\grpc.aspnetcore.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.aspnetcore.server\\2.63.0\\grpc.aspnetcore.server.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.aspnetcore.server.clientfactory\\2.63.0\\grpc.aspnetcore.server.clientfactory.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.aspnetcore.server.reflection\\2.63.0\\grpc.aspnetcore.server.reflection.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.core.api\\2.63.0\\grpc.core.api.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.net.client\\2.63.0\\grpc.net.client.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.net.clientfactory\\2.63.0\\grpc.net.clientfactory.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.net.common\\2.63.0\\grpc.net.common.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\grpc.reflection\\2.63.0\\grpc.reflection.2.63.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\jwt\\10.1.1\\jwt.10.1.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore\\8.0.2\\microsoft.entityframeworkcore.8.0.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore.abstractions\\8.0.2\\microsoft.entityframeworkcore.abstractions.8.0.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\8.0.2\\microsoft.entityframeworkcore.analyzers.8.0.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore.relational\\8.0.2\\microsoft.entityframeworkcore.relational.8.0.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\8.0.0\\microsoft.extensions.caching.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.caching.memory\\8.0.0\\microsoft.extensions.caching.memory.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration\\8.0.0\\microsoft.extensions.configuration.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\8.0.0\\microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration.binder\\8.0.0\\microsoft.extensions.configuration.binder.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration.fileextensions\\8.0.0\\microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration.json\\8.0.0\\microsoft.extensions.configuration.json.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.configuration.usersecrets\\8.0.0\\microsoft.extensions.configuration.usersecrets.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\8.0.0\\microsoft.extensions.dependencyinjection.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\8.0.1\\microsoft.extensions.dependencyinjection.abstractions.8.0.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.diagnostics\\8.0.0\\microsoft.extensions.diagnostics.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.diagnostics.abstractions\\8.0.0\\microsoft.extensions.diagnostics.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\8.0.0\\microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.fileproviders.physical\\8.0.0\\microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.filesystemglobbing\\8.0.0\\microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.http\\8.0.0\\microsoft.extensions.http.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.logging\\8.0.0\\microsoft.extensions.logging.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\8.0.0\\microsoft.extensions.logging.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.options\\8.0.0\\microsoft.extensions.options.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.options.configurationextensions\\8.0.0\\microsoft.extensions.options.configurationextensions.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.extensions.primitives\\8.0.0\\microsoft.extensions.primitives.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.identitymodel.abstractions\\7.6.2\\microsoft.identitymodel.abstractions.7.6.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.identitymodel.jsonwebtokens\\7.6.2\\microsoft.identitymodel.jsonwebtokens.7.6.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.identitymodel.logging\\7.6.2\\microsoft.identitymodel.logging.7.6.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.identitymodel.tokens\\7.6.2\\microsoft.identitymodel.tokens.7.6.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\microsoft.openapi\\1.6.22\\microsoft.openapi.1.6.22.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\mongodb.bson\\2.26.0\\mongodb.bson.2.26.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\mysqlconnector\\2.3.7\\mysqlconnector.2.3.7.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\neosmart.asynclock\\3.2.1\\neosmart.asynclock.3.2.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\newtonsoft.json\\13.0.3\\newtonsoft.json.13.0.3.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex\\5.1.2\\nito.asyncex.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex.context\\5.1.2\\nito.asyncex.context.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex.coordination\\5.1.2\\nito.asyncex.coordination.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex.interop.waithandles\\5.1.2\\nito.asyncex.interop.waithandles.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex.oop\\5.1.2\\nito.asyncex.oop.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.asyncex.tasks\\5.1.2\\nito.asyncex.tasks.5.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.cancellation\\1.1.2\\nito.cancellation.1.1.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.collections.deque\\1.1.1\\nito.collections.deque.1.1.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nito.disposables\\2.2.1\\nito.disposables.2.2.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nlog\\5.3.2\\nlog.5.3.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nlog.extensions.logging\\5.3.11\\nlog.extensions.logging.5.3.11.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\nlog.web.aspnetcore\\5.3.11\\nlog.web.aspnetcore.5.3.11.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\otp.net\\1.4.0\\otp.net.1.4.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\pipelines.sockets.unofficial\\2.2.8\\pipelines.sockets.unofficial.2.2.8.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\pomelo.entityframeworkcore.mysql\\8.0.2\\pomelo.entityframeworkcore.mysql.8.0.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\rabbitmq.client\\6.8.1\\rabbitmq.client.6.8.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\ssh.net\\2024.0.0\\ssh.net.2024.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\stackexchange.redis\\2.8.24\\stackexchange.redis.2.8.24.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\stackexchange.redis.extensions.core\\10.2.0\\stackexchange.redis.extensions.core.10.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\stackexchange.redis.extensions.newtonsoft\\10.2.0\\stackexchange.redis.extensions.newtonsoft.10.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\stackexchange.redis.multiplexerpool\\2.2.0\\stackexchange.redis.multiplexerpool.2.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\swashbuckle.aspnetcore.annotations\\7.2.0\\swashbuckle.aspnetcore.annotations.7.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\swashbuckle.aspnetcore.swagger\\7.2.0\\swashbuckle.aspnetcore.swagger.7.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\swashbuckle.aspnetcore.swaggergen\\7.2.0\\swashbuckle.aspnetcore.swaggergen.7.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\swashbuckle.aspnetcore.swaggerui\\7.2.0\\swashbuckle.aspnetcore.swaggerui.7.2.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.collections.immutable\\1.7.1\\system.collections.immutable.1.7.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.diagnostics.diagnosticsource\\8.0.0\\system.diagnostics.diagnosticsource.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.identitymodel.tokens.jwt\\7.6.2\\system.identitymodel.tokens.jwt.7.6.2.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.io.pipelines\\5.0.1\\system.io.pipelines.5.0.1.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.memory\\4.5.5\\system.memory.4.5.5.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.reactive\\6.0.0\\system.reactive.6.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\5.0.0\\system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.text.encodings.web\\8.0.0\\system.text.encodings.web.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.text.json\\8.0.0\\system.text.json.8.0.0.nupkg.sha512",
"C:\\Users\\user\\.nuget\\packages\\system.threading.channels\\7.0.0\\system.threading.channels.7.0.0.nupkg.sha512"
],
"logs": []
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
17388052526770821

View File

@@ -0,0 +1 @@
17388294830086441