1 /// 2 module drmi.base; 3 4 import drmi.types; 5 import drmi.exceptions; 6 import drmi.helpers; 7 8 /// 9 interface RMICom 10 { 11 /// 12 RMIResponse process(RMICall call); 13 } 14 15 /// 16 class RMISkeleton(T) : RMICom 17 if (is(T == interface)) 18 { 19 protected: 20 T server; 21 22 public: 23 24 /// 25 this(T server) 26 { 27 import std.exception : enforce; 28 this.server = enforce(server, "server is null"); 29 } 30 31 override RMIResponse process(RMICall call) 32 { 33 import std.meta; 34 import std.traits; 35 import std.typecons : tuple; 36 37 template ov(string s) { alias ov = AliasSeq!(__traits(getOverloads, T, s)); } 38 39 switch (call.func) 40 { 41 foreach (n, func; staticMap!(ov, __traits(derivedMembers, T))) 42 { 43 case rmiFunctionName!func: 44 try 45 { 46 auto params = Parameters!func.init; 47 48 static if (params.length) 49 params = call.data.sbinDeserialize!(typeof(tuple(params))); 50 51 ubyte[] resData; 52 enum callstr = "server."~__traits(identifier, func)~"(params)"; 53 static if(is(ReturnType!func == void)) mixin(callstr~";"); 54 else resData = mixin(callstr).sbinSerialize; 55 56 return RMIResponse(0, call, resData); 57 } 58 catch (Throwable e) 59 return RMIResponse(2, call, e.msg.sbinSerialize); 60 } 61 default: 62 return RMIResponse(1, call, "unknown func".sbinSerialize); 63 } 64 } 65 } 66 67 /// 68 interface RMIStubCom : RMICom 69 { 70 /// 71 string caller() const @property; 72 } 73 74 /// 75 class RMIStub(T) : T 76 { 77 protected: 78 RMIStubCom com; 79 public: 80 /// 81 this(RMIStubCom com) { this.com = com; } 82 83 private mixin template overrideIface() 84 { 85 private enum string packCode = 86 q{ 87 enum dummy; 88 alias self = AliasSeq!(__traits(parent, dummy))[0]; 89 90 static fname = rmiFunctionName!self; 91 92 RMICall call; 93 call.caller = com.caller; 94 call.func = fname; 95 call.ts = Clock.currStdTime; 96 97 auto tmp = tuple(Parameters!self.init); 98 foreach (i, p; ParameterIdentifierTuple!self) 99 tmp[i] = mixin(p); 100 101 call.data = tmp.sbinSerialize; 102 103 auto result = com.process(call); 104 105 enforce(result.status == 0, new RMIProcessException(result)); 106 107 static if (!is(typeof(return) == void)) 108 return result.data.sbinDeserialize!(typeof(return)); 109 }; 110 111 import std.datetime : Clock; 112 import std.exception : enforce; 113 import std.typecons : tuple; 114 import std.meta : staticMap; 115 import std.traits : ReturnType, AliasSeq, Parameters, ParameterIdentifierTuple, 116 functionAttributes, FunctionAttribute; 117 118 private mixin template impl(F...) 119 { 120 private static string trueParameters(alias FNC)() 121 { 122 import std.conv : text; 123 import std.string : join; 124 string[] ret; 125 foreach (i, param; Parameters!FNC) 126 ret ~= `Parameters!(F[0])[`~text(i)~`] __param_` ~ text(i); 127 return ret.join(", "); 128 } 129 130 private static string getAttributesString(alias FNC)() 131 { 132 import std.string : join; 133 string[] ret; 134 // TODO 135 ret ~= functionAttributes!FNC & FunctionAttribute.property ? "@property" : ""; 136 return ret.join(" "); 137 } 138 139 static if (F.length == 1) 140 { 141 mixin("override ReturnType!(F[0]) " ~ __traits(identifier, F[0]) ~ 142 `(` ~ trueParameters!(F[0]) ~ `) ` ~ getAttributesString!(F[0]) ~ 143 ` { ` ~ packCode ~ `}`); 144 } 145 else 146 { 147 mixin impl!(F[0..$/2]); 148 mixin impl!(F[$/2..$]); 149 } 150 } 151 152 private template getOverloads(string s) 153 { alias getOverloads = AliasSeq!(__traits(getOverloads, T, s)); } 154 155 mixin impl!(staticMap!(getOverloads, __traits(derivedMembers, T))); 156 } 157 158 mixin overrideIface; 159 } 160 161 private version (unittest) 162 { 163 struct Point { double x, y, z; } 164 165 interface Test 166 { 167 int foo(string abc, int xyz); 168 string foo(string str); 169 string bar(double val); 170 double len(Point pnt); 171 string state() @property; 172 void state(string s) @property; 173 } 174 175 class Impl : Test 176 { 177 string _state; 178 override: 179 string foo(string str) { return "<" ~ str ~ ">"; } 180 int foo(string abc, int xyz) { return cast(int)(abc.length * xyz); } 181 string bar(double val) { return val > 3.14 ? "big" : "small"; } 182 double len(Point pnt) 183 { 184 import std.math; 185 return sqrt(pnt.x^^2 + pnt.y^^2 + pnt.z^^2); 186 } 187 string state() @property { return _state; } 188 void state(string s) @property { _state = s; } 189 } 190 } 191 192 unittest 193 { 194 auto rea = new Impl; 195 auto ske = new RMISkeleton!Test(rea); 196 auto cli = new RMIStub!Test(new class RMIStubCom 197 { 198 string caller() const @property { return "fake caller"; } 199 RMIResponse process(RMICall call) { return ske.process(call); } 200 }); 201 202 assert(rea.foo("hello", 123) == cli.foo("hello", 123)); 203 assert(rea.bar(2.71) == cli.bar(2.71)); 204 assert(rea.bar(3.1415) == cli.bar(3.1415)); 205 assert(rea.foo("okda") == cli.foo("okda")); 206 assert(rea.len(Point(1,2,3)) == cli.len(Point(1,2,3))); 207 208 static str = "foo"; 209 cli.state = str; 210 assert(rea.state == str); 211 assert(cli.state == str); 212 }