From 5fa6c3ecbfb533cdaa325be4b9f65c936d85b129 Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Mon, 10 Jul 2023 22:56:07 +0200 Subject: [PATCH] added RPC macro --- src/bin/HelloWorld.hx | 8 ++++ src/bin/HelloWorldService.hx | 23 +++++------ src/macros/rpc/RPC.hx | 79 ++++++++++++++++++++++++++++++++++++ src/macros/rpc/RPCBase.hx | 29 +++++++++++++ 4 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 src/macros/rpc/RPC.hx create mode 100644 src/macros/rpc/RPCBase.hx diff --git a/src/bin/HelloWorld.hx b/src/bin/HelloWorld.hx index 7a139f2..d68cdb5 100644 --- a/src/bin/HelloWorld.hx +++ b/src/bin/HelloWorld.hx @@ -1,5 +1,6 @@ package bin; +import kernel.log.Log; import kernel.ps.ProcessHandle; import kernel.ps.Process; @@ -11,6 +12,13 @@ class HelloWorld implements Process { public function run(handle:ProcessHandle) { handle.write("Hello World!"); + + var c = new HelloWorldServiceRPC(0); + + c.getNumber().handle((res)->{ + Log.debug("Got number: " + res); + }); + handle.close(); } } diff --git a/src/bin/HelloWorldService.hx b/src/bin/HelloWorldService.hx index 6708f6b..4206bdb 100644 --- a/src/bin/HelloWorldService.hx +++ b/src/bin/HelloWorldService.hx @@ -1,26 +1,25 @@ package bin; -import kernel.Timer; +import macros.rpc.RPC; import kernel.ps.ProcessHandle; import kernel.ps.Process; +using tink.CoreApi; + +@:build(macros.rpc.RPC.buildRPC()) class HelloWorldService implements Process { - private var timer:Timer; + private var handle:ProcessHandle; public function new() {} public function run(handle:ProcessHandle) { - handle.write("Hello World! Started\n"); - this.startTimer(handle); - handle.addDeferFunc(()->{ - timer.cancle(); - }); + this.handle = handle; + + RPC.generateRPCPackageHandle(); } - public function startTimer(handle: ProcessHandle) { - this.timer = new Timer(5, function() { - handle.write("Hello World!\n"); - this.startTimer(handle); - }); + @rpc + public function getNumber():Int{ + return 42; } } \ No newline at end of file diff --git a/src/macros/rpc/RPC.hx b/src/macros/rpc/RPC.hx new file mode 100644 index 0000000..7d4430c --- /dev/null +++ b/src/macros/rpc/RPC.hx @@ -0,0 +1,79 @@ +package macros.rpc; + +import haxe.macro.Context; +import haxe.macro.Expr; +using Lambda; + +class RPC { + macro static public function buildRPC(): Array { + var fields = Context.getBuildFields(); + + var className = Context.getLocalClass().get().name + "RPC"; + + var c = macro class $className extends macros.rpc.RPCBase { + public function new(id: kernel.net.Package.NetworkID) { + super(id,$v{className}); + } + } + + for (field in fields){ + if (field.meta == null) continue; + if (field.meta.exists((i) -> i.name == "rpc") == false) continue; + + switch (field.kind){ + case FFun(f): + c.fields.push({ + name: field.name, + pos: field.pos, + kind: FFun({ + args: f.args, + expr: macro { + return cast this._performRequest($v{field.name},[]); + }, + ret: TPath({name: "Promise", params: [TPType(f.ret)], pack: ["tink","core"]}), + }), + access: [APublic], + doc: null, + meta: [], + }); + default: + Context.error("Only functions can be used for rpc", field.pos); + } + } + + haxe.macro.Context.defineType(c); + + return fields; + } + + macro static public function generateRPCPackageHandle() { + var proto = Context.getLocalClass().get().name + "RPC"; + var exprs: Array = []; + + var fields = Context.getLocalClass().get().fields.get(); + + for (field in fields){ + if (field.meta == null) continue; + if (!field.meta.has("rpc")) continue; + + switch (field.kind){ + case FMethod(k): + var funName = field.name; + exprs.push(macro { + if (pack.data.func == $v{funName}){ + pack.respond(this.$funName()); + } + }); + + default: + Context.error("Only functions can be used for rpc", field.pos); + } + } + + return macro { + kernel.net.Net.instance.registerProto($v{proto},(pack)->{ + $a{exprs} + }); + }; + } +} diff --git a/src/macros/rpc/RPCBase.hx b/src/macros/rpc/RPCBase.hx new file mode 100644 index 0000000..c4d4a14 --- /dev/null +++ b/src/macros/rpc/RPCBase.hx @@ -0,0 +1,29 @@ +package macros.rpc; + +import kernel.net.Net; +import kernel.net.Package.NetworkID; + +using tink.CoreApi; + +abstract class RPCBase { + public final id:NetworkID; + private final _proto:String; + public function new(id: NetworkID, proto: String) { + this.id = id; + this._proto = proto; + } + + private function _performRequest(func: String, args: Array):Promise { + return Net.instance.sendAndAwait(id, this._proto, { + func: func, + // args: args + }).map((res) -> { + switch (res){ + case Success(pack): + return pack.data; + case Failure(_): + return res; + } + }); + } +}