Compare commits
4 Commits
1d9e08641e
...
e3875f76f6
| Author | SHA1 | Date | |
|---|---|---|---|
|
e3875f76f6
|
|||
|
fdcb81b565
|
|||
|
72654b1036
|
|||
|
fe85c33d64
|
6
Makefile
6
Makefile
@@ -58,4 +58,8 @@ webconsole:
|
|||||||
|
|
||||||
.PHONY: format
|
.PHONY: format
|
||||||
format:
|
format:
|
||||||
haxelib run formatter -s src
|
haxelib run formatter -s src
|
||||||
|
|
||||||
|
.PHONY: format-deps
|
||||||
|
format-deps:
|
||||||
|
haxelib install formatter
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Hello world", ["hello"]))
|
|
||||||
class HelloWorld implements Process {
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
handle.write("Hello World!");
|
|
||||||
|
|
||||||
handle.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import lib.ui.elements.TextElement;
|
|
||||||
import lib.Pos;
|
|
||||||
import lib.ui.elements.UIElement;
|
|
||||||
import lib.ui.elements.LayerdRootElement;
|
|
||||||
import kernel.ui.WindowContext;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("HelloWorld-GUI", ["hello-gui"]))
|
|
||||||
class HelloWorldGUI implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
private var ctx:WindowContext;
|
|
||||||
private var requestRender:Void->Void;
|
|
||||||
private var root:LayerdRootElement;
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
|
|
||||||
var stateless = handle.createStatelessWindowContext();
|
|
||||||
this.ctx = stateless.ctx;
|
|
||||||
this.requestRender = stateless.requestRender;
|
|
||||||
|
|
||||||
stateless.setRenderFunc(this.render);
|
|
||||||
|
|
||||||
this.root = new LayerdRootElement();
|
|
||||||
|
|
||||||
this.ctx.delegateEvents(this.root);
|
|
||||||
|
|
||||||
this.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function render() {
|
|
||||||
var children:Array<{element:UIElement, offset:Pos}> = [
|
|
||||||
{
|
|
||||||
element: new TextElement("Hello World", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Hello World");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 0, y: 0})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: new TextElement("Holla Mundo", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Holla Mundo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 0, y: 1})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: new TextElement("Ayyy", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Ayy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 4, y: 1})
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
this.root.setChildren(children);
|
|
||||||
this.root.render(ctx.getSize()).renderToContext(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
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 handle:ProcessHandle;
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
|
|
||||||
RPC.generateRPCPackageHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function getNumber(arg1:Int, arg2:Int):Int {
|
|
||||||
Log.debug(arg1);
|
|
||||||
Log.debug(arg2);
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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,58 +0,0 @@
|
|||||||
package bin.exporter;
|
|
||||||
|
|
||||||
import lib.exporter.Export;
|
|
||||||
import lib.exporter.IExportable;
|
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
|
||||||
import kernel.service.ServiceManager;
|
|
||||||
import lib.exporter.Import;
|
|
||||||
import lib.CLIAppBase;
|
|
||||||
|
|
||||||
class Res extends CLIAppBase {
|
|
||||||
public function new() {
|
|
||||||
registerAsyncSubcommand("get", (args) -> {
|
|
||||||
var url = args[0];
|
|
||||||
|
|
||||||
return Import.get(url).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(data):
|
|
||||||
handle.writeLine(Std.string(data));
|
|
||||||
case Failure(err):
|
|
||||||
handle.writeLine("Error: ");
|
|
||||||
handle.writeLine(Std.string(err));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, "<url>");
|
|
||||||
|
|
||||||
registerAsyncSubcommand("register", (args) -> {
|
|
||||||
var srv:Null<ResManager> = ServiceManager.get("resmgr");
|
|
||||||
|
|
||||||
var addr = args[0];
|
|
||||||
var name = args[1];
|
|
||||||
|
|
||||||
if (srv == null) {
|
|
||||||
handle.writeLine("Error: resmgr not found");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var perf:kernel.peripherals.Redstone = Peripheral.getRedstone(addr);
|
|
||||||
|
|
||||||
if (perf == null) {
|
|
||||||
handle.writeLine("Error: peripheral not found");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return srv.register(name, new Export(perf)).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(_):
|
|
||||||
handle.writeLine("Success");
|
|
||||||
return true;
|
|
||||||
case Failure(err):
|
|
||||||
handle.writeLine("Error: ");
|
|
||||||
handle.writeLine(Std.string(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, "<addr> <name>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package bin.exporter;
|
|
||||||
|
|
||||||
import kernel.KernelSettings;
|
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
|
||||||
import lib.KVStore;
|
|
||||||
import lib.exporter.Request;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import lib.exporter.Export;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
import kernel.net.Package;
|
|
||||||
import kernel.net.Net;
|
|
||||||
import kernel.net.Package.GenericPackage;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
class ResManager implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
private var exports:Map<String, Export> = [];
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
Net.registerProto("res", handlePackage);
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function register(id:String, export:Export):Promise<Noise> {
|
|
||||||
if (exports.exists(id)) {
|
|
||||||
return Promise.reject(new Error("Ressource already exists: " + id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return registerName(id).next((success) -> {
|
|
||||||
exports.set(id, export);
|
|
||||||
persist();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handlePackage(pack:GenericPackage) {
|
|
||||||
var requestPack:Package<Request> = cast pack;
|
|
||||||
var id = requestPack.data.id;
|
|
||||||
|
|
||||||
if (!exports.exists(id)) {
|
|
||||||
requestPack.respond(lib.exporter.Response.NotFound);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var export = exports.get(id);
|
|
||||||
var response = export.handleRequest(requestPack.data);
|
|
||||||
|
|
||||||
requestPack.respond(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function registerName(id:String) {
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
return rpc.register(id, Net.networkID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function persist() {
|
|
||||||
var store = new KVStore("export");
|
|
||||||
|
|
||||||
var saveExports:Array<{name:String, addr:String, type:String}> = [for (k => v in this.exports) {name: k, addr: v.getAddr(), type: v.getType()}];
|
|
||||||
|
|
||||||
store.set("exports", saveExports);
|
|
||||||
|
|
||||||
store.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function load() {
|
|
||||||
var store = new KVStore("export");
|
|
||||||
|
|
||||||
var savedExports:Array<{name:String, addr:String, type:String}> = store.get("exports", []);
|
|
||||||
|
|
||||||
for (export in savedExports) {
|
|
||||||
var perph = Peripheral.getFromType(export.addr, export.type);
|
|
||||||
|
|
||||||
if (perph == null) {
|
|
||||||
handle.writeLine('Could not load export: ${export.name} on ${export.addr}');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I dont know if cast is the best way to do this
|
|
||||||
// But since we know that this is a IExportable we can do this (I think)
|
|
||||||
exports.set(export.name, new Export(cast perph));
|
|
||||||
|
|
||||||
handle.writeLine('Loaded export: ${export.name} on ${export.addr}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import lib.exporter.ExportConfig;
|
class EnergyStorage implements IPeripheral {
|
||||||
import lib.exporter.IExportable;
|
|
||||||
|
|
||||||
class EnergyStorage implements IPeripheral implements IExportable {
|
|
||||||
public static inline final TYPE_NAME:String = "energyCell";
|
public static inline final TYPE_NAME:String = "energyCell";
|
||||||
|
|
||||||
private final addr:String;
|
private final addr:String;
|
||||||
@@ -29,13 +26,4 @@ class EnergyStorage implements IPeripheral implements IExportable {
|
|||||||
public function getType():String {
|
public function getType():String {
|
||||||
return TYPE_NAME;
|
return TYPE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function export():ExportConfig {
|
|
||||||
return {
|
|
||||||
getDelegates: [
|
|
||||||
"energy" => _ -> Number(this.getEnergy()),
|
|
||||||
"capacity" => _ -> Number(this.getEnergyCapacity()),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import lib.exporter.ExportConfig;
|
|
||||||
import lib.exporter.IExportable;
|
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
|
|
||||||
@@ -43,8 +41,7 @@ abstract BundleMask(Int) from cc.Colors.Color to cc.Colors.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:build(macros.Exporter.buildExport())
|
class Redstone implements IPeripheral {
|
||||||
class Redstone implements IPeripheral implements IExportable {
|
|
||||||
public static inline final TYPE_NAME:String = "redstone"; // TODO: there is technically not a type for redstone.
|
public static inline final TYPE_NAME:String = "redstone"; // TODO: there is technically not a type for redstone.
|
||||||
|
|
||||||
public final onChange:Signal<Noise>;
|
public final onChange:Signal<Noise>;
|
||||||
@@ -89,12 +86,10 @@ class Redstone implements IPeripheral implements IExportable {
|
|||||||
cc.Redstone.setOutput(this.addr, on);
|
cc.Redstone.setOutput(this.addr, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
@export("output")
|
|
||||||
public inline function getOutput():Bool {
|
public inline function getOutput():Bool {
|
||||||
return cc.Redstone.getOutput(this.addr);
|
return cc.Redstone.getOutput(this.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@export("input")
|
|
||||||
public inline function getInput():Bool {
|
public inline function getInput():Bool {
|
||||||
return cc.Redstone.getInput(this.addr);
|
return cc.Redstone.getInput(this.addr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
import kernel.peripherals.IPeripheral;
|
|
||||||
import kernel.log.Log;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
class Export {
|
|
||||||
private final exportConfig:ExportConfig;
|
|
||||||
private final peripheral:IPeripheral;
|
|
||||||
|
|
||||||
public function new<T:IExportable & IPeripheral>(exportPerph:T) {
|
|
||||||
this.peripheral = exportPerph;
|
|
||||||
this.exportConfig = exportPerph.export();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleRequest(req:Request):Response {
|
|
||||||
switch (req.operation) {
|
|
||||||
case Get:
|
|
||||||
return handleGet(req);
|
|
||||||
case Set(value):
|
|
||||||
// TODO: implement
|
|
||||||
return NotFound;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleGet(request:Request):Response {
|
|
||||||
if (!this.exportConfig.getDelegates.exists(request.field)) {
|
|
||||||
Log.warn('Requested get field ${request.field} does not exist in ??');
|
|
||||||
return NotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
var delegate = this.exportConfig.getDelegates.get(request.field);
|
|
||||||
var value = delegate(request.index);
|
|
||||||
|
|
||||||
return Get(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getType():String {
|
|
||||||
return this.peripheral.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAddr():String {
|
|
||||||
return this.peripheral.getAddr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
import lib.exporter.Response;
|
|
||||||
|
|
||||||
typedef ExportConfig = {
|
|
||||||
getDelegates:Map<String, Null<Int>->ValueType>,
|
|
||||||
// setDelegates: Map<String, (ValueType, Null<Int>)->ValueType>,
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
interface IExportable {
|
|
||||||
public function export():ExportConfig;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
import kernel.KernelSettings;
|
|
||||||
import kernel.net.Net;
|
|
||||||
import kernel.net.Package.NetworkID;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
class Import {
|
|
||||||
public static function get(ressourceLocator:String):Promise<Response> {
|
|
||||||
var request = Request.fromString(ressourceLocator);
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
|
|
||||||
return rpc.get(request.id).next((response) -> {
|
|
||||||
return performRequest(response, request);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function performRequest(netID:NetworkID, request:Request):Promise<Response> {
|
|
||||||
return Net.sendAndAwait(netID, "res", request).map((response) -> {
|
|
||||||
switch (response) {
|
|
||||||
case Success(data):
|
|
||||||
return Success(cast(data.data, Response));
|
|
||||||
case Failure(error):
|
|
||||||
return Failure(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
enum Operation {
|
|
||||||
Get;
|
|
||||||
Set(value:Dynamic);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
import lua.TableTools;
|
|
||||||
import lua.NativeStringTools;
|
|
||||||
|
|
||||||
class Request {
|
|
||||||
public final id:String;
|
|
||||||
public final field:String;
|
|
||||||
public final index:Null<Int>;
|
|
||||||
public final operation:Operation;
|
|
||||||
|
|
||||||
public function new(id:String, field:String, index:Null<Int>, operation:Operation) {
|
|
||||||
this.id = id;
|
|
||||||
this.field = field;
|
|
||||||
this.index = index;
|
|
||||||
this.operation = operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Example:
|
|
||||||
"myfield[2]@myid"
|
|
||||||
"myfield@myid"
|
|
||||||
**/
|
|
||||||
public static function fromString(locator:String):Request {
|
|
||||||
if (StringTools.contains(locator, "[")) {
|
|
||||||
var f = TableTools.pack(NativeStringTools.gmatch(locator, "(%a+)%[([%d]+)%]@(%a+)")());
|
|
||||||
|
|
||||||
var field = f[1];
|
|
||||||
var index = Std.parseInt(f[2]);
|
|
||||||
var id = f[3];
|
|
||||||
|
|
||||||
return new Request(id, field, index, Get);
|
|
||||||
} else {
|
|
||||||
var f = TableTools.pack(NativeStringTools.gmatch(locator, "(%a+)@(%a+)")());
|
|
||||||
|
|
||||||
var field = f[1];
|
|
||||||
var id = f[2];
|
|
||||||
|
|
||||||
return new Request(id, field, null, Get);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString() {
|
|
||||||
if (index == null) {
|
|
||||||
return field + "@" + id;
|
|
||||||
} else {
|
|
||||||
return field + "[" + index + "]@" + id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package lib.exporter;
|
|
||||||
|
|
||||||
enum Response {
|
|
||||||
NotFound;
|
|
||||||
Set;
|
|
||||||
NotSet;
|
|
||||||
Get(value:ValueType);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ValueType {
|
|
||||||
Number(value:Int);
|
|
||||||
String(value:String);
|
|
||||||
Bool(value:Bool);
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package macros;
|
|
||||||
|
|
||||||
import haxe.macro.Context;
|
|
||||||
import haxe.macro.Expr;
|
|
||||||
|
|
||||||
using Lambda;
|
|
||||||
|
|
||||||
class Exporter {
|
|
||||||
macro public static function buildExport():Array<haxe.macro.Expr.Field> {
|
|
||||||
var fields = Context.getBuildFields();
|
|
||||||
|
|
||||||
var getExp = [];
|
|
||||||
|
|
||||||
for (field in fields) {
|
|
||||||
if (field.meta == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var s = "";
|
|
||||||
for (meta in field.meta) {
|
|
||||||
if (meta.name == "export") {
|
|
||||||
switch (meta.params[0].expr) {
|
|
||||||
case EConst(CString(s1)):
|
|
||||||
s = s1;
|
|
||||||
default:
|
|
||||||
Context.error("Invalid export name", meta.pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s == "")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (field.kind) {
|
|
||||||
case FFun(f):
|
|
||||||
var funName = field.name;
|
|
||||||
switch (f.ret) {
|
|
||||||
case TPath(p):
|
|
||||||
switch (p.name) {
|
|
||||||
case "Int":
|
|
||||||
getExp.push(macro $v{s} => (i:Int) -> lib.exporter.Response.ValueType.Int(this.$funName()));
|
|
||||||
case "Float":
|
|
||||||
getExp.push(macro $v{s} => (i:Int) -> lib.exporter.Response.ValueType.Float(this.$funName()));
|
|
||||||
case "Bool":
|
|
||||||
getExp.push(macro $v{s} => (i:Int) -> lib.exporter.Response.ValueType.Bool(this.$funName()));
|
|
||||||
case "String":
|
|
||||||
getExp.push(macro $v{s} => (i:Int) -> lib.exporter.Response.ValueType.String(this.$funName()));
|
|
||||||
default:
|
|
||||||
Context.error("Only Int, Float, Bool and String can be exported", field.pos);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Context.error("Only functions returning a type can be exported", field.pos);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Context.error("Only functions can be exported", field.pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var exportField:Field = {
|
|
||||||
name: "export",
|
|
||||||
pos: Context.currentPos(),
|
|
||||||
kind: FFun({
|
|
||||||
args: [],
|
|
||||||
ret: TPath({name: "ExportConfig", pack: []}),
|
|
||||||
expr: macro {
|
|
||||||
return {
|
|
||||||
getDelegates: $a{getExp},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
access: [APublic],
|
|
||||||
doc: null,
|
|
||||||
meta: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
fields.push(exportField);
|
|
||||||
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +1,136 @@
|
|||||||
package macros.rpc;
|
package macros.rpc;
|
||||||
|
|
||||||
import haxe.macro.ComplexTypeTools;
|
|
||||||
import haxe.macro.TypeTools;
|
import haxe.macro.TypeTools;
|
||||||
import haxe.macro.Context;
|
import haxe.macro.Context;
|
||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
|
|
||||||
using Lambda;
|
|
||||||
|
|
||||||
class RPC {
|
class RPC {
|
||||||
macro static public function buildRPC():Array<Field> {
|
macro static public function buildRPC(iface:Expr):Array<Field> {
|
||||||
var fields = Context.getBuildFields();
|
var buildFields = Context.getBuildFields();
|
||||||
|
var localClass = Context.getLocalClass().get();
|
||||||
|
var handleExprs:Array<Expr> = [];
|
||||||
|
|
||||||
var className = Context.getLocalClass().get().name + "RPC";
|
var ifaceType = null;
|
||||||
|
|
||||||
var c = macro class $className extends macros.rpc.RPCBase {
|
switch (iface.expr) {
|
||||||
public function new(id:kernel.net.Package.NetworkID) {
|
case EConst(CIdent(i)):
|
||||||
super(id, $v{className});
|
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<Expr> = [for (a in args) macro $i{a.name}];
|
||||||
|
|
||||||
for (field in fields) {
|
var convertedArgs:Array<FunctionArg> = [];
|
||||||
if (field.meta == null)
|
for (a in args) {
|
||||||
continue;
|
convertedArgs.push({
|
||||||
if (field.meta.exists((i) -> i.name == "rpc") == false)
|
name: a.name,
|
||||||
continue;
|
opt: a.opt,
|
||||||
|
type: TypeTools.toComplexType(a.t)
|
||||||
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 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<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 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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
var retComplexType = TypeTools.toComplexType(ret);
|
||||||
exprs.push(macro {
|
var retType:ComplexType = if (Helper.isPromise(ret)) {
|
||||||
if (pack.data.func == $v{funName}) {
|
TypeTools.toComplexType(Helper.getPromiseType(retComplexType));
|
||||||
pack.respond(this.$funName($a{callArgs}));
|
} 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 Interfaces are supported", iface.pos);
|
||||||
default:
|
}
|
||||||
Context.error("Only functions can be used for rpc", field.pos);
|
|
||||||
}
|
default:
|
||||||
|
Context.error("Only Interfaces are supported", iface.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return macro {
|
// Add handle package static method
|
||||||
kernel.net.Net.registerProto($v{proto}, (pack) -> {
|
buildFields.push({
|
||||||
$a{exprs}
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user