HandlerRegistration #2

Merged
Kayori merged 4 commits from HandlerRegistration into main 2024-08-19 07:27:10 +00:00
15 changed files with 324 additions and 56 deletions
Showing only changes of commit ce7765fdc2 - Show all commits

View File

@ -25,7 +25,9 @@ var medusaDB = postgres.AddDatabase(dbVolumeName);
builder.AddProject<Projects.Medusa_Core>("Medusa-core") builder.AddProject<Projects.Medusa_Core>("Medusa-core")
.WithReference(cache) .WithReference(cache)
.WithReference(messenger) .WithReference(messenger)
.WithEnvironment("weburl", weburl); .WithEnvironment("weburl", weburl)
.WithEnvironment("rabbitHostName", messenger)
.WaitOn(messenger);
builder.AddProject<Projects.Medusa_Web_Server>("Medusa-web-server"); builder.AddProject<Projects.Medusa_Web_Server>("Medusa-web-server");
@ -33,6 +35,8 @@ builder.AddProject<Projects.Medusa_Data>("medusa-data")
.WithReference(cache) .WithReference(cache)
.WithReference(messenger) .WithReference(messenger)
.WithReference(medusaDB) .WithReference(medusaDB)
.WaitOn(postgres); .WithEnvironment("rabbitHostName", messenger)
.WaitOn(postgres)
.WaitOn(messenger);
builder.Build().Run(); builder.Build().Run();

View File

@ -11,7 +11,8 @@ namespace Medusa.Core.Extensions
var handlerService = app.ApplicationServices.GetRequiredService<IHandlerService>(); var handlerService = app.ApplicationServices.GetRequiredService<IHandlerService>();
var assembly = Assembly.GetEntryAssembly() ?? throw new InvalidOperationException("Could not find entry assembly."); var assembly = Assembly.GetEntryAssembly() ?? throw new InvalidOperationException("Could not find entry assembly.");
var types = assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IHandler))); var types = assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IHandler)) ||
(t.IsSubclassOf(typeof(Handler)) && !t.IsAbstract));
handlerService.Handlers.AddRange(types); handlerService.Handlers.AddRange(types);

View File

@ -5,8 +5,7 @@ using System.Xml.Linq;
namespace Medusa.Core.Handlers.Boot namespace Medusa.Core.Handlers.Boot
{ {
[Handler("services", "get")] public class GetServicesHandler(IServer server, ILogger<GetServicesHandler> logger, XDocument body) : Handler
public class GetServicesHandler(IServer server, ILogger<GetServicesHandler> logger, XDocument body) : IHandler
{ {
private readonly IServer _server = server; private readonly IServer _server = server;
private readonly ILogger<GetServicesHandler> _logger = logger; private readonly ILogger<GetServicesHandler> _logger = logger;
@ -14,7 +13,13 @@ namespace Medusa.Core.Handlers.Boot
private const string CommonUrl = "http://127.0.0.1:8083/ea"; private const string CommonUrl = "http://127.0.0.1:8083/ea";
private string listeningAddress = "http://127.0.0.1:8083"; private string listeningAddress = "http://127.0.0.1:8083";
public Task<XDocument> HandleAsync(string model) public override void Configure()
{
Module("services");
Method("get");
}
public override Task<XDocument> HandleAsync(string model)
{ {
var services = CreateCoreServicesElement(); var services = CreateCoreServicesElement();

View File

@ -0,0 +1,39 @@
using Medusa.Core.Attributes;
using Medusa.Core.Services;
using System.Xml.Linq;
namespace Medusa.Core.Handlers.Common.Card
{
[Handler("system_3", "convcardnumber")]
public class ConvCardnNumberSystem3(ICardService cardService, XDocument body) : IHandler
{
private readonly ICardService _cardService = cardService;
public Task<XDocument> HandleAsync(string model)
{
var root = body.Root;
var systemElement = root.Element("system_3");
var data = systemElement.Element("data");
var cardIdElement = data.Element("card_id").Value;
var cardId = cardIdElement;
var cardNumber = _cardService.ConvertUidToKonamiId(cardId);
var system = new XElement("system",
new XAttribute("status", "0"),
new XElement("result",
new XAttribute("__type", "s32"),
0
),
new XElement("data",
new XElement("card_number", cardNumber)));
var document = new XDocument(
new XElement("response",
system
)
);
return Task.FromResult(document);
}
}
}

View File

@ -0,0 +1,26 @@
using System.Xml.Linq;
namespace Medusa.Core.Handlers
{
public abstract class Handler
{
public string HandlerModule { get; set; } = "";
public string HandlerMethod { get; set; } = "";
public virtual void Configure() { throw new NotImplementedException("Configure method not implemented."); }
protected void Module(string module)
{
this.HandlerModule = module;
}
protected void Method(string method)
{
this.HandlerMethod = method;
}
public virtual XDocument Handle(string model) { throw new NotImplementedException("Handle method not implemented."); }
public virtual Task<XDocument> HandleAsync(string model) { throw new NotImplementedException("Handle method not implemented."); }
}
}

View File

@ -0,0 +1,29 @@
using Medusa.Core.Attributes;
using Microsoft.AspNetCore.Routing.Patterns;
using System.Xml.Linq;
namespace Medusa.Core.Handlers.M39
{
public class BootPCB24Handler: Handler
{
public override void Configure()
{
Module("pcb24");
Method("boot");
}
public override XDocument Handle(string model)
{
var pcb24 = new XElement("pcb24",
new XAttribute("status", "0"));
var document = new XDocument(
new XElement("response",
pcb24
)
);
return document;
}
}
}

View File

@ -0,0 +1,17 @@
using Medusa.Core.Attributes;
using System.Xml.Linq;
namespace Medusa.Core.Handlers.MDX
{
[Handler("playdata_3", "musicdata_load")]
public class MusicDataLoadPlayDate3Handler(XDocument body) : IHandler
{
private readonly XDocument _body = body;
public Task<XDocument> HandleAsync(string model)
{
var document = new XDocument("Response");
return Task.FromResult(document);
}
}
}

View File

@ -0,0 +1,17 @@
using Medusa.Core.Attributes;
using System.Xml.Linq;
namespace Medusa.Core.Handlers.MDX
{
[Handler("playdata_3", "playerdata_load")]
public class PlayerDataLoadPlayData3Handler(XDocument body) : IHandler
{
private readonly XDocument _body = body;
public Task<XDocument> HandleAsync(string model)
{
var document = new XDocument("Response");
return Task.FromResult(document);
}
}
}

View File

@ -12,6 +12,8 @@
<PackageReference Include="FastEndpoints" Version="5.28.0" /> <PackageReference Include="FastEndpoints" Version="5.28.0" />
<PackageReference Include="KbinXml.Net" Version="1.1.0" /> <PackageReference Include="KbinXml.Net" Version="1.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
<PackageReference Include="RabbitMQ.Client.Core.DependencyInjection.Updated" Version="570.0.0-alpha" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -19,9 +21,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Handlers\MDX\" />
<Folder Include="Handlers\KFC\" /> <Folder Include="Handlers\KFC\" />
<Folder Include="Handlers\M39\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -2,6 +2,8 @@ using FastEndpoints;
using Medusa.Core.Extensions; using Medusa.Core.Extensions;
using Medusa.Core.Middlewares; using Medusa.Core.Middlewares;
using Medusa.Core.Request; using Medusa.Core.Request;
using RabbitMQ.Client.Core.DependencyInjection;
using RabbitMQ.Client.Core.DependencyInjection.Configuration;
using System.Text; using System.Text;
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
@ -12,6 +14,20 @@ builder.Services.AddFastEndpoints();
builder.Services.AddHandlers(); builder.Services.AddHandlers();
var uri = new Uri(Environment.GetEnvironmentVariable("rabbitHostName"));
var userInfo = uri.UserInfo.Split(':');
var rabbitMqConfiguration = new RabbitMqServiceOptions
{
HostName = uri.Host,
Port = uri.Port,
UserName = userInfo[0],
Password = userInfo[1]
};
builder.Services.AddRabbitMqServices(rabbitMqConfiguration);
builder.Services.AddRabbitMqProducer(rabbitMqConfiguration);
builder.AddServiceDefaults(); builder.AddServiceDefaults();

View File

@ -14,18 +14,27 @@ namespace Medusa.Core.Services
public async Task<XDocument> Handle(string model, string module, string method, XDocument body) public async Task<XDocument> Handle(string model, string module, string method, XDocument body)
{ {
foreach (var handler in Handlers) foreach(var handler in Handlers)
{ {
//Module and service are on the attribute //Module and service are on the attribute
var handlerAttribute = handler.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(HandlerAttribute)); var handlerAttribute = handler.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(HandlerAttribute));
if (handlerAttribute is null) if(handlerAttribute is null)
{
var response = await HandleInheritanceClass(handler, model, module, method, body);
if(response is not null)
{
return response;
}
continue; continue;
}
var attributeModule = handlerAttribute.ConstructorArguments[0].Value.ToString(); var attributeModule = handlerAttribute.ConstructorArguments[0].Value.ToString();
var attributeMethod = handlerAttribute.ConstructorArguments[1].Value.ToString(); var attributeMethod = handlerAttribute.ConstructorArguments[1].Value.ToString();
if (attributeModule == module && attributeMethod == method) if(attributeModule == module && attributeMethod == method)
{ {
// Body param is optional so check for it // Body param is optional so check for it
bool requiresXDocumentConstructor = handler.GetConstructors() bool requiresXDocumentConstructor = handler.GetConstructors()
@ -44,5 +53,63 @@ namespace Medusa.Core.Services
return new XDocument(); return new XDocument();
} }
private async Task<XDocument?> HandleInheritanceClass(Type handler, string model, string module, string method, XDocument body)
{
bool requiredXdocumentConstructor = handler.GetConstructors()
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
Handler handlerInstance = requiredXdocumentConstructor
? (Handler)ActivatorUtilities.CreateInstance(_serviceProvider, handler, body)
: (Handler)ActivatorUtilities.CreateInstance(_serviceProvider, handler);
try
{
var configureMethod = handler.GetMethod("Configure");
configureMethod?.Invoke(handlerInstance, null);
}
catch(NotImplementedException e)
{
_logger.LogError(e, "Configure method not implemented for {Handler}", handler.Name);
return null;
}
var handlerModule = handlerInstance.HandlerModule;
var handlerMethod = handlerInstance.HandlerMethod;
if(string.IsNullOrEmpty(handlerModule))
{
_logger.LogError("Module not set for {Handler}", handler.Name);
return null;
}
if(string.IsNullOrEmpty(handlerMethod))
{
_logger.LogError("Method not set for {Handler}", handler.Name);
return null;
}
if(handlerModule != module && handlerMethod != method)
return null;
var handleMethod = handlerInstance.GetType().GetMethod("Handle", [typeof(string)]);
var handleAsyncMethod = handlerInstance.GetType().GetMethod("HandleAsync", [typeof(string)]);
var response = new XDocument();
response = handleMethod?.DeclaringType != typeof(Handler)
? handlerInstance.Handle(model)
: handleAsyncMethod?.DeclaringType != typeof(Handler)
? await handlerInstance.HandleAsync(model)
: null;
if(response is null)
{
_logger.LogError("Handle and HandleAsync not implemented for {Handler}", handler.Name);
return null;
}
return response;
}
} }
} }

View File

@ -2,74 +2,95 @@
{ {
public class LZ77 public class LZ77
{ {
public static byte[] Decompress(byte[] compressedData) public static byte[] Decompress(byte[] data)
{ {
byte[] decompressedData = new byte[0x190000]; // init a buffer, size comes from eamuemu
int inputPosition = 0; byte[] res = new byte[0x190000];
int outputPosition = 0; // current data location
byte bitmask = 0; int p = 0;
int bitCounter = 8; // current output location
int r = 0;
// traceback location
int t = 0;
// bitmask location
int b = 8; // read next bitmask byte on start
byte mask = 0;
while(true) while(true)
{ {
if(bitCounter == 8) // read bitmask on block end
if(b == 8)
{ {
bitmask = compressedData[inputPosition++]; mask = data[p];
bitCounter = 0; p += 1;
b = 0;
} }
// get mask for next byte
if((bitmask & 1) != 0) if((mask & 1) == 1)
{ { // not coded
decompressedData[outputPosition++] = compressedData[inputPosition++]; // copy the byte from data to result
res[r] = data[p];
r += 1;
p += 1;
} }
else else
{ { // coded
int distance = compressedData[inputPosition]; // read descriptors
int count = compressedData[inputPosition + 1]; int distance = data[p];
int count = data[p + 1];
// EOF mark
if(distance == 0 && count == 0) if(distance == 0 && count == 0)
{
break; break;
}
inputPosition += 2; p += 2;
distance = (distance << 4) | (count >> 4); // shift to correct location
distance <<= 4;
distance |= count >> 4;
count = (count & 0x0F) + 3; count = (count & 0x0F) + 3;
// copy earlier result bytes to the end
t = r - distance; // initialize traceback location
for(int i = 0; i < count; i++) for(int i = 0; i < count; i++)
{ {
decompressedData[outputPosition] = decompressedData[outputPosition - distance]; res[r] = t < 0 ? (byte)0x00 : res[t];
outputPosition++; r += 1;
t += 1;
} }
} }
// shift mask
bitmask >>= 1; mask >>= 1;
bitCounter++; b += 1;
} }
// r = result length
var output = new byte[outputPosition]; byte[] output = new byte[r];
Array.Copy(decompressedData, output, outputPosition); Array.Copy(res, output, r);
return output; return output;
} }
public static byte[] CompressEmpty(byte[] data) public static byte[] CompressEmpty(byte[] data)
{ {
int estimatedLength = data.Length + (data.Length / 8) + 3; byte[] res = new byte[data.Length + data.Length / 8 + 3];
byte[] compressedData = new byte[estimatedLength]; int p = 0;
int outputPosition = 0;
for(int i = 0; i < data.Length; i++) for(int i = 0; i < data.Length; i++)
{ {
if(i % 8 == 0) if(i % 8 == 0)
{ {
compressedData[outputPosition++] = (byte)((data.Length - i < 8) ? (Math.Pow(2, data.Length - i) - 1) : 255); if(data.Length - i < 8)
{
res[p] = (byte)(Math.Pow(2, data.Length - i) - 1);
}
else
{
res[p] = 255;
}
p += 1;
} }
res[p] = data[i];
compressedData[outputPosition++] = data[i]; p += 1;
} }
res[p] = 0;
compressedData[outputPosition++] = 0; res[p + 1] = 0;
compressedData[outputPosition] = 0; return res;
return compressedData;
} }
} }
} }

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@ -19,6 +19,12 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
<PackageReference Include="RabbitMQ.Client.Core.DependencyInjection.Updated" Version="570.0.0-alpha" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Medusa.ServiceDefaults\Medusa.ServiceDefaults.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,2 +1,10 @@
// See https://aka.ms/new-console-template for more information 
Console.WriteLine("Hello, World!"); using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
var app = builder.Build();
app.Run();

View File

@ -0,0 +1,12 @@
{
"profiles": {
"Medusa.Data": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:58881;http://localhost:58882"
}
}
}