HandlerRegistration #2
@ -25,7 +25,9 @@ var medusaDB = postgres.AddDatabase(dbVolumeName);
|
||||
builder.AddProject<Projects.Medusa_Core>("Medusa-core")
|
||||
.WithReference(cache)
|
||||
.WithReference(messenger)
|
||||
.WithEnvironment("weburl", weburl);
|
||||
.WithEnvironment("weburl", weburl)
|
||||
.WithEnvironment("rabbitHostName", messenger)
|
||||
.WaitOn(messenger);
|
||||
|
||||
builder.AddProject<Projects.Medusa_Web_Server>("Medusa-web-server");
|
||||
|
||||
@ -33,6 +35,8 @@ builder.AddProject<Projects.Medusa_Data>("medusa-data")
|
||||
.WithReference(cache)
|
||||
.WithReference(messenger)
|
||||
.WithReference(medusaDB)
|
||||
.WaitOn(postgres);
|
||||
.WithEnvironment("rabbitHostName", messenger)
|
||||
.WaitOn(postgres)
|
||||
.WaitOn(messenger);
|
||||
|
||||
builder.Build().Run();
|
||||
|
@ -11,7 +11,8 @@ namespace Medusa.Core.Extensions
|
||||
var handlerService = app.ApplicationServices.GetRequiredService<IHandlerService>();
|
||||
|
||||
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);
|
||||
|
||||
|
@ -5,8 +5,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Medusa.Core.Handlers.Boot
|
||||
{
|
||||
[Handler("services", "get")]
|
||||
public class GetServicesHandler(IServer server, ILogger<GetServicesHandler> logger, XDocument body) : IHandler
|
||||
public class GetServicesHandler(IServer server, ILogger<GetServicesHandler> logger, XDocument body) : Handler
|
||||
{
|
||||
private readonly IServer _server = server;
|
||||
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 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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
26
Medusa.Core/Handlers/Handler.cs
Normal file
26
Medusa.Core/Handlers/Handler.cs
Normal 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."); }
|
||||
|
||||
}
|
||||
}
|
29
Medusa.Core/Handlers/M39/BootPCB24Handler.cs
Normal file
29
Medusa.Core/Handlers/M39/BootPCB24Handler.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
17
Medusa.Core/Handlers/MDX/MusicDataLoadPlayDate3Handler.cs
Normal file
17
Medusa.Core/Handlers/MDX/MusicDataLoadPlayDate3Handler.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
17
Medusa.Core/Handlers/MDX/PlayerDataLoadPlayData3Handler.cs
Normal file
17
Medusa.Core/Handlers/MDX/PlayerDataLoadPlayData3Handler.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@
|
||||
<PackageReference Include="FastEndpoints" Version="5.28.0" />
|
||||
<PackageReference Include="KbinXml.Net" Version="1.1.0" />
|
||||
<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>
|
||||
@ -19,9 +21,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Handlers\MDX\" />
|
||||
<Folder Include="Handlers\KFC\" />
|
||||
<Folder Include="Handlers\M39\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -2,6 +2,8 @@ using FastEndpoints;
|
||||
using Medusa.Core.Extensions;
|
||||
using Medusa.Core.Middlewares;
|
||||
using Medusa.Core.Request;
|
||||
using RabbitMQ.Client.Core.DependencyInjection;
|
||||
using RabbitMQ.Client.Core.DependencyInjection.Configuration;
|
||||
using System.Text;
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
@ -12,6 +14,20 @@ builder.Services.AddFastEndpoints();
|
||||
|
||||
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();
|
||||
|
||||
|
@ -14,18 +14,27 @@ namespace Medusa.Core.Services
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
var attributeModule = handlerAttribute.ConstructorArguments[0].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
|
||||
bool requiresXDocumentConstructor = handler.GetConstructors()
|
||||
@ -44,5 +53,63 @@ namespace Medusa.Core.Services
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,74 +2,95 @@
|
||||
{
|
||||
public class LZ77
|
||||
{
|
||||
public static byte[] Decompress(byte[] compressedData)
|
||||
public static byte[] Decompress(byte[] data)
|
||||
{
|
||||
byte[] decompressedData = new byte[0x190000];
|
||||
int inputPosition = 0;
|
||||
int outputPosition = 0;
|
||||
byte bitmask = 0;
|
||||
int bitCounter = 8;
|
||||
// init a buffer, size comes from eamuemu
|
||||
byte[] res = new byte[0x190000];
|
||||
// current data location
|
||||
int p = 0;
|
||||
// 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)
|
||||
{
|
||||
if(bitCounter == 8)
|
||||
// read bitmask on block end
|
||||
if(b == 8)
|
||||
{
|
||||
bitmask = compressedData[inputPosition++];
|
||||
bitCounter = 0;
|
||||
mask = data[p];
|
||||
p += 1;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
if((bitmask & 1) != 0)
|
||||
{
|
||||
decompressedData[outputPosition++] = compressedData[inputPosition++];
|
||||
// get mask for next byte
|
||||
if((mask & 1) == 1)
|
||||
{ // not coded
|
||||
// copy the byte from data to result
|
||||
res[r] = data[p];
|
||||
r += 1;
|
||||
p += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int distance = compressedData[inputPosition];
|
||||
int count = compressedData[inputPosition + 1];
|
||||
|
||||
{ // coded
|
||||
// read descriptors
|
||||
int distance = data[p];
|
||||
int count = data[p + 1];
|
||||
// EOF mark
|
||||
if(distance == 0 && count == 0)
|
||||
{
|
||||
break;
|
||||
|
||||
inputPosition += 2;
|
||||
distance = (distance << 4) | (count >> 4);
|
||||
}
|
||||
p += 2;
|
||||
// shift to correct location
|
||||
distance <<= 4;
|
||||
distance |= count >> 4;
|
||||
count = (count & 0x0F) + 3;
|
||||
|
||||
// copy earlier result bytes to the end
|
||||
t = r - distance; // initialize traceback location
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
decompressedData[outputPosition] = decompressedData[outputPosition - distance];
|
||||
outputPosition++;
|
||||
res[r] = t < 0 ? (byte)0x00 : res[t];
|
||||
r += 1;
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bitmask >>= 1;
|
||||
bitCounter++;
|
||||
// shift mask
|
||||
mask >>= 1;
|
||||
b += 1;
|
||||
}
|
||||
|
||||
var output = new byte[outputPosition];
|
||||
Array.Copy(decompressedData, output, outputPosition);
|
||||
// r = result length
|
||||
byte[] output = new byte[r];
|
||||
Array.Copy(res, output, r);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static byte[] CompressEmpty(byte[] data)
|
||||
{
|
||||
int estimatedLength = data.Length + (data.Length / 8) + 3;
|
||||
byte[] compressedData = new byte[estimatedLength];
|
||||
int outputPosition = 0;
|
||||
|
||||
byte[] res = new byte[data.Length + data.Length / 8 + 3];
|
||||
int p = 0;
|
||||
for(int i = 0; i < data.Length; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
compressedData[outputPosition++] = data[i];
|
||||
else
|
||||
{
|
||||
res[p] = 255;
|
||||
}
|
||||
|
||||
compressedData[outputPosition++] = 0;
|
||||
compressedData[outputPosition] = 0;
|
||||
|
||||
return compressedData;
|
||||
p += 1;
|
||||
}
|
||||
res[p] = data[i];
|
||||
p += 1;
|
||||
}
|
||||
res[p] = 0;
|
||||
res[p + 1] = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
@ -19,6 +19,12 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
12
Medusa.Data/Properties/launchSettings.json
Normal file
12
Medusa.Data/Properties/launchSettings.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Medusa.Data": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:58881;http://localhost:58882"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user