1 module buffer.rpc.server;
2 
3 import std.meta : staticIndexOf;
4 import std.traits;
5 import std.algorithm.searching;
6 import std.conv : to;
7 import std.variant;
8 
9 import buffer.message;
10 
11 class Server(Business)
12 {
13     static immutable string[] builtinFunctions = [ "__ctor", "__dtor", "opEquals", "opCmp", "toHash", "toString", "Monitor", "factory" ];
14     private Business business = new Business();
15 
16     this()
17     {
18         business = new Business();
19     }
20 
21     ubyte[] Handler(string Package = string.init, Stuff...)(const ubyte[] data, Stuff stuff)
22     {
23         string name;
24         string method;
25         Variant[] params = Message.deserialize(data, name, method);
26         foreach (s; stuff)
27         {
28             params ~= Variant(s);
29         }
30 
31         foreach (member; __traits(allMembers, Business))
32         {
33             alias funcs = MemberFunctionsTuple!(Business, member);
34 
35             static if (funcs.length > 0 && !canFind(builtinFunctions, member))
36             {
37                 static assert(funcs.length == 1, "The function of RPC call doesn't allow the overloads, function: " ~ member);
38 
39                 alias func = typeof(funcs[0]);
40                 alias ParameterTypes = ParameterTypeTuple!func;
41                 alias T = ReturnType!func;
42 
43                 static assert(is(T == void) || (staticIndexOf!(T, supportedBuiltinTypes) != -1) || ((BaseTypeTuple!T.length > 0) && is(BaseTypeTuple!T[0] == Message)),
44                         "The function of RPC call return type is incorrect, function: " ~ member);
45 
46                 static if (Package != string.init)
47                 {
48                     mixin("import " ~ Package ~ ";");
49                 }
50 
51                 static if (is(T == void))
52                 {
53                     mixin(`
54                         if (method == "` ~ member ~ `")
55                         {
56                             if (params.length < ` ~ ParameterTypes.length.to!string ~ `)
57                             {
58                                 import std.stdio : writeln;
59                                 writeln("Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
60                                 assert(0, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
61                             }
62 
63                             business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
64                             return null;
65                         }
66                     `);
67                 }
68                 else static if (isBuiltinType!T)
69                 {
70                     mixin(`
71                         if (method == "` ~ member ~ `")
72                         {
73                             if (params.length < ` ~ ParameterTypes.length.to!string ~ `)
74                             {
75                                 import std.stdio : writeln;
76                                 writeln("Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
77                                 assert(0, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
78                             }
79 
80                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
81                             return Message.serialize_without_msginfo(method, ret);
82                         }
83                     `);
84                 }
85                 else
86                 {
87                     mixin(`
88                         if (method == "` ~ member ~ `")
89                         {
90                             if (params.length < ` ~ ParameterTypes.length.to!string ~ `)
91                             {
92                                 import std.stdio : writeln;
93                                 writeln("Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
94                                 assert(0, "Incorrect number of parameters, ` ~ member ~ ` requires ` ~ ParameterTypes.length.to!string ~ ` parameters.");
95                             }
96 
97                             T ret = business.` ~ member ~ `(` ~ combineParams!ParameterTypes ~ `);
98                             return ((ret is null) ? null : ret.serialize());
99                         }
100                     `);
101                 }
102             }
103         }
104 
105         // Server does not implement client call method.
106         return null;
107     }
108 
109     private static string combineParams(ParameterTypes...)()
110     {
111         string s;
112 
113         foreach (i, type; ParameterTypes)
114         {
115             if (i > 0) s ~= ", ";
116 
117             s ~= ("params[" ~ i.to!string ~ "].get!" ~ type.stringof);
118         }
119 
120         return s;
121     }
122 }