From fe85c33d64b3e8a86418159c8be3ce9fd510d05d Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Tue, 12 Mar 2024 21:44:08 +0100 Subject: [PATCH] remade RPC system --- src/bin/debug/Debug.hx | 41 ++++++ src/bin/debug/DebugRPC.hx | 10 ++ src/bin/debug/DebugService.hx | 27 ++++ src/macros/rpc/RPC.hx | 229 ++++++++++++++++++---------------- 4 files changed, 196 insertions(+), 111 deletions(-) create mode 100644 src/bin/debug/Debug.hx create mode 100644 src/bin/debug/DebugRPC.hx create mode 100644 src/bin/debug/DebugService.hx diff --git a/src/bin/debug/Debug.hx b/src/bin/debug/Debug.hx new file mode 100644 index 0000000..e14d559 --- /dev/null +++ b/src/bin/debug/Debug.hx @@ -0,0 +1,41 @@ +package bin.debug; + +import kernel.log.Log; +import lib.turtle.InvManager; +import kernel.ps.ProcessHandle; +import kernel.ps.Process; + +/** + Use this to test whatever you are working on. It will also print debug statements. + IDK if you commit changes in this file. It will not be included in non debug build. +**/ +#if debug +@:build(macros.Binstore.includeBin("Debug", ["dbg", "debug"])) +#end +class Debug implements Process { + public function new() {} + + public function run(handle:ProcessHandle) { + var link = Log.onLog.handle((line) -> { + handle.writeLine('[${line.level}] ${line.message}'); + }); + + handle.addDeferFunc(() -> { + link.cancel(); + }); + + // Add your stuff here + // ----- + + var rpc = new bin.debug.DebugRPC.DebugRPCImpl(1, "debug"); + + var a = rpc.addNumber(1, 2); + + // rpc.addNumber(1,2).handle((e)->{ + // Log.debug(e); + // handle.close(); + // }); + + // ----- + } +} diff --git a/src/bin/debug/DebugRPC.hx b/src/bin/debug/DebugRPC.hx new file mode 100644 index 0000000..298228d --- /dev/null +++ b/src/bin/debug/DebugRPC.hx @@ -0,0 +1,10 @@ +package bin.debug; + +import macros.rpc.RPCBase; + +interface DebugRPC { + function addNumber(a:Int, b:Int):Int; +} + +@:build(macros.rpc.RPC.buildRPC(DebugRPC)) +class DebugRPCImpl extends RPCBase {} diff --git a/src/bin/debug/DebugService.hx b/src/bin/debug/DebugService.hx new file mode 100644 index 0000000..b2bdddf --- /dev/null +++ b/src/bin/debug/DebugService.hx @@ -0,0 +1,27 @@ +package bin.debug; + +import bin.debug.DebugRPC.DebugRPCImpl; +import macros.rpc.RPC; +import kernel.ps.ProcessHandle; +import kernel.ps.Process; + +#if debug +@:build(macros.Binstore.includeBin("Debug SRV", ["dbg-srv", "debug-srv"])) +#end +class DebugService implements Process implements DebugRPC { + private var handle:ProcessHandle; + + public function new() {} + + public function run(handle:ProcessHandle) { + this.handle = handle; + + kernel.net.Net.registerProto("debug", (pack) -> { + DebugRPCImpl.handlePackage(this, pack); + }); + } + + public function addNumber(a:Int, b:Int):Int { + return a + b; + } +} diff --git a/src/macros/rpc/RPC.hx b/src/macros/rpc/RPC.hx index 320e991..538a2af 100644 --- a/src/macros/rpc/RPC.hx +++ b/src/macros/rpc/RPC.hx @@ -1,129 +1,136 @@ package macros.rpc; -import haxe.macro.ComplexTypeTools; import haxe.macro.TypeTools; import haxe.macro.Context; import haxe.macro.Expr; -using Lambda; - class RPC { - macro static public function buildRPC():Array { - var fields = Context.getBuildFields(); + macro static public function buildRPC(iface:Expr):Array { + var buildFields = Context.getBuildFields(); + var localClass = Context.getLocalClass().get(); + var handleExprs:Array = []; - var className = Context.getLocalClass().get().name + "RPC"; + var ifaceType = null; - var c = macro class $className extends macros.rpc.RPCBase { - public function new(id:kernel.net.Package.NetworkID) { - super(id, $v{className}); - } - } + switch (iface.expr) { + case EConst(CIdent(i)): + var t = Context.getType(i); + ifaceType = TypeTools.toComplexType(t); + switch (t) { + case TInst(t2, params): + var fields = t2.get().fields.get(); + for (field in fields) { + switch (field.type) { + case TFun(args, ret): + var argsExprs:Array = [for (a in args) macro $i{a.name}]; - 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): - var argsExprs:Array = [for (a in f.args) macro $i{a.name}]; - - var convertedArgs = []; - for (a in f.args) { - a.type = Helper.resolveType(a.type, field.pos); - convertedArgs.push(a); - } - - var rtn = if (Helper.isPromise(ComplexTypeTools.toType(f.ret))) { - TypeTools.toComplexType(Helper.getPromiseType(f.ret)); - } else { - Helper.resolveType(f.ret, field.pos); - } - - c.fields.push({ - name: field.name, - pos: field.pos, - kind: FFun({ - args: convertedArgs, - expr: macro { - return cast this._performRequest($v{field.name}, $a{argsExprs}); - }, - ret: Helper.newPromise(rtn), - }), - 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() { - #if display - return macro {}; - #end - - 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; - - var exprsType = field.expr().t; - - switch (exprsType) { - case TFun(args, ret): - var callArgs = [for (k => v in args) macro pack.data.args[$v{k}]]; - - if (Helper.isVoid(ret)) { - exprs.push(macro { - if (pack.data.func == $v{funName}) { - this.$funName($a{callArgs}); - pack.respond(null); - } - }); - } else if (Helper.isPromise(ret)) { - exprs.push(macro { - if (pack.data.func == $v{funName}) { - this.$funName($a{callArgs}).handle((r) -> { - pack.respond(r); + var convertedArgs:Array = []; + for (a in args) { + convertedArgs.push({ + name: a.name, + opt: a.opt, + type: TypeTools.toComplexType(a.t) }); } - }); - } else { - exprs.push(macro { - if (pack.data.func == $v{funName}) { - pack.respond(this.$funName($a{callArgs})); + + var retComplexType = TypeTools.toComplexType(ret); + var retType:ComplexType = if (Helper.isPromise(ret)) { + TypeTools.toComplexType(Helper.getPromiseType(retComplexType)); + } else { + retComplexType; } - }); + + buildFields.push({ + name: field.name, + pos: localClass.pos, + access: [APublic, AInline], + kind: FFun({ + args: convertedArgs, + expr: macro { + return cast this._performRequest($v{field.name}, $a{argsExprs}); + }, + ret: Helper.newPromise(retType), + }), + }); + + // Add expr for package handle + // TODO: this needs to be more efficient. Maybe use a switch case. + + var callArgs = [for (k => v in args) macro p.data.args[$v{k}]]; + var funName = field.name; + + if (Helper.isVoid(ret)) { + handleExprs.push(macro { + if (p.data.func == $v{funName}) { + d.$funName($a{callArgs}); + p.respond(null); + return true; + } + + true; + }); + } else if (Helper.isPromise(ret)) { + handleExprs.push(macro { + if (p.data.func == $v{funName}) { + d.$funName($a{callArgs}).handle((r) -> { + p.respond(r); + return true; + }); + } + + true; + }); + } else { + handleExprs.push(macro { + if (p.data.func == $v{funName}) { + p.respond(d.$funName($a{callArgs})); + return true; + } + + // HACK: I not a 100% sure why this need to be here but it does not work without it. + // My guess is that a macro has to be able to be evaluated to a value and a simple if + // statement is of type Void. I don't think this last true statement will have an impact + // on the resulting Expr. + true; + }); + } + + default: + Context.warning("IDFK man", field.pos); } - default: - Context.error("Only functions can be used for rpc", field.pos); - } - default: - Context.error("Only functions can be used for rpc", field.pos); - } + } + default: + Context.error("Only Interfaces are supported", iface.pos); + } + + default: + Context.error("Only Interfaces are supported", iface.pos); } - return macro { - kernel.net.Net.registerProto($v{proto}, (pack) -> { - $a{exprs} - }); - }; + // Add handle package static method + buildFields.push({ + name: "handlePackage", + access: [APublic, AStatic], + pos: localClass.pos, + kind: FFun({ + args: [ + { + name: "d", + type: ifaceType, + opt: false, + }, + { + name: "p", + type: macro :kernel.net.Package.GenericPackage, + opt: false, + }, + ], + expr: macro { + $a{handleExprs} return false; + } + }) + }); + + return buildFields; } }