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     private Business business = new Business();
14 
15     this()
16     {
17         business = new Business();
18     }
19 
20     ubyte[] Handler(string Package = string.init, Stuff...)(ubyte[] data, Stuff stuff)
21     {
22         string name;
23         string method;
24         Variant[] params = Message.deserialize(data, name, method);
25         foreach (s; stuff)
26         {
27             params ~= Variant(s);
28         }
29 
30         foreach (member; __traits(allMembers, Business))
31         {
32             alias MemberFunctionsTuple!(Business, member) funcs;
33 
34             static if (funcs.length > 0 && !canFind(builtinFunctions, member))
35             {
36                 static assert(funcs.length == 1, "The function of RPC call doesn't allow the overloads, function: " ~ member);
37 
38                 alias typeof(funcs[0]) func;
39                 alias ParameterTypeTuple!func ParameterTypes;
40                 alias ReturnType!func T;
41 
42                 static assert((
43                         is(T == byte) || is(T == ubyte)  || is(T == short) || is(T == ushort) || is(T == int)  || is(T == uint)
44                      || is(T == long) || is(T == ulong)  || is(T == float) || is(T == double) || is(T == real) || is(T == bool)
45                      || is(T == char) || is(T == string) || ((BaseTypeTuple!T.length > 0) && is(BaseTypeTuple!T[0] == Message))),
46                         "The function of RPC call return type is incorrect, function: " ~ member);
47 
48                 static if (Package != string.init)
49                 {
50                     mixin("import " ~ Package ~ ";");
51                 }
52 
53                 static if (isBuiltinType!T)
54                 {
55                     mixin(`
56                         if (method == "` ~ member ~ `")
57                         {
58                             if (params.length < ` ~ ParameterTypes.length.to!string ~ `)
59                             {
60                                 import std.stdio;
61                                 writeln("Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
62                                 assert(0, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` lengthString!(ParameterTypes.length).");
63                             }
64 
65                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
66 
67                             return Message.serialize_without_msginfo(method, ret);
68                         }
69                     `);
70                 }
71                 else
72                 {
73                     mixin(`
74                         if (method == "` ~ member ~ `")
75                         {
76                             if (params.length < ` ~ ParameterTypes.length.to!string ~ `)
77                             {
78                                 import std.stdio;
79                                 writeln("Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
80                                 assert(0, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
81                             }
82 
83                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
84 
85                             if (ret is null)
86                             {
87                                 return null;
88                             }
89 
90                             return ret.serialize();
91                         }
92                     `);
93                 }
94             }
95         }
96 
97         assert(0, "The server does not implement client call method: " ~ method);
98     }
99 
100     private static string combineParams(ParameterTypes...)()
101     {
102         string s;
103 
104         foreach (i, type; ParameterTypes)
105         {
106             if (i > 0) s ~= ", ";
107 
108             s ~= ("params[" ~ i.to!string ~ "].get!" ~ type.stringof);
109         }
110 
111         return s;
112     }
113 }