提交 1d1b0499 编写于 作者: T tanghai

重新设计了RPC服务端代码,使用起来更简单更不容易出错

上级 05b2758d
......@@ -23,7 +23,7 @@ namespace App
Object.ObjectManager.Register("Controller", controller);
Options options = Game.Scene.AddComponent<OptionsComponent, string[]>(args).Options;
Game.Scene.AddComponent<EventComponent>();
Game.Scene.AddComponent<TimerComponent>();
Game.Scene.AddComponent<NetworkComponent, NetworkProtocol, string, int>(options.Protocol, options.Host, options.Port);
......
......@@ -122,12 +122,12 @@
<Compile Include="..\..\Unity\Assets\Plugins\Base\LogType.cs">
<Link>LogType.cs</Link>
</Compile>
<Compile Include="..\..\Unity\Assets\Plugins\Base\Message\AMessage.cs">
<Link>Message\AMessage.cs</Link>
</Compile>
<Compile Include="..\..\Unity\Assets\Plugins\Base\Message\AMEvent.cs">
<Link>Message\AMEvent.cs</Link>
</Compile>
<Compile Include="..\..\Unity\Assets\Plugins\Base\Message\IErrorMessage.cs">
<Link>Message\IErrorMessage.cs</Link>
</Compile>
<Compile Include="..\..\Unity\Assets\Plugins\Base\Message\IMRegister.cs">
<Link>Message\IMRegister.cs</Link>
</Compile>
......
using Base;
using System;
using Base;
using Model;
namespace Controller
{
[MessageHandler(AppType.Realm)]
public class C2S_LoginEvent: AMRpcEvent<C2S_Login>
public class C2S_LoginHandler: AMRpcEvent<C2S_Login, S2C_Login>
{
protected override void Run(Entity scene, C2S_Login message, uint rpcId)
protected override void Run(Entity scene, C2S_Login message, Action<S2C_Login> reply)
{
Log.Info(MongoHelper.ToJson(message));
scene.GetComponent<MessageComponent>().Reply(rpcId, new S2C_Login());
reply(new S2C_Login());
}
}
}
\ No newline at end of file
using Base;
using System;
using Base;
using Model;
namespace Controller
{
[MessageHandler(AppType.Realm)]
public class C2S_SubscribeLogEvent : AMRpcEvent<C2S_SubscribeLog>
public class C2S_SubscribeLogHandler : AMRpcEvent<C2S_SubscribeLog, S2C_SubscribeLog>
{
protected override void Run(Entity entity, C2S_SubscribeLog message, uint rpcId)
protected override void Run(Entity entity, C2S_SubscribeLog message, Action<S2C_SubscribeLog> reply)
{
Log.Info(MongoHelper.ToJson(message));
entity.AddComponent<LogToClientComponent>();
entity.GetComponent<MessageComponent>().Reply(rpcId, new S2C_SubscribeLog());
reply(new S2C_SubscribeLog());
}
}
}
\ No newline at end of file
......@@ -34,9 +34,9 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="C2S_SubscribeLogEvent.cs" />
<Compile Include="C2S_SubscribeLogHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="C2S_LoginEvent.cs" />
<Compile Include="C2S_LoginHandler.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Base\Server.Base.csproj">
......
......@@ -13,8 +13,11 @@ namespace Model
public class LogToClientComponent : Component
{
private string appType;
public void Awake()
{
this.appType = Game.Scene.GetComponent<OptionsComponent>().Options.AppType;
Log.Callback.Add(this.Id, this.LogToClient);
}
......@@ -24,7 +27,7 @@ namespace Model
{
return;
}
this.GetComponent<MessageComponent>().Send(new S2C_ServerLog { Type = type, Log = message });
this.GetComponent<MessageComponent>().Send(new S2C_ServerLog { AppType = this.appType, Type = type, Log = message });
}
public override void Dispose()
......
......@@ -41,6 +41,9 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Unity\Assets\Scripts\Component\AppInfoComponent.cs">
<Link>Component\AppInfoComponent.cs</Link>
</Compile>
<Compile Include="..\..\Unity\Assets\Scripts\Component\EventComponent.cs">
<Link>Component\EventComponent.cs</Link>
</Compile>
......
namespace Base
using System;
namespace Base
{
public abstract class AMEvent<T>: IMRegister
public abstract class AMEvent<Message>: IMRegister where Message: AMessage
{
protected abstract void Run(Entity scene, T message);
protected abstract void Run(Entity scene, Message message);
public void Register(IMessageDispather component)
{
ushort opcode = component.GetOpcode(typeof (T));
component.RegisterHandler<T>(opcode, Run);
ushort opcode = component.GetOpcode(typeof (Message));
component.RegisterHandler<Message>(opcode, Run);
}
}
public abstract class AMRpcEvent<T> : IMRegister
public abstract class AMRpcEvent<Request, Response> : IMRegister
where Request : ARequest
where Response: AResponse
{
protected abstract void Run(Entity scene, T message, uint rpcId);
protected abstract void Run(Entity scene, Request message, Action<Response> reply);
public void Register(IMessageDispather component)
{
ushort opcode = component.GetOpcode(typeof(T));
component.RegisterRpcHandler<T>(opcode, Run);
ushort opcode = component.GetOpcode(typeof(Request));
component.RegisterRpcHandler<Request, Response>(opcode, Run);
}
}
}
\ No newline at end of file
......@@ -6,7 +6,6 @@
public abstract class ARequest : AMessage
{
public uint RpcId;
}
/// <summary>
......@@ -14,8 +13,6 @@
/// </summary>
public abstract class AResponse: AMessage
{
public uint RpcId;
public int ErrorCode = 0;
public string Message = "";
}
......
......@@ -5,8 +5,11 @@ namespace Base
public interface IMessageDispather
{
ushort GetOpcode(Type type);
void RegisterHandler<T>(ushort opcode, Action<Entity, T> action);
void RegisterRpcHandler<T>(ushort opcode, Action<Entity, T, uint> action);
void RegisterHandler<Message>(ushort opcode, Action<Entity, Message> action) where Message : AMessage;
void RegisterRpcHandler<Request, Response>(ushort opcode, Action<Entity, Request, Action<Response>> action)
where Request : ARequest
where Response : AResponse;
}
public interface IMRegister
......
using Base;
namespace Model
{
[ObjectEvent]
public class AppInfoComponentEvent : ObjectEvent<AppInfoComponent>, IAwake<string>
{
public void Awake(string appType)
{
this.GetValue().Awake(appType);
}
}
public class AppInfoComponent : Component
{
private string AppType { get; set; }
public void Awake(string appType)
{
this.AppType = appType;
}
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: d4852a0f714d73f43af0109603bd32ba
timeCreated: 1476849603
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
......@@ -99,20 +99,24 @@ namespace Model
private void RunDecompressedBytes(ushort opcode, uint rpcId, uint rpcFlag, byte[] messageBytes, int offset)
{
// 普通消息
if (rpcId == 0)
{
this.messageDispather.Handle(this.Owner, opcode, messageBytes, offset);
return;
}
// rpcFlag>0 表示这是一个rpc响应消息
if (rpcFlag > 0)
{
Action<byte[], int, int> action;
if (this.requestCallback.TryGetValue(rpcId, out action))
// Rpc回调有找不着的可能,因为client可能取消Rpc调用
if (!this.requestCallback.TryGetValue(rpcId, out action))
{
this.requestCallback.Remove(rpcId);
action(messageBytes, offset, messageBytes.Length - offset);
return;
}
this.requestCallback.Remove(rpcId);
action(messageBytes, offset, messageBytes.Length - offset);
}
else // 这是一个rpc请求消息
{
......@@ -161,7 +165,6 @@ namespace Model
where Request: ARequest
where Response : AResponse
{
request.RpcId = ++RpcId;
this.SendMessage(++RpcId, request);
var tcs = new TaskCompletionSource<Response>();
this.requestCallback[RpcId] = (bytes, offset, count) =>
......@@ -185,12 +188,12 @@ namespace Model
return tcs.Task;
}
public void Send(object message)
public void Send<Message>(Message message) where Message: AMessage
{
this.SendMessage(0, message);
}
public void Reply<T>(uint rpcId, T message) where T: AResponse
public void Reply<Response>(uint rpcId, Response message) where Response: AResponse
{
this.SendMessage(rpcId, message, false);
}
......@@ -199,18 +202,24 @@ namespace Model
{
ushort opcode = this.messageDispather.GetOpcode(message.GetType());
byte[] opcodeBytes = BitConverter.GetBytes(opcode);
if (rpcId > 0 && !isCall)
if (!isCall)
{
rpcId = rpcId | 0x4fffffff;
rpcId = rpcId | 0x40000000;
}
byte[] seqBytes = BitConverter.GetBytes(rpcId);
byte[] messageBytes = MongoHelper.ToBson(message);
if (channel == null)
byte[] messageBytes = MongoHelper.ToBson(message);
if (messageBytes.Length > 100)
{
throw new Exception("game channel not found!");
byte[] newMessageBytes = ZipHelper.Compress(messageBytes);
if (newMessageBytes.Length < messageBytes.Length)
{
messageBytes = newMessageBytes;
rpcId = rpcId | 0x80000000;
}
}
byte[] seqBytes = BitConverter.GetBytes(rpcId);
channel.Send(new List<byte[]> { opcodeBytes, seqBytes, messageBytes });
}
......
......@@ -35,9 +35,9 @@ namespace Model
}
private string AppType;
private Dictionary<ushort, List<Action<Entity, MessageInfo>>> events;
private Dictionary<ushort, List<Action<Entity, MessageInfo>>> rpcHandlers;
public Dictionary<Type, MessageAttribute> messageOpcode { get; private set; } = new Dictionary<Type, MessageAttribute>();
private Dictionary<ushort, List<Action<Entity, MessageInfo>>> handlers;
private Dictionary<ushort, Action<Entity, MessageInfo>> rpcHandlers;
private Dictionary<Type, MessageAttribute> messageOpcode { get; set; } = new Dictionary<Type, MessageAttribute>();
public void Awake(string appType)
{
......@@ -47,8 +47,8 @@ namespace Model
public void Load()
{
this.events = new Dictionary<ushort, List<Action<Entity, MessageInfo>>>();
this.rpcHandlers = new Dictionary<ushort, List<Action<Entity, MessageInfo>>>();
this.handlers = new Dictionary<ushort, List<Action<Entity, MessageInfo>>>();
this.rpcHandlers = new Dictionary<ushort, Action<Entity, MessageInfo>>();
this.messageOpcode = new Dictionary<Type, MessageAttribute>();
Assembly[] assemblies = Object.ObjectManager.GetAssemblies();
......@@ -91,7 +91,7 @@ namespace Model
IMRegister iMRegister = obj as IMRegister;
if (iMRegister == null)
{
throw new Exception($"message handler not inherit IEventSync or IEventAsync interface: {obj.GetType().FullName}");
throw new Exception($"message handler not inherit AMEvent or AMRpcEvent abstract class: {obj.GetType().FullName}");
}
iMRegister.Register(this);
}
......@@ -103,51 +103,55 @@ namespace Model
return this.messageOpcode[type].Opcode;
}
public void RegisterHandler<T>(ushort opcode, Action<Entity, T> action)
public void RegisterHandler<Message>(ushort opcode, Action<Entity, Message> action) where Message: AMessage
{
if (!this.events.ContainsKey(opcode))
if (!this.handlers.ContainsKey(opcode))
{
this.events.Add(opcode, new List<Action<Entity, MessageInfo>>());
this.handlers.Add(opcode, new List<Action<Entity, MessageInfo>>());
}
List<Action<Entity, MessageInfo>> actions = this.events[opcode];
List<Action<Entity, MessageInfo>> actions = this.handlers[opcode];
actions.Add((entity, messageInfo) =>
{
T t;
Message message;
try
{
t = MongoHelper.FromBson<T>(messageInfo.MessageBytes, messageInfo.Offset, messageInfo.Count);
message = MongoHelper.FromBson<Message>(messageInfo.MessageBytes, messageInfo.Offset, messageInfo.Count);
}
catch (Exception ex)
{
throw new Exception("解释消息失败:" + opcode, ex);
}
action(entity, t);
action(entity, message);
});
}
public void RegisterRpcHandler<T>(ushort opcode, Action<Entity, T, uint> action)
public void RegisterRpcHandler<Request, Response>(ushort opcode, Action<Entity, Request, Action<Response>> action)
where Request: ARequest
where Response: AResponse
{
if (!this.rpcHandlers.ContainsKey(opcode))
if (this.rpcHandlers.ContainsKey(opcode))
{
this.rpcHandlers.Add(opcode, new List<Action<Entity, MessageInfo>>());
Log.Error($"rpc消息不能注册两次! opcode: {opcode}");
return;
}
List<Action<Entity, MessageInfo>> actions = this.rpcHandlers[opcode];
actions.Add((entity, messageInfo) =>
this.rpcHandlers.Add(opcode, (entity, messageInfo) =>
{
T t;
Request request;
try
{
t = MongoHelper.FromBson<T>(messageInfo.MessageBytes, messageInfo.Offset, messageInfo.Count);
request = MongoHelper.FromBson<Request>(messageInfo.MessageBytes, messageInfo.Offset, messageInfo.Count);
}
catch (Exception ex)
{
throw new Exception("解释消息失败:" + opcode, ex);
}
action(entity, t, messageInfo.RpcId);
action(entity, request, response =>
{
entity.GetComponent<MessageComponent>().Reply(messageInfo.RpcId, response);
});
});
}
......@@ -155,7 +159,7 @@ namespace Model
public void Handle(Entity entity, ushort opcode, byte[] messageBytes, int offset)
{
List<Action<Entity, MessageInfo>> actions;
if (!this.events.TryGetValue(opcode, out actions))
if (!this.handlers.TryGetValue(opcode, out actions))
{
Log.Error($"消息 {opcode} 没有处理");
return;
......@@ -176,23 +180,20 @@ namespace Model
public void HandleRpc(Entity entity, ushort opcode, byte[] messageBytes, int offset, uint rpcId)
{
List<Action<Entity, MessageInfo>> actions;
if (!this.rpcHandlers.TryGetValue(opcode, out actions))
Action<Entity, MessageInfo> action;
if (!this.rpcHandlers.TryGetValue(opcode, out action))
{
Log.Error($"Rpc消息 {opcode} 没有处理");
return;
}
foreach (var ev in actions)
try
{
try
{
ev(entity, new MessageInfo { MessageBytes = messageBytes, Offset = offset, Count = messageBytes.Length - offset, RpcId = rpcId });
}
catch (Exception e)
{
Log.Error(e.ToString());
}
action(entity, new MessageInfo { MessageBytes = messageBytes, Offset = offset, Count = messageBytes.Length - offset, RpcId = rpcId });
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
......
......@@ -21,8 +21,9 @@ namespace Model
[Message(3)]
[BsonIgnoreExtraElements]
public class S2C_ServerLog
public class S2C_ServerLog: AMessage
{
public string AppType;
public LogType Type;
public string Log;
}
......
......@@ -4,11 +4,11 @@ using Model;
namespace Controller
{
[MessageHandler(AppType.Client)]
public class S2C_ServerLogEvent: AMEvent<S2C_ServerLog>
public class S2C_ServerLogHandler: AMEvent<S2C_ServerLog>
{
protected override void Run(Entity scene, S2C_ServerLog message)
{
Log.Debug(message.Log);
Log.Debug($"[{message.AppType}] [{message.Type}] {message.Log}");
}
}
}
......@@ -54,7 +54,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Event\InitSceneStartEvent_InitGame.cs" />
<Compile Include="Message\S2C_ServerLogEvent.cs" />
<Compile Include="Message\S2C_ServerLogHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -100,7 +100,7 @@
<Compile Include="Assets\Plugins\Base\Log.cs" />
<Compile Include="Assets\Plugins\Base\LogType.cs" />
<Compile Include="Assets\Plugins\Base\Message\AMEvent.cs" />
<Compile Include="Assets\Plugins\Base\Message\IErrorMessage.cs" />
<Compile Include="Assets\Plugins\Base\Message\AMessage.cs" />
<Compile Include="Assets\Plugins\Base\Message\IMRegister.cs" />
<Compile Include="Assets\Plugins\Base\Message\MessageHandlerAttribute.cs" />
<Compile Include="Assets\Plugins\Base\Message\MessageAttribute.cs" />
......
......@@ -83,6 +83,7 @@
<Compile Include="Assets\Scripts\Component\EventComponent.cs" />
<Compile Include="Assets\Scripts\Component\GameObjectComponent.cs" />
<Compile Include="Assets\Scripts\Component\GlobalConfigComponent.cs" />
<Compile Include="Assets\Scripts\Component\AppInfoComponent.cs" />
<Compile Include="Assets\Scripts\Component\KVComponent.cs" />
<Compile Include="Assets\Scripts\Component\MessageComponent.cs" />
<Compile Include="Assets\Scripts\Component\MessageDispatherComponent.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册