Better way to con figure handlers. Fixed services handler. Working on popn music handle. Working on database connetion using rabbit mq to the database service

This commit is contained in:
= 2024-08-19 09:26:41 +02:00
parent 22623b11b5
commit ce7765fdc2
15 changed files with 324 additions and 56 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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();

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="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>

View File

@ -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();

View File

@ -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;
}
}
}

View File

@ -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);
}
else
{
res[p] = 255;
}
p += 1;
}
compressedData[outputPosition++] = data[i];
res[p] = data[i];
p += 1;
}
compressedData[outputPosition++] = 0;
compressedData[outputPosition] = 0;
return compressedData;
res[p] = 0;
res[p + 1] = 0;
return res;
}
}
}

View File

@ -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>

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"
}
}
}