1 /**********************************************************\ 2 | | 3 | hprose | 4 | | 5 | Official WebSite: http://www.hprose.com/ | 6 | http://www.hprose.org/ | 7 | | 8 \**********************************************************/ 9 10 /**********************************************************\ 11 * * 12 * hprose/rpc/service.d * 13 * * 14 * hprose service library for D. * 15 * * 16 * LastModified: Apr 22, 2016 * 17 * Author: Ma Bingyao <andot@hprose.com> * 18 * * 19 \**********************************************************/ 20 21 module hprose.rpc.service; 22 23 import hprose.io; 24 import hprose.rpc.common; 25 import hprose.rpc.context; 26 import hprose.rpc.filter; 27 import std.conv; 28 import std.stdio; 29 import std.string; 30 import std.traits; 31 import std.typecons; 32 import std.variant; 33 34 alias OnBeforeInvoke = void delegate(string name, Variant[] args, bool byRef, Context context); 35 alias OnAfterInvoke = void delegate(string name, Variant[] args, bool byRef, Variant result, Context context); 36 alias OnSendError = Exception delegate(Exception e, Context context); 37 38 class Service { 39 40 private { 41 alias RemoteMethod = char delegate(string, Reader, BytesIO, Context); 42 Filter[] _filters; 43 RemoteMethod[string] _remoteMethods; 44 string[] _allNames; 45 } 46 47 bool simple = false; 48 49 bool debugEnabled = false; 50 51 OnBeforeInvoke onBeforeInvoke = null; 52 OnAfterInvoke onAfterInvoke = null; 53 OnSendError onSendError = null; 54 InvokeHandler[] invokeHandlers = []; 55 FilterHandler[] beforeFilterHandlers = []; 56 FilterHandler[] afterFilterHandlers = []; 57 NextFilterHandler beforeFilterHandler; 58 NextFilterHandler afterFilterHandler; 59 60 @property ref filters() { 61 return this._filters; 62 } 63 64 this() { 65 this._filters = []; 66 beforeFilterHandler = &beforeFilter; 67 afterFilterHandler = &afterFilter; 68 } 69 70 private { 71 ubyte[] inputFilter(ubyte[] data, Context context) { 72 foreach_reverse(filter; _filters) { 73 data = filter.inputFilter(data, context); 74 } 75 return data; 76 } 77 78 ubyte[] outputFilter(ubyte[] data, Context context) { 79 foreach(filter; _filters) { 80 data = filter.outputFilter(data, context); 81 } 82 return data; 83 } 84 85 ubyte[] sendError(Exception e, Context context) { 86 try { 87 if (onSendError !is null) { 88 Exception ex = onSendError(e, context); 89 if (ex !is null) { 90 e = ex; 91 } 92 } 93 } 94 catch (Exception ex) { 95 e = ex; 96 } 97 BytesIO stream = new BytesIO(); 98 Writer writer = new Writer(stream, true); 99 stream.write(TagError); 100 writer.writeString(debugEnabled ? e.toString() : e.msg); 101 stream.write(TagEnd); 102 return cast(ubyte[])stream.buffer; 103 } 104 } 105 106 protected { 107 ubyte[] doInvoke(BytesIO input, Context context) { 108 Reader reader = new Reader(input); 109 BytesIO output = new BytesIO(); 110 char tag; 111 do { 112 reader.reset(); 113 string name = reader.readString!string(); 114 string aliasName = toLower(name); 115 if (aliasName in _remoteMethods) { 116 tag = _remoteMethods[aliasName](name, reader, output, context); 117 } 118 else if ("*" in _remoteMethods) { 119 tag = _remoteMethods["*"](name, reader, output, context); 120 } 121 else { 122 throw new Exception("Can't find this method " ~ name); 123 } 124 } while (tag == TagCall); 125 if (tag != TagEnd && tag != 0) { 126 throw new Exception("Wrong Request: \r\n" ~ input.toString()); 127 } 128 if (tag == TagEnd) { 129 output.write(TagEnd); 130 } 131 return cast(ubyte[])output.buffer; 132 } 133 134 ubyte[] doFunctionList() { 135 BytesIO output = new BytesIO(); 136 Writer writer = new Writer(output, true); 137 output.write(TagFunctions); 138 writer.writeList(_allNames); 139 output.write(TagEnd); 140 return cast(ubyte[])output.buffer; 141 } 142 143 ubyte[] afterFilter(ubyte[] data, Context context) { 144 try { 145 BytesIO input = new BytesIO(data); 146 switch (input.read()) { 147 case TagCall: return doInvoke(input, context); 148 case TagEnd: return doFunctionList(); 149 default: throw new Exception("Wrong Request: \r\n" ~ input.toString()); 150 } 151 } 152 catch (Exception e) { 153 return sendError(e, context); 154 } 155 } 156 157 ubyte[] beforeFilter(ubyte[] data, Context context) { 158 try { 159 data = inputFilter(data, context); 160 data = afterFilterHandler(data, context); 161 return outputFilter(data, context); 162 } 163 catch (Exception e) { 164 return outputFilter(sendError(e, context), context); 165 } 166 } 167 168 ubyte[] handle(ubyte[] data, Context context) { 169 return beforeFilterHandler(data, context); 170 } 171 } 172 173 void addFunction(string name, ResultMode mode = ResultMode.Normal, bool simple = false, T)(T func) if (isCallable!T && (name != "*" || is(ReturnType!T == Variant) && Parameters!T.length >= 2 && is(Parameters!T[0] == string) && is(Parameters!T[1] == Variant[]))) { 174 _remoteMethods[toLower(name)] = delegate(string aliasName, Reader reader, BytesIO output, Context context) { 175 alias returnType = ReturnType!T; 176 alias paramsType = Parameters!T; 177 alias defaultArgs = ParameterDefaults!T; 178 179 Tuple!(paramsType) args; 180 foreach (i, ref arg; args) { 181 static if (!is(defaultArgs[i] == void)) { 182 arg = defaultArgs[i]; 183 } 184 } 185 186 static if (is(paramsType[$ - 1] : Context)) { 187 args[$ - 1] = cast(paramsType[$ - 1])context; 188 } 189 190 static if (name == "*") { 191 args[0] = aliasName; 192 } 193 194 BytesIO input = reader.stream; 195 char tag = input.read(); 196 bool byRef = false; 197 if (tag == TagList) { 198 reader.reset(); 199 static if (name == "*") { 200 args[1] = reader.readArrayWithoutTag!(Variant[])(); 201 } 202 else static if (is(paramsType[$ - 1] : Context)) { 203 reader.readTupleWithoutTag(args[0 .. $ - 1]); 204 } 205 else { 206 reader.readTupleWithoutTag(args.expand); 207 } 208 tag = input.read(); 209 if (tag == TagTrue) { 210 byRef = true; 211 tag = input.read(); 212 } 213 } 214 if (onBeforeInvoke !is null) { 215 static if (name == "*") { 216 onBeforeInvoke(aliasName, args[1], byRef, context); 217 } 218 else { 219 onBeforeInvoke(aliasName, variantArray(args.expand), byRef, context); 220 } 221 } 222 static if (is(returnType == void)) { 223 Variant result = null; 224 } 225 else { 226 returnType result; 227 } 228 if (invokeHandlers.length == 0) { 229 static if (is(returnType == void)) { 230 func(args.expand); 231 } 232 else { 233 result = func(args.expand); 234 } 235 } 236 else { 237 NextInvokeHandler next = delegate Variant(string name, ref Variant[] args, Context context) { 238 Tuple!(paramsType) _args; 239 foreach (i, ref arg; _args) { 240 arg = args[i].get!(paramsType[i]); 241 } 242 Variant result; 243 static if (is(returnType == void)) { 244 func(_args.expand); 245 result = null; 246 } 247 else { 248 result = cast(Variant)(func(_args.expand)); 249 } 250 foreach (i, ref arg; _args) { 251 args[i] = cast(Variant)arg; 252 } 253 return result; 254 }; 255 256 foreach (handler; invokeHandlers) { 257 next = (delegate(NextInvokeHandler next, InvokeHandler handler) { 258 return delegate Variant(string name, ref Variant[] args, Context context) { 259 return handler(name, args, context, next); 260 }; 261 })(next, handler); 262 } 263 264 Variant[] _args = variantArray(args.expand); 265 266 static if (is(returnType == void)) { 267 next(name, _args, context); 268 } 269 else static if (is(returnType == Variant)) { 270 result = next(name, _args, context); 271 } 272 else { 273 result = next(name, _args, context).get!(returnType); 274 } 275 276 foreach (i, ref arg; args) { 277 arg = _args[i].get!(paramsType[i]); 278 } 279 } 280 281 if (onAfterInvoke !is null) { 282 static if (name == "*") { 283 onAfterInvoke(aliasName, args[1], byRef, result, context); 284 } 285 else { 286 onAfterInvoke(aliasName, variantArray(args.expand), byRef, cast(Variant)result, context); 287 } 288 } 289 static if (mode == ResultMode.RawWithEndTag) { 290 static if (is(returnType == Variant)) { 291 output.write(result.get!(ubyte[])); 292 } 293 else { 294 output.write(cast(ubyte[])result); 295 } 296 return 0; 297 } 298 else static if (mode == ResultMode.Raw) { 299 static if (is(returnType == Variant)) { 300 output.write(result.get!(ubyte[])); 301 } 302 else { 303 output.write(cast(ubyte[])result); 304 } 305 } 306 else { 307 output.write(TagResult); 308 Writer writer = new Writer(output, simple); 309 static if (mode == ResultMode.Serialized) { 310 static if (is(returnType == Variant)) { 311 output.write(result.get!(ubyte[])); 312 } 313 else { 314 output.write(cast(ubyte[])result); 315 } 316 } 317 else { 318 writer.serialize(result); 319 } 320 static if (name == "*") { 321 if (byRef) { 322 output.write(TagArgument); 323 writer.reset(); 324 writer.writeArray(args[1]); 325 } 326 } 327 else static if ((paramsType.length > 1) || (paramsType.length == 1) && is(paramsType[$ - 1] : Context)) { 328 if (byRef) { 329 output.write(TagArgument); 330 writer.reset(); 331 static if (is(paramsType[$ - 1] : Context)) { 332 writer.writeTuple(args[0 .. $ - 1]); 333 } 334 else { 335 writer.writeTuple(args.expand); 336 } 337 } 338 } 339 } 340 return tag; 341 }; 342 _allNames ~= name; 343 } 344 345 void addFunction(string name, bool simple, T)(T func) if (isCallable!T) { 346 addFunction!(name, ResultMode.Normal, simple)(func); 347 } 348 349 void addFunctions(string[] names, ResultMode mode = ResultMode.Normal, bool simple = false, T...)(T funcs) if (names.length == T.length && ((T.length > 1) || (T.length == 1) && isCallable!T)) { 350 addFunction!(names[0], mode, simple)(funcs[0]); 351 static if (names.length > 1) { 352 addFunctions!(names[1..$], mode, simple)(funcs[1..$]); 353 } 354 } 355 356 void addFunctions(string[] names, bool simple, T...)(T funcs) if (names.length == T.length && ((T.length > 1) || (T.length == 1) && isCallable!T)) { 357 addFunctions!(names, ResultMode.Normal, simple)(funcs); 358 } 359 360 void addMethod(string name, string aliasName = "", ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 361 addFunction!((aliasName == "" ? name : aliasName), mode, simple)(mixin("&obj." ~ name)); 362 } 363 364 void addMethod(string name, ResultMode mode, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 365 addMethod!(name, "", mode, simple)(obj); 366 } 367 368 void addMethod(string name, bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 369 addMethod!(name, "", ResultMode.Normal, simple)(obj); 370 } 371 372 void addMethod(string name, T, string aliasName = "", ResultMode mode = ResultMode.Normal, bool simple = false)() if (is(T == class) && !isCallable!T) { 373 addFunction!((aliasName == "" ? name : aliasName), mode, simple)(mixin("&T." ~ name)); 374 } 375 376 void addMethod(string name, T, ResultMode mode, bool simple = false)() if (is(T == class) && !isCallable!T) { 377 addMethod!(name, T, "", mode, simple)(); 378 } 379 380 void addMethod(string name, T, bool simple)() if (is(T == class) && !isCallable!T) { 381 addMethod!(name, T, "", ResultMode.Normal, simple)(); 382 } 383 384 void addMethods(string[] names, string[] aliasNames = null, ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T && (names.length > 0) && ((names.length == aliasNames.length) || (aliasNames == null))) { 385 static if (aliasNames == null) { 386 addMethod!(names[0], "", mode, simple)(obj); 387 static if (names.length > 1) { 388 addMethods!(names[1..$], null, mode, simple)(obj); 389 } 390 } 391 else { 392 addMethod!(names[0], aliasNames[0], mode, simple)(obj); 393 static if (names.length > 1) { 394 addMethods!(names[1..$], aliasNames[1..$], mode, simple)(obj); 395 } 396 } 397 } 398 399 void addMethods(string[] names, ResultMode mode, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T && (names.length > 0)) { 400 addMethods!(names, null, mode, simple)(obj); 401 } 402 403 void addMethods(string[] names, string[] aliasNames, bool simple, T)(T obj) if (is(T == class) && !isCallable!T && (names.length > 0) && ((names.length == aliasNames.length) || (aliasNames == null))) { 404 addMethods!(names, aliasNames, ResultMode.Normal, simple)(obj); 405 } 406 407 void addMethods(string[] names, bool simple, T)(T obj) if (is(T == class) && !isCallable!T && (names.length > 0)) { 408 addMethods!(names, null, ResultMode.Normal, simple)(obj); 409 } 410 411 void addMethods(U = void, string prefix = "", ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj = null) if ((is(T == class) && (is(U == void) || is(T : U)) && !isCallable!T) || (is(T == typeof(null)) && is(U == class))) { 412 static if (is(U == void)) { 413 alias B = Object; 414 alias C = T; 415 } 416 else { 417 alias B = BaseClassesTuple!U[0]; 418 alias C = U; 419 } 420 static if (is(T == typeof(null))) { 421 foreach (M; __traits(allMembers, C)) { 422 static if (__traits(compiles, mixin("typeof(&U." ~ M ~ ")"))) { 423 static if (!__traits(hasMember, B, M) || !__traits(isSame, __traits(getMember, B, M), __traits(getMember, C, M))) { 424 mixin("alias MT = typeof(&U." ~ M ~ ");"); 425 static if (isCallable!MT) { 426 addFunction!((prefix == "" ? M : prefix ~ '_' ~ M), mode, simple)(mixin("&U." ~ M)); 427 } 428 } 429 } 430 } 431 } 432 else { 433 foreach (M; __traits(allMembers, C)) { 434 static if (__traits(compiles, mixin("typeof(&obj." ~ M ~ ")"))) { 435 static if (!__traits(hasMember, B, M) || !__traits(isSame, __traits(getMember, B, M), __traits(getMember, C, M))) { 436 mixin("alias MT = typeof(&obj." ~ M ~ ");"); 437 static if (isCallable!MT) { 438 addFunction!((prefix == "" ? M : prefix ~ '_' ~ M), mode, simple)(mixin("&obj." ~ M)); 439 } 440 } 441 } 442 } 443 } 444 } 445 446 void addMethods(string prefix, ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 447 addMethods!(void, prefix, mode, simple)(obj); 448 } 449 450 void addMethods(ResultMode mode, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 451 addMethods!(void, "", mode, simple)(obj); 452 } 453 454 void addMethods(string prefix, bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 455 addMethods!(void, prefix, ResultMode.Normal, simple)(obj); 456 } 457 458 void addMethods(bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 459 addMethods!(void, "", ResultMode.Normal, simple)(obj); 460 } 461 462 void addMethods(U, ResultMode mode, bool simple = false)() if (is(U == class) && !isCallable!U) { 463 addMethods!(U, "", mode, simple)(); 464 } 465 466 void addMethods(U, string prefix, bool simple)() if (is(U == class) && !isCallable!T) { 467 addMethods!(U, prefix, ResultMode.Normal, simple)(); 468 } 469 470 void addMethods(U, bool simple)() if (is(U == class) && !isCallable!U) { 471 addMethods!(U, "", ResultMode.Normal, simple)(); 472 } 473 474 void addStaticMethods(U, string prefix = "", ResultMode mode = ResultMode.Normal, bool simple = false)() if (is(U == class) && !isCallable!U) { 475 addMethods!(U, prefix, mode, simple)(); 476 } 477 478 void addStaticMethods(U, ResultMode mode, bool simple = false)() if (is(U == class) && !isCallable!U) { 479 addMethods!(U, "", mode, simple)(); 480 } 481 482 void addStaticMethods(U, string prefix, bool simple)() if (is(U == class) && !isCallable!T) { 483 addMethods!(U, prefix, ResultMode.Normal, simple)(); 484 } 485 486 void addStaticMethods(U, bool simple)() if (is(U == class) && !isCallable!U) { 487 addMethods!(U, "", ResultMode.Normal, simple)(); 488 } 489 490 void addInstanceMethods(U = void, string prefix = "", ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj) if (is(T == class) && (is(U == void) || is(T : U)) && !isCallable!T) { 491 static if (is(U == void)) { 492 alias B = Object; 493 alias C = T; 494 } 495 else { 496 alias B = BaseClassesTuple!U[0]; 497 alias C = U; 498 } 499 foreach (M; __traits(allMembers, C)) { 500 static if (__traits(compiles, mixin("typeof(&obj." ~ M ~ ")"))) { 501 static if (!__traits(hasMember, B, M) || !__traits(isSame, __traits(getMember, B, M), __traits(getMember, C, M))) { 502 mixin("alias MT = typeof(&obj." ~ M ~ ");"); 503 static if (isCallable!MT && !__traits(isStaticFunction, __traits(getMember, C, M))) { 504 addFunction!((prefix == "" ? M : prefix ~ '_' ~ M), mode, simple)(mixin("&obj." ~ M)); 505 } 506 } 507 } 508 } 509 } 510 511 void addInstanceMethods(U, ResultMode mode, bool simple = false, T)(T obj) if (is(T == class) && (is(U == void) || is(T : U)) && !isCallable!T) { 512 addInstanceMethods!(U, "", mode, simple)(obj); 513 } 514 515 void addInstanceMethods(U, string prefix, bool simple, T)(T obj) if (is(T == class) && (is(U == void) || is(T : U)) && !isCallable!T) { 516 addInstanceMethods!(U, prefix, ResultMode.Normal, simple)(obj); 517 } 518 519 void addInstanceMethods(U, bool simple, T)(T obj) if (is(T == class) && (is(U == void) || is(T : U)) && !isCallable!T) { 520 addInstanceMethods!(U, "", ResultMode.Normal, simple)(obj); 521 } 522 523 void addInstanceMethods(ResultMode mode, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 524 addInstanceMethods!(void, "", mode, simple)(obj); 525 } 526 527 void addInstanceMethods(string prefix, bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 528 addInstanceMethods!(void, prefix, ResultMode.Normal, simple)(obj); 529 } 530 531 void addInstanceMethods(bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 532 addInstanceMethods!(void, "", ResultMode.Normal, simple)(obj); 533 } 534 535 void addMissingFunction(ResultMode mode = ResultMode.Normal, bool simple = false, T)(T func) if (isCallable!T && is(ReturnType!T == Variant) && Parameters!T.length >=2 && is(Parameters!T[0] == string) && is(Parameters!T[1] == Variant[])) { 536 addFunction!("*", mode, simple)(func); 537 } 538 539 void addMissingFunction(bool simple, T)(T func) if (isCallable!T && is(ReturnType!T == Variant) && Parameters!T.length >=2 && is(Parameters!T[0] == string) && is(Parameters!T[1] == Variant[])) { 540 addMissingFunction!(ResultMode.Normal, simple)(func); 541 } 542 543 void addMissingMethod(string name, ResultMode mode = ResultMode.Normal, bool simple = false, T)(T obj) if (is(T == class) && !isCallable!T) { 544 addMissingFunction!(mode, simple)(mixin("&obj." ~ name)); 545 } 546 547 void addMissingMethod(string name, bool simple, T)(T obj) if (is(T == class) && !isCallable!T) { 548 addMissingMethod!(name, ResultMode.Normal, simple)(obj); 549 } 550 551 void addMissingMethod(string name, T, ResultMode mode = ResultMode.Normal, bool simple = false)() if (is(T == class) && !isCallable!T) { 552 addMissingFunction!(mode, simple)(mixin("&T." ~ name)); 553 } 554 555 void addMissingMethod(string name, T, bool simple)() if (is(T == class) && !isCallable!T) { 556 addMissingMethod!(name, T, ResultMode.Normal, simple)(); 557 } 558 559 alias addFunction add; 560 alias addFunctions add; 561 alias addMethod add; 562 alias addMethods add; 563 564 void use(InvokeHandler[] handler...) { 565 if (handler !is null) { 566 invokeHandlers ~= handler; 567 } 568 } 569 void use(string when)(FilterHandler[] handler...) if ((when == "beforeFilter") || (when == "afterFilter")) { 570 if (handler !is null) { 571 mixin( 572 when ~ "Handlers ~= handler;\r\n" ~ 573 when ~ "Handler = &" ~ when ~ ";\r\n" ~ 574 "foreach (h; " ~ when ~ "Handlers) {\r\n" ~ 575 " " ~ when ~ "Handler = (delegate(NextFilterHandler next, FilterHandler handler) {\r\n" ~ 576 " return delegate ubyte[](ubyte[] request, Context context) {\r\n" ~ 577 " return handler(request, context, next);\r\n" ~ 578 " };\r\n" ~ 579 " })(" ~ when ~ "Handler, h);\r\n" ~ 580 "}\r\n" 581 ); 582 } 583 } 584 }