1 module buffer.rpc.server;
2 
3 import std.traits;
4 import std.algorithm.searching;
5 import std.conv : to;
6 import std.variant;
7 
8 import buffer.message;
9 
10 class Server(Business)
11 {
12     static immutable string[] builtinFunctions = [ "__ctor", "__dtor", "opEquals", "opCmp", "toHash", "toString", "Monitor", "factory" ];
13     Business business = new Business();
14 
15     ubyte[] Handler(ubyte[] data)
16     {
17         ushort messageId;
18         TypeInfo_Class messageName;
19         string method;
20         Variant[] params = Message.deserialize(data, messageId, messageName, method);
21 
22         if (params is null)
23         {
24             return null;
25         }
26 
27         foreach (member; __traits(allMembers, Business))
28         {
29             alias MemberFunctionsTuple!(Business, member) funcs;
30 
31             static if (funcs.length > 0 && !canFind(builtinFunctions, member))
32             {
33                 static assert(funcs.length == 1, "The function of RPC call doesn't allow the overloads, function: " ~ member);
34 
35                 alias typeof(funcs[0]) func;
36                 alias ParameterTypeTuple!func ParameterTypes;
37                 alias ReturnType!func T;
38 
39                 static assert((
40                         is(T == byte) || is(T == ubyte) || is(T == short) || is(T == ushort) || is(T == int)  || is(T == uint)
41                      || is(T == long) || is(T == ulong) || is(T == float) || is(T == double) || is(T == bool) || is(T == char)
42                      || is(T == string) || (BaseTypeTuple!T.length > 0 && is(BaseTypeTuple!T[0] == Message))),
43                         "The function of RPC call return type is incorrect, function: " ~ member);
44 
45                 static if (isBuiltinType!T)
46                 {
47                     mixin(`
48                         if (method == "` ~ member ~ `")
49                         {
50                             assert(` ~ ParameterTypes.length.to!string ~ ` == params.length, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
51                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
52                             return Message.serialize_without_msginfo(method, ret);
53                         }
54                     `);
55                 }
56                 else
57                 {
58                     mixin(`
59                         if (method == "` ~ member ~ `")
60                         {
61                             assert(` ~ ParameterTypes.length.to!string ~ ` == params.length, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
62                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
63                             return ret.serialize();
64                         }
65                     `);
66                 }
67             }
68         }
69 
70         assert(0, "The server does not implement client call method: " ~ method);
71     }
72 
73     static string combineParams(ParameterTypes...)()
74     {
75         string s;
76 
77         foreach (i, type; ParameterTypes)
78         {
79             if (i > 0)
80                 s ~= ", ";
81             s ~= ("params[" ~ i.to!string ~ "].get!" ~ type.stringof);
82         }
83 
84         return s;
85     }
86 }