remade RPC system
This commit is contained in:
parent
1d9e08641e
commit
fe85c33d64
41
src/bin/debug/Debug.hx
Normal file
41
src/bin/debug/Debug.hx
Normal file
@ -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();
|
||||
// });
|
||||
|
||||
// -----
|
||||
}
|
||||
}
|
10
src/bin/debug/DebugRPC.hx
Normal file
10
src/bin/debug/DebugRPC.hx
Normal file
@ -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 {}
|
27
src/bin/debug/DebugService.hx
Normal file
27
src/bin/debug/DebugService.hx
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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<Field> {
|
||||
var fields = Context.getBuildFields();
|
||||
macro static public function buildRPC(iface:Expr):Array<Field> {
|
||||
var buildFields = Context.getBuildFields();
|
||||
var localClass = Context.getLocalClass().get();
|
||||
var handleExprs:Array<Expr> = [];
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
var ifaceType = null;
|
||||
|
||||
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) {
|
||||
if (field.meta == null)
|
||||
continue;
|
||||
if (field.meta.exists((i) -> i.name == "rpc") == false)
|
||||
continue;
|
||||
switch (field.type) {
|
||||
case TFun(args, ret):
|
||||
var argsExprs:Array<Expr> = [for (a in args) macro $i{a.name}];
|
||||
|
||||
switch (field.kind) {
|
||||
case FFun(f):
|
||||
var argsExprs:Array<Expr> = [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 convertedArgs:Array<FunctionArg> = [];
|
||||
for (a in args) {
|
||||
convertedArgs.push({
|
||||
name: a.name,
|
||||
opt: a.opt,
|
||||
type: TypeTools.toComplexType(a.t)
|
||||
});
|
||||
}
|
||||
|
||||
var rtn = if (Helper.isPromise(ComplexTypeTools.toType(f.ret))) {
|
||||
TypeTools.toComplexType(Helper.getPromiseType(f.ret));
|
||||
var retComplexType = TypeTools.toComplexType(ret);
|
||||
var retType:ComplexType = if (Helper.isPromise(ret)) {
|
||||
TypeTools.toComplexType(Helper.getPromiseType(retComplexType));
|
||||
} else {
|
||||
Helper.resolveType(f.ret, field.pos);
|
||||
retComplexType;
|
||||
}
|
||||
|
||||
c.fields.push({
|
||||
buildFields.push({
|
||||
name: field.name,
|
||||
pos: field.pos,
|
||||
pos: localClass.pos,
|
||||
access: [APublic, AInline],
|
||||
kind: FFun({
|
||||
args: convertedArgs,
|
||||
expr: macro {
|
||||
return cast this._performRequest($v{field.name}, $a{argsExprs});
|
||||
},
|
||||
ret: Helper.newPromise(rtn),
|
||||
ret: Helper.newPromise(retType),
|
||||
}),
|
||||
access: [APublic],
|
||||
doc: null,
|
||||
meta: [],
|
||||
});
|
||||
default:
|
||||
Context.error("Only functions can be used for rpc", field.pos);
|
||||
}
|
||||
}
|
||||
|
||||
haxe.macro.Context.defineType(c);
|
||||
return fields;
|
||||
}
|
||||
// Add expr for package handle
|
||||
// TODO: this needs to be more efficient. Maybe use a switch case.
|
||||
|
||||
macro static public function generateRPCPackageHandle() {
|
||||
#if display
|
||||
return macro {};
|
||||
#end
|
||||
|
||||
var proto = Context.getLocalClass().get().name + "RPC";
|
||||
var exprs:Array<Expr> = [];
|
||||
|
||||
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 callArgs = [for (k => v in args) macro p.data.args[$v{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);
|
||||
handleExprs.push(macro {
|
||||
if (p.data.func == $v{funName}) {
|
||||
d.$funName($a{callArgs});
|
||||
p.respond(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
true;
|
||||
});
|
||||
} else if (Helper.isPromise(ret)) {
|
||||
exprs.push(macro {
|
||||
if (pack.data.func == $v{funName}) {
|
||||
this.$funName($a{callArgs}).handle((r) -> {
|
||||
pack.respond(r);
|
||||
handleExprs.push(macro {
|
||||
if (p.data.func == $v{funName}) {
|
||||
d.$funName($a{callArgs}).handle((r) -> {
|
||||
p.respond(r);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
exprs.push(macro {
|
||||
if (pack.data.func == $v{funName}) {
|
||||
pack.respond(this.$funName($a{callArgs}));
|
||||
}
|
||||
});
|
||||
}
|
||||
default:
|
||||
Context.error("Only functions can be used for rpc", field.pos);
|
||||
}
|
||||
default:
|
||||
Context.error("Only functions can be used for rpc", field.pos);
|
||||
}
|
||||
}
|
||||
|
||||
return macro {
|
||||
kernel.net.Net.registerProto($v{proto}, (pack) -> {
|
||||
$a{exprs}
|
||||
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 Interfaces are supported", iface.pos);
|
||||
}
|
||||
|
||||
default:
|
||||
Context.error("Only Interfaces are supported", iface.pos);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user