초기커밋
This commit is contained in:
336
ServerBase/MessageQueue/RabbitMqConnector.cs
Normal file
336
ServerBase/MessageQueue/RabbitMqConnector.cs
Normal file
@@ -0,0 +1,336 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
|
||||
using Nettention.Proud;
|
||||
using RabbitMQ.Client.Events;
|
||||
using RabbitMQ.Client;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using MongoDB.Bson.IO;
|
||||
|
||||
|
||||
|
||||
using ServerCore;
|
||||
|
||||
|
||||
|
||||
namespace ServerBase;
|
||||
|
||||
public abstract partial class RabbitMqConnector : RabbitMQConnectorBase, IRabbitMqSession, IModule, IWithPacketNamespaceVerifier
|
||||
{
|
||||
public delegate Task FnServerMessageRecvFromConsumer(BasicDeliverEventArgs ea, IMessage message);
|
||||
public FnServerMessageRecvFromConsumer? _fnServerMessageRecvFromConsumer;
|
||||
|
||||
private readonly PacketReceiver m_packet_receiver;
|
||||
|
||||
private ModuleContext m_module_context;
|
||||
|
||||
public RabbitMqConnector( ModuleContext moduleContext )
|
||||
: base( getConfigParamsOrThrow(moduleContext).serviceName
|
||||
, getConfigParamsOrThrow(moduleContext).address
|
||||
, getConfigParamsOrThrow(moduleContext).port
|
||||
, getConfigParamsOrThrow(moduleContext).userName
|
||||
, getConfigParamsOrThrow(moduleContext).password
|
||||
, getConfigParamsOrThrow(moduleContext).useSSL )
|
||||
|
||||
{
|
||||
m_module_context = moduleContext;
|
||||
m_packet_receiver = new PacketReceiver(this);
|
||||
}
|
||||
|
||||
private static (string serviceName, string address, int port, string userName, string password, bool useSSL) getConfigParamsOrThrow(ModuleContext context)
|
||||
{
|
||||
if (context.getConfigParam() is not ConfigParam param)
|
||||
throw new InvalidCastException("IConfigParam must be of type RabbitMqConnector.ConfigParam !!!");
|
||||
|
||||
return (
|
||||
param.ServiceName ?? throw new InvalidOperationException("ServiceName is null !!!"),
|
||||
param.HostName ?? throw new InvalidOperationException("HostName is null !!!"),
|
||||
param.Port,
|
||||
param.UserName ?? throw new InvalidOperationException("Username is null !!!"),
|
||||
param.Password ?? throw new InvalidOperationException("Password is null !!!"),
|
||||
param.UseSSL
|
||||
);
|
||||
}
|
||||
|
||||
public bool isValidPacketNamespace(string toCheckNamespace, IPacketCommand packetCommand)
|
||||
{
|
||||
var packet_namespace = ".PacketHandler";
|
||||
|
||||
if (null != toCheckNamespace
|
||||
&& true == toCheckNamespace.Contains(packet_namespace))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerCore.Log.getLogger().error($"Invalid PacketNamespace !!!, not included Namespace : {packet_namespace} ⊆ {toCheckNamespace}, packetCommnad:{packetCommand.toBasicString()}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<Result> startModule()
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var module_context = getModuleContext();
|
||||
var config_param = module_context.getConfigParam() as ConfigParam;
|
||||
NullReferenceCheckHelper.throwIfNull(config_param, () => $"config_param is null !!!");
|
||||
var fn_receiver = config_param.fnServerMessageRecvFromConsumer;
|
||||
NullReferenceCheckHelper.throwIfNull(fn_receiver, () => $"fn_receiver is null !!!");
|
||||
|
||||
result = onCreateExchangeChannel();
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onCreateExchangeChannel() in startModule() !!! - {config_param.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.RabbitMqChannelCreateFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var is_success = await startMessageReceiverByConsumer(fn_receiver);
|
||||
if(false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to startMessageReceiverByConsumer() in startModule() !!! - {config_param.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.RabbitMqConsumerStartFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> stopModule()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public async Task<bool> startMessageReceiverByConsumer(RabbitMqConnector.FnServerMessageRecvFromConsumer fnFromConsumer)
|
||||
{
|
||||
if(null == fnFromConsumer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = await m_packet_receiver.registerRecvHandlerAll();
|
||||
if (false == result)
|
||||
{
|
||||
Log.getLogger().error("rabbitMq registerRecvHandler error");
|
||||
return result;
|
||||
}
|
||||
|
||||
_fnServerMessageRecvFromConsumer = fnFromConsumer;
|
||||
|
||||
return base.startConsumer();
|
||||
}
|
||||
|
||||
public async Task<bool> onRecvProtocol<T>(BasicDeliverEventArgs ea, T recvProtocol)
|
||||
where T : Google.Protobuf.IMessage
|
||||
{
|
||||
Log.getLogger().info($"receive:{recvProtocol.ToString()} - {toBasicString()}");
|
||||
|
||||
Stopwatch? stopwatch = null;
|
||||
var event_tid = string.Empty;
|
||||
|
||||
var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
|
||||
if (true == server_config.PerformanceCheckEnable)
|
||||
{
|
||||
event_tid = System.Guid.NewGuid().ToString("N");
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
var receiver = getPacketReceiver();
|
||||
|
||||
if (false == receiver.fillupRabbitMqPacketCommand(ea, recvProtocol, out var fillupPacketCommand))
|
||||
{
|
||||
Log.getLogger().error($"Invalid received Packet !!! : {recvProtocol.ToString()}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fillupPacketCommand == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var found_handler = receiver.findRecvHandler(fillupPacketCommand);
|
||||
if (null == found_handler)
|
||||
{
|
||||
Log.getLogger().error($"Unacceptable Packet !!! : {fillupPacketCommand.toBasicString()} - {toBasicString()}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var check_by_exchange_type = onCheckByExchangeType(ea, recvProtocol);
|
||||
if (false == check_by_exchange_type) return false;
|
||||
|
||||
//var task = Task.Factory.StartNew(async () =>
|
||||
var task = Task.Run(async () =>
|
||||
{
|
||||
var result = await found_handler.onCheckValid(this, recvProtocol);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"Failed to check Valid !!! : {fillupPacketCommand.toBasicString()}");
|
||||
}
|
||||
|
||||
result = await found_handler.onProcessPacket(this, recvProtocol);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"Failed to process Packet !!! : {fillupPacketCommand.toBasicString()}");
|
||||
}
|
||||
|
||||
if (null != stopwatch)
|
||||
{
|
||||
var elapsed_msec = stopwatch.ElapsedMilliseconds;
|
||||
stopwatch.Stop();
|
||||
Log.getLogger().debug($"{GetType()} MQSSPacket Stopwatch Stop : ETID:{event_tid}, ElapsedMSec:{elapsed_msec} - {recvProtocol.toBasicString()}");
|
||||
}
|
||||
});
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
|
||||
protected override async void onRecvJsonMessageFromConsumer(object? sender, BasicDeliverEventArgs ea)
|
||||
{
|
||||
var body = ea.Body.ToArray();
|
||||
var bodyStr = Encoding.UTF8.GetString(body);
|
||||
|
||||
ServerMessage? message = null;
|
||||
try
|
||||
{
|
||||
message = ServerMessage.Parser.ParseJson(bodyStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.getLogger().error($"consumer parsing error bodyStr : {bodyStr}, stackTrace : {e.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
if(message == null)
|
||||
{
|
||||
Log.getLogger().error($"message is null, bodyStr : {bodyStr}");
|
||||
return;
|
||||
}
|
||||
|
||||
if(_fnServerMessageRecvFromConsumer == null)
|
||||
{
|
||||
Log.getLogger().error("_fnServerMessageRecvFromConsumer is null");
|
||||
return;
|
||||
}
|
||||
|
||||
await _fnServerMessageRecvFromConsumer.Invoke(ea, message);
|
||||
}
|
||||
|
||||
protected override void onRecvProtoMessageFromConsumer(object? sender, BasicDeliverEventArgs ea)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual bool onCheckByExchangeType<T>(BasicDeliverEventArgs ea, T recvProtocol)
|
||||
where T : Google.Protobuf.IMessage
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<object>? SendKick( string destServer, string name, Int32 delayMS
|
||||
, Action<Task<object>>? callback )
|
||||
{
|
||||
int reqId = nextReqId();
|
||||
Task<object>? waitTask = null;
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
CancellationTokenSource cancelTokenSrc = new CancellationTokenSource(delayMS);
|
||||
|
||||
waitTask = registerCompletionSource(reqId, cancelTokenSrc.Token, callback);
|
||||
if (waitTask == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ServerMessage message = new ServerMessage();
|
||||
message.KickReq = new ServerMessage.Types.KickReq();
|
||||
message.KickReq.ReqId = reqId;
|
||||
message.KickReq.Name = name;
|
||||
|
||||
SendMessage(destServer, message);
|
||||
|
||||
return waitTask;
|
||||
}
|
||||
|
||||
public void SendMessage(string to, ServerMessage message)
|
||||
{
|
||||
IConnection? con = getConnection();
|
||||
if(con == null)
|
||||
{
|
||||
Log.getLogger().error("GetConnection return null");
|
||||
return;
|
||||
}
|
||||
using (var channel = con.CreateModel())
|
||||
{
|
||||
Stopwatch? stopwatch = null;
|
||||
var event_tid = string.Empty;
|
||||
|
||||
var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
|
||||
if (true == server_config.PerformanceCheckEnable)
|
||||
{
|
||||
event_tid = System.Guid.NewGuid().ToString("N");
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
channel.QueueDeclare( queue: to,
|
||||
durable: true,
|
||||
exclusive: false,
|
||||
autoDelete: true,
|
||||
arguments: null );
|
||||
|
||||
message.MessageTime = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow);
|
||||
message.MessageSender = getServiceName();
|
||||
|
||||
string messageJson = JsonFormatter.Default.Format(message);
|
||||
var body = Encoding.UTF8.GetBytes(messageJson);
|
||||
|
||||
channel.BasicPublish( exchange: "",
|
||||
routingKey: to,
|
||||
basicProperties: null,
|
||||
body: body );
|
||||
|
||||
Log.getLogger().info($"send to MQS !!!, msg:{messageJson} - receiver:{to}");
|
||||
|
||||
if (null != stopwatch)
|
||||
{
|
||||
var elapsed_msec = stopwatch.ElapsedMilliseconds;
|
||||
stopwatch.Stop();
|
||||
Log.getLogger().debug($"{GetType()} SMQSPacket Stopwatch Stop : ETID:{event_tid}, ElapsedMSec:{stopwatch.ElapsedMilliseconds} - {message.toBasicString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Result onCreateExchangeChannel();
|
||||
|
||||
public PacketReceiver getPacketReceiver() => m_packet_receiver;
|
||||
|
||||
public ModuleContext getModuleContext() => m_module_context;
|
||||
|
||||
public virtual string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user