Compare commits

..

4 Commits

Author SHA1 Message Date
909aac941c added export to Redstone 2023-06-25 19:06:48 +02:00
e686afb298 implmented basic ressource exporting 2023-06-25 19:05:57 +02:00
7996dd062d changed synaopsis to srv 2023-06-25 19:02:45 +02:00
9d6979c8e8 added a type to Package and added GenericPackage
This forces you to use cast to if you want to force the package to have
a specific type
2023-06-07 23:42:23 +02:00
21 changed files with 336 additions and 42 deletions

56
src/bin/Res.hx Normal file
View File

@@ -0,0 +1,56 @@
package bin;
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.instance.get("resmgr");
var addr = args[0];
var name = args[1];
if (srv == null) {
handle.writeLine("Error: resmgr not found");
return false;
}
var perf: IExportable = Peripheral.instance.getRedstone(addr);
if (perf == null) {
handle.writeLine("Error: peripheral not found");
return false;
}
return srv.register(name,new Export(perf)).map((res)->{
if (res) {
handle.writeLine("Success");
} else {
handle.writeLine("Error");
}
return res;
});
},"<addr> <name>");
}
}

67
src/bin/ResManager.hx Normal file
View File

@@ -0,0 +1,67 @@
package bin;
import lib.exporter.Request;
import kernel.ps.ProcessHandle;
import lib.RessourceNames;
import lib.exporter.Export;
import kernel.ps.Process;
import kernel.log.Log;
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 final exports:Map<String,Export> = [];
public function new() {}
public function run(handle:ProcessHandle) {
this.handle = handle;
Net.instance.registerProto("res",handlePackage);
}
public function register(id: String, export: Export): Future<Bool>{
if (exports.exists(id)){
handle.writeLine("Ressource already exists: " + id);
return Future.sync(false);
}
return registerName(id).map((success)->{
if (success){
exports.set(id,export);
}
return success;
});
}
private function handlePackage(pack: GenericPackage){
Log.debug("Handling ressource request" + pack);
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){
return RessourceNames.register(id, Net.instance.networkID).map((res)->{
switch (res) {
case Success(data):
return data;
case Failure(err):
Log.error("Failed to register ressource: " + id + " " + err);
return false;
}
});
}
}

View File

@@ -16,7 +16,7 @@ class Service extends CLIAppBase {
var result = ServiceManager.instance.start(name); var result = ServiceManager.instance.start(name);
return handleResult(result); return handleResult(result);
},"Start a service"); },"<name>");
registerSyncSubcommand("stop", (args) ->{ registerSyncSubcommand("stop", (args) ->{
if (args.length < 1) { if (args.length < 1) {
@@ -27,7 +27,7 @@ class Service extends CLIAppBase {
var result = ServiceManager.instance.stop(name); var result = ServiceManager.instance.stop(name);
return handleResult(result); return handleResult(result);
},"Stop a service"); },"<name>");
registerSyncSubcommand("register", (args) ->{ registerSyncSubcommand("register", (args) ->{
if (args.length < 2) { if (args.length < 2) {
@@ -40,7 +40,7 @@ class Service extends CLIAppBase {
var result = ServiceManager.instance.register(name, binName, rest); var result = ServiceManager.instance.register(name, binName, rest);
return handleResult(result); return handleResult(result);
},"Register a new service"); },"<name> <binary> <args...>");
registerSyncSubcommand("unregister", (args) ->{ registerSyncSubcommand("unregister", (args) ->{
if (args.length < 2) { if (args.length < 2) {
@@ -51,7 +51,7 @@ class Service extends CLIAppBase {
var result = ServiceManager.instance.unregister(name); var result = ServiceManager.instance.unregister(name);
return handleResult(result); return handleResult(result);
},"Unregister a service"); },"<name>");
registerSyncSubcommand("list", (args) ->{ registerSyncSubcommand("list", (args) ->{
@@ -62,7 +62,7 @@ class Service extends CLIAppBase {
} }
return true; return true;
},"List all services"); });
registerSyncSubcommand("enable", (args) ->{ registerSyncSubcommand("enable", (args) ->{
if (args.length < 1) { if (args.length < 1) {
@@ -71,7 +71,7 @@ class Service extends CLIAppBase {
ServiceManager.instance.enable(args[0]); ServiceManager.instance.enable(args[0]);
return true; return true;
},"Enable a service"); },"<name>");
} }
private function handleResult(res: Outcome<Noise,String>): Bool { private function handleResult(res: Outcome<Noise,String>): Bool {

View File

@@ -1,5 +1,6 @@
package bin.srsc; package bin.srsc;
import lib.TypeField;
import kernel.log.Log; import kernel.log.Log;
import lib.KVStore; import lib.KVStore;
import bin.srsc.PackageTypes; import bin.srsc.PackageTypes;
@@ -29,7 +30,7 @@ class SiteRessourceController implements Process {
kernel.net.Net.instance.registerProto(SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO, this.handleMsg); kernel.net.Net.instance.registerProto(SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO, this.handleMsg);
} }
private function handleMsg(pkg:Package) { private function handleMsg(pkg:GenericPackage) {
/* /*
There are 3 types of messages: There are 3 types of messages:
- Register a new ressource name - Register a new ressource name
@@ -39,11 +40,11 @@ class SiteRessourceController implements Process {
switch (pkg.data.type) { switch (pkg.data.type) {
case "register": case "register":
pkg.respond(handleRegister(pkg.data)); pkg.respond(handleRegister(cast pkg.data));
case "unregister": case "unregister":
pkg.respond(handleUnregister(pkg.data)); pkg.respond(handleUnregister(cast pkg.data));
case "get": case "get":
pkg.respond(handleGet(pkg.data)); pkg.respond(handleGet(cast pkg.data));
default: default:
handle.writeLine("Unknown message type: " + pkg.data.type); handle.writeLine("Unknown message type: " + pkg.data.type);
} }

View File

@@ -20,6 +20,8 @@ class DCEHack {
new bin.srsc.CLI(), new bin.srsc.CLI(),
new bin.Perf(), new bin.Perf(),
new bin.KSettings(), new bin.KSettings(),
new bin.ResManager(),
new bin.Res(),
]; ];
} }
} }

View File

@@ -1,5 +1,7 @@
package kernel.binstore; package kernel.binstore;
import bin.Res;
import bin.ResManager;
import bin.KSettings; import bin.KSettings;
import bin.Perf; import bin.Perf;
import bin.srsc.CLI; import bin.srsc.CLI;
@@ -36,6 +38,8 @@ class BinStore {
{c: CLI, name: "SRSC CLI", aliases: ["srsc-cli"]}, {c: CLI, name: "SRSC CLI", aliases: ["srsc-cli"]},
{c: Perf, name: "Perf", aliases: ["perf"]}, {c: Perf, name: "Perf", aliases: ["perf"]},
{c: KSettings, name: "KSettings", aliases: ["ksettings","ks"]}, {c: KSettings, name: "KSettings", aliases: ["ksettings","ks"]},
{c: ResManager, name: "ResManager", aliases: ["resmanager","resmgr"]},
{c: Res, name: "Res", aliases: ["res"]}
]; ];
@:allow(kernel.Init) @:allow(kernel.Init)

View File

@@ -124,7 +124,7 @@ class GPS {
} }
@:allow(kernel.net.Net) @:allow(kernel.net.Net)
private function handlePackage(pack:Package, dist: Float,iface: INetworkInterface) { private function handlePackage(pack:Package<Noise>, dist: Float,iface: INetworkInterface) {
switch (pack.type) { switch (pack.type) {
case GPSRequest: case GPSRequest:
if (!shouldRespond) return; if (!shouldRespond) return;

View File

@@ -1,5 +1,6 @@
package kernel.net; package kernel.net;
import kernel.net.Package.GenericPackage;
using tink.CoreApi; using tink.CoreApi;
/** /**
@@ -13,5 +14,5 @@ interface INetworkInterface {
public function send(chan: Int,replyChan: Int,payload: Any):Void; public function send(chan: Int,replyChan: Int,payload: Any):Void;
public function name():String; public function name():String;
public function getBaseRoutingCost():Int; public function getBaseRoutingCost():Int;
public var onMessage (default, null): Signal<{pack:Package,?dist:Float}>; public var onMessage (default, null): Signal<{pack:GenericPackage,?dist:Float}>;
} }

View File

@@ -1,5 +1,6 @@
package kernel.net; package kernel.net;
import kernel.net.Package.GenericPackage;
import kernel.log.Log; import kernel.log.Log;
using tink.CoreApi; using tink.CoreApi;
@@ -9,9 +10,9 @@ using tink.CoreApi;
class Loopback implements INetworkInterface { class Loopback implements INetworkInterface {
public static final instance:Loopback = new Loopback(); public static final instance:Loopback = new Loopback();
public var onMessage(default, null):Signal<{pack:Package,dist:Null<Float>}>; public var onMessage(default, null):Signal<{pack:GenericPackage,dist:Null<Float>}>;
private final onMessageTrigger: SignalTrigger<{pack:Package,dist:Null<Float>}> = Signal.trigger(); private final onMessageTrigger: SignalTrigger<{pack:GenericPackage,dist:Null<Float>}> = Signal.trigger();
private var openChans: Array<Int> = []; private var openChans: Array<Int> = [];
private function new() { private function new() {

View File

@@ -1,5 +1,6 @@
package kernel.net; package kernel.net;
import kernel.net.Package.GenericPackage;
import kernel.gps.GPS; import kernel.gps.GPS;
import haxe.ds.ReadOnlyArray; import haxe.ds.ReadOnlyArray;
import kernel.net.Package.NetworkID; import kernel.net.Package.NetworkID;
@@ -25,8 +26,8 @@ class Net {
public static inline final DEFAULT_TTL:Int = 10; public static inline final DEFAULT_TTL:Int = 10;
public final networkID:NetworkID = OS.getComputerID(); public final networkID:NetworkID = OS.getComputerID();
private final responseBus:Map<Int, Callback<Outcome<Package,Error>>> = new Map(); private final responseBus:Map<Int, Callback<Outcome<GenericPackage,Error>>> = new Map();
private final protoHandlers:Map<String, Callback<Package>> = new Map(); private final protoHandlers:Map<String, Callback<GenericPackage>> = new Map();
private var interfaces:Array<INetworkInterface>; private var interfaces:Array<INetworkInterface>;
@:allow(kernel.Init) @:allow(kernel.Init)
@@ -68,7 +69,7 @@ class Net {
/** /**
Called when a new package comes in. Called when a new package comes in.
**/ **/
private function handle(pack:Package,interf: INetworkInterface, ?dist: Float) { private function handle(pack:GenericPackage,interf: INetworkInterface, ?dist: Float) {
if (pack.toID == this.networkID || pack.toID == Net.BRODCAST_PORT){ if (pack.toID == this.networkID || pack.toID == Net.BRODCAST_PORT){
switch pack.type { switch pack.type {
case Data(_) | DataNoResponse(_): case Data(_) | DataNoResponse(_):
@@ -81,14 +82,14 @@ class Net {
} }
case RouteDiscover(_) | RouteDiscoverResponse(_) | RouteDiscoverUpdate(_): case RouteDiscover(_) | RouteDiscoverResponse(_) | RouteDiscoverUpdate(_):
// Delegate to Routing // Delegate to Routing
Routing.instance.handleRoutePackage(pack,interf); Routing.instance.handleRoutePackage(cast pack,interf);
case GPSRequest | GPSResponse(_): case GPSRequest | GPSResponse(_):
if (dist == null) { if (dist == null) {
Log.silly("Got a GPS package but no distance was provided"); Log.silly("Got a GPS package but no distance was provided");
return; return;
} }
// Delegate to GPS // Delegate to GPS
GPS.instance.handlePackage(pack,dist,interf); GPS.instance.handlePackage(cast pack,dist,interf);
} }
}else{ }else{
// New message received but its not ment for us. Forward if possible. // New message received but its not ment for us. Forward if possible.
@@ -104,7 +105,7 @@ class Net {
Send a message. Dont care if its reaches its destination nor it has a response. Send a message. Dont care if its reaches its destination nor it has a response.
**/ **/
public function sendAndForget(dest:Int, proto:String, data:Dynamic) { public function sendAndForget(dest:Int, proto:String, data:Dynamic) {
var pack:Package = { var pack:GenericPackage = {
toID: dest, toID: dest,
fromID: networkID, fromID: networkID,
msgID: generateMessageID(), msgID: generateMessageID(),
@@ -116,7 +117,7 @@ class Net {
sendRaw(pack); sendRaw(pack);
} }
private function forwardPackage(pack: Package) { private function forwardPackage(pack: GenericPackage) {
if (pack.ttl == 0){ if (pack.ttl == 0){
if (pack.type.match(Data(_))) { if (pack.type.match(Data(_))) {
@@ -136,7 +137,7 @@ class Net {
} }
} }
public function respondTo(pack:Package, data:Dynamic) { public function respondTo(pack:GenericPackage, data:Dynamic) {
if (pack.type.match(DataNoResponse(_))) { if (pack.type.match(DataNoResponse(_))) {
Log.warn("Responed to a no response package. Ignoring"); Log.warn("Responed to a no response package. Ignoring");
return; return;
@@ -150,7 +151,7 @@ class Net {
/** /**
Send to package to the localy register handler based on the proto Send to package to the localy register handler based on the proto
**/ **/
private function routeToProto(pack:Package) { private function routeToProto(pack:GenericPackage) {
var proto = switch pack.type { var proto = switch pack.type {
case Data(proto): case Data(proto):
proto; proto;
@@ -172,7 +173,7 @@ class Net {
Just send the package to the right modem. Just send the package to the right modem.
Returns true if message was send Returns true if message was send
**/ **/
private function sendRaw(pack:Package): Bool { private function sendRaw(pack:GenericPackage): Bool {
var route = Routing.instance.getRouteToID(pack.toID); var route = Routing.instance.getRouteToID(pack.toID);
if (route == null){ if (route == null){
return false; return false;
@@ -185,9 +186,9 @@ class Net {
/** /**
Send a message and wait for a response. Send a message and wait for a response.
**/ **/
public function sendAndAwait(dest:NetworkID, proto:String, data:Dynamic):Promise<Package> { public function sendAndAwait<T>(dest:NetworkID, proto:String, data:T):Promise<GenericPackage> {
return new Promise<Package>((resolve, reject) -> { return new Promise<GenericPackage>((resolve, reject) -> {
var pack:Package = { var pack:GenericPackage = {
toID: dest, toID: dest,
fromID: networkID, fromID: networkID,
msgID: generateMessageID(), msgID: generateMessageID(),
@@ -198,7 +199,7 @@ class Net {
var timeout:Timer = null; var timeout:Timer = null;
responseBus[pack.msgID] = ((reponse:Outcome<Package,Error>) -> { responseBus[pack.msgID] = ((reponse:Outcome<GenericPackage,Error>) -> {
switch reponse { switch reponse {
case Success(pack): case Success(pack):
@@ -227,7 +228,7 @@ class Net {
}); });
} }
public function registerProto(proto:String, callback:Callback<Package>) { public function registerProto(proto:String, callback:Callback<GenericPackage>) {
if (protoHandlers.exists(proto)) { if (protoHandlers.exists(proto)) {
// Failed. Handler already exist. // Failed. Handler already exist.
// TODO: return error // TODO: return error
@@ -270,7 +271,7 @@ class Net {
@:allow(kernel.gps.GPS) @:allow(kernel.gps.GPS)
private function brodcastGPSRequest() { private function brodcastGPSRequest() {
var pack: Package = { var pack: Package<Noise> = {
fromID: networkID, fromID: networkID,
toID: Net.BRODCAST_PORT, toID: Net.BRODCAST_PORT,
ttl: 0, // Prevent forwarding ttl: 0, // Prevent forwarding

View File

@@ -3,6 +3,7 @@ package kernel.net;
import lib.Pos3; import lib.Pos3;
typedef NetworkID = Int; typedef NetworkID = Int;
typedef GenericPackage = Package<Dynamic> ;
enum PackageTypes { enum PackageTypes {
Data(proto:String); Data(proto:String);
@@ -18,15 +19,15 @@ enum PackageTypes {
/** /**
Representing a network package. Representing a network package.
**/ **/
@:structInit class Package { @:structInit class Package<T> {
public final fromID:NetworkID; public final fromID:NetworkID;
public final toID:NetworkID; public final toID:NetworkID;
public final msgID:Int; public final msgID:Int;
public final type:PackageTypes; public final type:PackageTypes;
public final data:Dynamic; public final data:T;
public var ttl: Int; public var ttl: Int;
public function new(fromID:NetworkID, toID:NetworkID, msgID:Int, type:PackageTypes, data:Dynamic, ttl:Int) { public function new(fromID:NetworkID, toID:NetworkID, msgID:Int, type:PackageTypes, data:T, ttl:Int) {
this.fromID = fromID; this.fromID = fromID;
this.toID = toID; this.toID = toID;
this.msgID = msgID; this.msgID = msgID;
@@ -38,7 +39,7 @@ enum PackageTypes {
/** /**
Create package that can be used as a response. Create package that can be used as a response.
**/ **/
public function createResponse(newData:Dynamic):Package { public function createResponse<T2>(newData:T2):Package<T2> {
return { return {
toID: fromID, toID: fromID,
fromID: toID, fromID: toID,

View File

@@ -73,7 +73,7 @@ class Routing {
Handle incomming packages that involve route discovery. Handle incomming packages that involve route discovery.
**/ **/
@:allow(kernel.net.Net) @:allow(kernel.net.Net)
private function handleRoutePackage(pack:Package, interf:INetworkInterface):Void { private function handleRoutePackage(pack:Package<Noise>, interf:INetworkInterface):Void {
addPossibleRoute(pack.fromID, interf, 0, pack.fromID); addPossibleRoute(pack.fromID, interf, 0, pack.fromID);
var shouldRespond:Bool = switch pack.type { var shouldRespond:Bool = switch pack.type {
@@ -102,7 +102,7 @@ class Routing {
} }
// Respond to peer // Respond to peer
var response:Package = { var response:Package<Noise> = {
toID: pack.fromID, toID: pack.fromID,
fromID: Net.instance.networkID, fromID: Net.instance.networkID,
msgID: null, msgID: null,
@@ -128,8 +128,8 @@ class Routing {
return routes; return routes;
} }
private function newRoutDiscoverPackage():Package { private function newRoutDiscoverPackage():Package<Noise> {
var pack:Package = { var pack:Package<Noise> = {
type: RouteDiscover(genRouteList()), type: RouteDiscover(genRouteList()),
toID: Net.BRODCAST_PORT, toID: Net.BRODCAST_PORT,
msgID: null, msgID: null,

View File

@@ -11,9 +11,9 @@ class Modem implements INetworkInterface implements IPeripheral {
public static inline final TYPE_NAME:String = "modem"; public static inline final TYPE_NAME:String = "modem";
public final addr:String; public final addr:String;
public var onMessage(default, null):Signal<{pack:Package,dist:Null<Float>}>; public var onMessage(default, null):Signal<{pack:GenericPackage,dist:Null<Float>}>;
private final onMessageTrigger:SignalTrigger<{pack:Package,dist:Null<Float>}> = Signal.trigger(); private final onMessageTrigger:SignalTrigger<{pack:GenericPackage,dist:Null<Float>}> = Signal.trigger();
private final native:cc.periphs.Modem.Modem; private final native:cc.periphs.Modem.Modem;
@:allow(kernel.peripherals) @:allow(kernel.peripherals)
@@ -25,7 +25,7 @@ class Modem implements INetworkInterface implements IPeripheral {
KernelEvents.instance.onModemMessage.handle(params ->{ KernelEvents.instance.onModemMessage.handle(params ->{
try{ try{
if (params.addr == this.addr){ if (params.addr == this.addr){
var pack:Package = { var pack:GenericPackage = {
fromID: params.message.fromID, fromID: params.message.fromID,
toID: params.message.toID, toID: params.message.toID,
msgID: params.message.msgID, msgID: params.message.msgID,

View File

@@ -1,5 +1,7 @@
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;
@@ -41,7 +43,7 @@ abstract BundleMask(Int) from cc.Colors.Color to cc.Colors.Color {
} }
} }
class Redstone implements IPeripheral { class Redstone implements IPeripheral implements IExportable {
public final onChange:Signal<Noise>; public final onChange:Signal<Noise>;
@@ -120,4 +122,14 @@ class Redstone implements IPeripheral {
return cc.Redstone.testBundledInput(this.addr,mask); return cc.Redstone.testBundledInput(this.addr,mask);
} }
public function export():ExportConfig {
return {
type: "redstone",
getDelegates: [
"input" => (_) -> {return Bool(this.getInput());},
"analog" => (_) -> {return Number(this.getAnalogInput());}
]
};
}
} }

View File

@@ -0,0 +1,35 @@
package lib.exporter;
import kernel.log.Log;
using tink.CoreApi;
class Export {
private final exportConfig: ExportConfig;
public function new(exportConfig: IExportable) {
this.exportConfig = exportConfig.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);
}
}

View File

@@ -0,0 +1,9 @@
package lib.exporter;
import lib.exporter.Response;
typedef ExportConfig = {
type: String,
getDelegates: Map<String, Null<Int>->ValueType>,
// setDelegates: Map<String, (ValueType, Null<Int>)->ValueType>,
}

View File

@@ -0,0 +1,5 @@
package lib.exporter;
interface IExportable {
public function export(): ExportConfig;
}

View File

@@ -0,0 +1,28 @@
package lib.exporter;
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);
return RessourceNames.get(request.id).next((response)->{
return performRequest(response,request);
});
}
private static function performRequest(netID: NetworkID, request: Request): Promise<Response> {
return Net.instance.sendAndAwait(netID,"res",request).map((response)->{
switch (response){
case Success(data):
return Success(cast (data.data, Response));
case Failure(error):
return Failure(error);
}
});
}
}

View File

@@ -0,0 +1,6 @@
package lib.exporter;
enum Operation {
Get;
Set(value: Dynamic);
}

View File

@@ -0,0 +1,51 @@
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;
}
}
}

View File

@@ -0,0 +1,14 @@
package lib.exporter;
enum Response {
NotFound;
Set;
NotSet;
Get(value: ValueType);
}
enum ValueType {
Number(value: Int);
String(value: String);
Bool(value: Bool);
}