diff --git a/.editorconfig b/.editorconfig index bf41b2b..518faa8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,7 @@ root = true [*] end_of_line = lf insert_final_newline = true +tab_width = 4 [*.hx] indent_style = tab diff --git a/Makefile b/Makefile index 1eeef96..1773d61 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ BUNDLE_NAME = bundle.lua HAXE_NAME = haxe.lua MINIFYD_NAME = bundle.min.lua BUILD_DIR = build -HAXE_FLAGS = -D webconsole +HAXE_FLAGS = -D webconsole --debug POLYFILLED_NAME = bundle.polyfill.lua POLYFILL_SRC = src/polyfill.lua @@ -14,7 +14,7 @@ all: clean build build: $(MIN_PATH) -$(HAXE_PATH): $(shell find src -name '*.hx') $(POLYFILL_SRC) +$(HAXE_PATH): $(shell find src -name '*.hx') haxe build.hxml $(HAXE_FLAGS) $(MIN_PATH): $(POLYFILL_PATH) diff --git a/src/Startup.hx b/src/Startup.hx index abdcb57..b392d5d 100644 --- a/src/Startup.hx +++ b/src/Startup.hx @@ -1,41 +1,11 @@ -import haxe.MainLoop; +import kernel.Log; import kernel.Init; -import lib.ui.Observable; -import lib.ui.TextElement; -import lib.ui.ReactiveUI; -import kernel.ui.WindowManager; -import kernel.KernelEvents; using util.Extender.LambdaExtender; class Startup { public static function main() { Init.initKernel(); - - MainLoop.add(() -> { - KernelEvents.instance.startEventLoop(); - },0); - - exampleUI(); - } - - static function exampleUI() { - var context = WindowManager.instance.createNewContext(); - - var text = new Observable("Hello world"); - - var ui = new ReactiveUI(context,[ - new TextElement(text), - new TextElement(text,Green,Red), - ]); - - ui.render(); - - context.clickSignal.handle(data -> { - text.set("Holla mundo"); - }); - - WindowManager.instance.focusContextToOutput(context,"main"); } } diff --git a/src/bin/NetTest.hx b/src/bin/NetTest.hx deleted file mode 100644 index 59c49f7..0000000 --- a/src/bin/NetTest.hx +++ /dev/null @@ -1,29 +0,0 @@ -package bin; - -import lib.TermIO; -import kernel.net.Net; -import kernel.ui.WindowManager; -import kernel.ui.WindowContext; -import lib.IUserProgramm; - -class NetTest implements IUserProgramm { - private final windowContext:WindowContext = WindowManager.instance.createNewContext(); - private final writer:TermIO; - - public function new() { - writer = new TermIO(windowContext); - } - - private function drawUI() { - var allNeighbors = Net.instance.getAllNeighbors(); - - for (neighbor in allNeighbors) { - writer.writeLn(""+neighbor,Green); - } - } - - - public function getName():String { - return "Network tester"; - } -} diff --git a/src/kernel/Init.hx b/src/kernel/Init.hx index e877f6c..ac4c397 100644 --- a/src/kernel/Init.hx +++ b/src/kernel/Init.hx @@ -1,5 +1,7 @@ package kernel; +import haxe.MainLoop; +import kernel.net.Routing; import cc.OS; import util.Debug; import kernel.ui.WindowManager; @@ -10,13 +12,20 @@ class Init { public static function initKernel() { // Init singeltons here because haxe is confused about the order to create them. KernelEvents.instance = new KernelEvents(); + MainLoop.add(() -> { + KernelEvents.instance.startEventLoop(); + },1); + Peripheral.instance = new Peripheral(); WindowManager.instance = new WindowManager(); MainTerm.instance = new MainTerm(); Log.init(); + + Routing.instance = new Routing(); Net.instance = new Net(); + Routing.instance.init(); // Register default terminate handler KernelEvents.instance.onTerminate.handle(_->{ @@ -24,5 +33,8 @@ class Init { }); Debug.printBuildInfo(); + + + Log.moveToOutput("main"); } } diff --git a/src/kernel/KernelEvents.hx b/src/kernel/KernelEvents.hx index 5c8b44b..4bd6c17 100644 --- a/src/kernel/KernelEvents.hx +++ b/src/kernel/KernelEvents.hx @@ -13,6 +13,9 @@ using lua.Table; Class for interacting with the native pullEvent system. **/ class KernelEvents { + /** + Depends on: (Nothing) + **/ public static var instance:KernelEvents; public final onAlarm:Signal; diff --git a/src/kernel/Log.hx b/src/kernel/Log.hx index 40ca320..d9c5a39 100644 --- a/src/kernel/Log.hx +++ b/src/kernel/Log.hx @@ -4,9 +4,10 @@ import kernel.ui.WindowContext; import kernel.ui.WindowManager; import lib.TermWriteable; import lib.TermIO; +#if webconsole import kernel.net.Net; import util.Debug; - +#end /** Log messages to specified output. **/ @@ -14,6 +15,9 @@ class Log { private static var context:WindowContext; private static var writer:TermIO; + /** + Depends on: WindowManager + **/ @:allow(kernel.Init) private static function init() { Log.context = WindowManager.instance.createNewContext(); diff --git a/src/kernel/MainTerm.hx b/src/kernel/MainTerm.hx index 6ffb79a..8e677e9 100644 --- a/src/kernel/MainTerm.hx +++ b/src/kernel/MainTerm.hx @@ -11,6 +11,9 @@ import util.Color; Represents the main computer screen. **/ class MainTerm implements TermWriteable { + /** + Depends on: KernelEvents, + **/ public static var instance:MainTerm; public var onResize(default, null):Signal>; diff --git a/src/kernel/net/INetworkInterface.hx b/src/kernel/net/INetworkInterface.hx new file mode 100644 index 0000000..f3dd8eb --- /dev/null +++ b/src/kernel/net/INetworkInterface.hx @@ -0,0 +1,17 @@ +package kernel.net; + +using tink.CoreApi; + +/** + A object that is able to send and receive messages. +**/ +interface INetworkInterface { + public function listen(chan: Int):Void; + public function close(chan: Int):Void; + public function isListening(chan: Int): Bool; + public function closeAll(): Void; + public function send(chan: Int,replyChan: Int,payload: Any):Void; + public function name():String; + public function getBaseRoutingCost():Int; + public var onMessage (default, null): Signal; +} diff --git a/src/kernel/net/Loopback.hx b/src/kernel/net/Loopback.hx new file mode 100644 index 0000000..2d469ae --- /dev/null +++ b/src/kernel/net/Loopback.hx @@ -0,0 +1,47 @@ +package kernel.net; + +using tink.CoreApi; + +/** + Virtual network interface that handle +**/ +class Loopback implements INetworkInterface { + public static final instance:Loopback = new Loopback(); + + public var onMessage(default, null):Signal; + + private final onMessageTrigger: SignalTrigger = Signal.trigger(); + private var openChans: Array = []; + + private function new() { + this.onMessage = onMessageTrigger.asSignal(); + } + + public function listen(chan:Int) { + // TODO + } + + public function close(chan:Int) { + // TODO + } + + public function isListening(chan:Int):Bool { + return this.openChans.contains(chan); + } + + public function closeAll() { + this.openChans = []; + } + + public function send(chan:Int, replyChan:Int, payload:Any) { + this.onMessageTrigger.trigger(payload); + } + + public function name():String { + return "loopback"; + } + + public function getBaseRoutingCost():Int { + return 0; + } +} diff --git a/src/kernel/net/Net.hx b/src/kernel/net/Net.hx index fecffc6..06c928f 100644 --- a/src/kernel/net/Net.hx +++ b/src/kernel/net/Net.hx @@ -5,8 +5,6 @@ using tink.CoreApi; import kernel.net.Package.NetworkID; import kernel.peripherals.Peripherals.Peripheral; import kernel.Log; -import kernel.KernelEvents; -import haxe.Exception; import kernel.Timer; import cc.OS; @@ -18,145 +16,53 @@ using util.Extender.LambdaExtender; Used to send and recceive packages. **/ class Net { + /** + Depends on: KernelEvents + **/ public static var instance:Net; public static inline final BRODCAST_PORT:Int = 65533; public static inline final MESSAGE_TIMEOUT:Int = 3; - public final onNewNeigbor:Signal; - public final networkID:NetworkID = OS.getComputerID(); private final responseBus:Map> = new Map(); private final protoHandlers:Map> = new Map(); - private var allModems:Array; - private final routingTable:Map = new Map(); - private final onNewNeigborTrigger:SignalTrigger = Signal.trigger(); + private var interfaces:Array; @:allow(kernel.Init) private function new() { - onNewNeigbor = onNewNeigborTrigger.asSignal(); - KernelEvents.instance.onModemMessage.handle(params -> { - var pack:Package = { - fromID: params.replyChannel, - toID: params.channel, - msgID: params.message.msgID, - type: params.message.type, - data: params.message.data, - }; + this.interfaces = [for (e in Peripheral.instance.getModems()) e ]; // TODO: is this the way to do it? + this.interfaces.push(Loopback.instance); - handelIncomming(pack, params.addr); - }); - - allModems = Peripheral.instance.getModems(); - - open(); - discoverNeighbors(); + for (interf in interfaces){ + interf.onMessage.handle(pack -> handle(pack,interf)); + interf.listen(networkID); + interf.listen(BRODCAST_PORT); + } } /** Called when a new package comes in. **/ - private function handelIncomming(pack:Package, ?addr:String) { + private function handle(pack:Package,interf: INetworkInterface) { switch pack.type { - case Data(_): - routeToProto(pack); - case DataNoResponse(_): + case Data(_) | DataNoResponse(_): + // Let a local proccess handle it routeToProto(pack); case Response: + // Got a response to a send message. Invoke the callback if (responseBus.exists(pack.msgID)) { responseBus[pack.msgID].invoke(pack); } case RouteDiscover(_) | RouteDiscoverResponse(_): - handleRouteDiscover(pack, addr); + // Delegate to Routing + Routing.instance.handleRoutePackage(pack,interf); } } - private function newRoutDiscoverPackage():Package { - var pack:Package = { - type: RouteDiscover(getAllNeighbors()), - toID: BRODCAST_PORT, - msgID: generateMessageID(), - fromID: networkID, - data: null, - } - - return pack; - } - - /** - Send out discover packages on all modems. - **/ - private function discoverNeighbors() { - for (modem in allModems) { - var pack = newRoutDiscoverPackage(); - - modem.transmit(BRODCAST_PORT, networkID, pack); - } - } - - /** - Handle incomming packages that involve route discovery. - **/ - private function handleRouteDiscover(pack:Package, addr:String) { - addRoute(pack.fromID, addr); - - var forward = getAllNeighbors().filter(i -> i == pack.fromID); - - switch pack.type{ - case RouteDiscoverResponse(reachableIDs): - for (id in reachableIDs) { - addRoute(id, addr); - } - return; // Dont respond to a response - case RouteDiscover(reachableIDs): - for (id in reachableIDs) { - addRoute(id, addr); - } - default: - throw new Error("Expcted RouteDiscover or RouteDiscoverResponse type"); - } - - // Respond to peer - var response:Package = { - toID: pack.fromID, - fromID: networkID, - msgID: pack.msgID, - type: RouteDiscoverResponse(forward), - data: null - } - - for (reponseModem in allModems.filter(m -> m.addr == addr)) { - reponseModem.transmit(pack.fromID, networkID, response); - } - } - - /** - Called when a route to a client has been disoverd. - Its posible to be called multiple times with the same id but different addr. - **/ - private function addRoute(toID:Int, addr:String) { - Log.info("Added new route to " + toID + " via " + addr); - routingTable.set(toID, allModems.find(item -> item.addr == addr)); - this.onNewNeigborTrigger.trigger(toID); - } - - public function getAllNeighbors():Array { - return routingTable.mapi((index, item) -> index); - } - private function generateMessageID():Int { return Std.random(2147483647); // TODO: better uniqe number } - /** - Open all wireless and wired modem. - **/ - private function open() { - for (m in allModems) { - m.open(networkID); - m.open(BRODCAST_PORT); - } - } - /** Send a message. Dont care if its reaches its destination nor it has a response. **/ @@ -207,17 +113,8 @@ class Net { Just send the package to the right modem. **/ private function sendRaw(pack:Package) { - if (pack.toID == networkID) { - // Loopback - handelIncomming(pack); - } else { - if (routingTable.exists(pack.toID)) { - routingTable[pack.toID].transmit(pack.toID, pack.fromID, pack); - } else { - // Route not found - // TODO: forward package or report not reachable - } - } + + Routing.instance.getIterfaceToId(pack.toID).send(pack.toID,pack.fromID,pack); } /** diff --git a/src/kernel/net/Package.hx b/src/kernel/net/Package.hx index c16286f..7d9e569 100644 --- a/src/kernel/net/Package.hx +++ b/src/kernel/net/Package.hx @@ -6,8 +6,8 @@ enum PackageTypes { Data(proto:String); DataNoResponse(proto:String); Response; - RouteDiscover(reachableIDs: Array); - RouteDiscoverResponse(reachableIDs: Array); + RouteDiscover(reachableIDs: Array<{id:NetworkID,cost:Int}>); + RouteDiscoverResponse(reachableIDs: Array<{id:NetworkID,cost:Int}>); } /** diff --git a/src/kernel/net/Routing.hx b/src/kernel/net/Routing.hx new file mode 100644 index 0000000..2ac4193 --- /dev/null +++ b/src/kernel/net/Routing.hx @@ -0,0 +1,135 @@ +package kernel.net; + +import kernel.peripherals.Peripherals.Peripheral; +import kernel.net.INetworkInterface; + +using tink.CoreApi; + +import kernel.net.Package.NetworkID; + +@:structInit typedef Route = { + interf:INetworkInterface, + cost:Int +} + +/** + Manages network routing. +**/ +class Routing { + /** + Depends on: Peripheral + **/ + public static var instance:Routing; + + public final onNewNeigbor:Signal; + + private final onNewNeigborTrigger:SignalTrigger = Signal.trigger(); + private final routingTable:Map = new Map(); + + @:allow(kernel.Init) + private function new() { + this.onNewNeigbor = this.onNewNeigborTrigger.asSignal(); + } + + @:allow(kernel.Init) + private function init() { + routingTable.set(Net.instance.networkID,{interf: Loopback.instance,cost:0}); + for (modem in Peripheral.instance.getModems()) { + modem.send(Net.BRODCAST_PORT, Net.instance.networkID, newRoutDiscoverPackage()); + } + } + + /** + Handle incomming packages that involve route discovery. + **/ + public function handleRoutePackage(pack:Package, interf:INetworkInterface):Void { + addPossibleRoute(pack.fromID,interf,0); + + var shouldRespond: Bool = switch pack.type { + case RouteDiscoverResponse(routes): + for (route in routes) { + addPossibleRoute(route.id,interf,route.cost); + } + false; + case RouteDiscover(routes): + for (route in routes) { + addPossibleRoute(route.id,interf,route.cost); + } + true; + default: + Log.error("Expected RouteDiscover or RouteDiscoverResponse type"); + false; + }; + + if (!shouldRespond){ + return; + } + + // Respond to peer + var response:Package = { + toID: pack.fromID, + fromID: Net.instance.networkID, + msgID: null, + type: RouteDiscoverResponse(genRouteList()), + data: null + } + + interf.send(pack.fromID,Net.instance.networkID,response); + } + + private function genRouteList(): Array<{id:NetworkID,cost:Int}> { + var routes: Array<{id:NetworkID,cost:Int}> = []; + for (k => v in this.routingTable){ + routes.push({ + id: k, + cost: v.cost + }); + } + return routes; + } + + private function newRoutDiscoverPackage():Package { + var pack:Package = { + type: RouteDiscover(genRouteList()), + toID: Net.BRODCAST_PORT, + msgID: null, + fromID: Net.instance.networkID, + data: null, + } + + return pack; + } + + /** + Called when a route to a client has been disoverd. + Its possible to be called multiple times with the same id but different addr. + **/ + private function addPossibleRoute(toID:Int, interf:INetworkInterface, cost:Int) { + if (toID == Net.instance.networkID){ + return; + } + + Log.debug("a"); + + var fullCost = cost+interf.getBaseRoutingCost(); + + if (this.routingTable.exists(toID)){ + if (this.routingTable[toID].cost > fullCost){ + Log.debug("Better route: " + toID + " -> " + interf.name() + ":$"+fullCost); + this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()}; + } + }else{ + this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()}; + Log.debug("New route: " + toID + " -> " + interf.name() + ":$"+fullCost); + this.onNewNeigborTrigger.trigger(toID); + } + } + + public function getIterfaceToId(networkID:NetworkID):INetworkInterface { + if (networkID == Net.instance.networkID) { + return Loopback.instance; + } + + return null; + } +} diff --git a/src/kernel/peripherals/IPeripheral.hx b/src/kernel/peripherals/IPeripheral.hx new file mode 100644 index 0000000..6412d95 --- /dev/null +++ b/src/kernel/peripherals/IPeripheral.hx @@ -0,0 +1,5 @@ +package kernel.peripherals; + +interface IPeripheral { + public function getAddr(): String; +} diff --git a/src/kernel/peripherals/Modem.hx b/src/kernel/peripherals/Modem.hx index 139c806..3875f74 100644 --- a/src/kernel/peripherals/Modem.hx +++ b/src/kernel/peripherals/Modem.hx @@ -1,101 +1,71 @@ package kernel.peripherals; -import haxe.exceptions.NotImplementedException; -import haxe.Exception; +using tink.CoreApi; -using lua.Table; - -class Modem { - private final nativ:cc.periphs.Modem.Modem; +import kernel.net.Package; +import kernel.net.INetworkInterface; +class Modem implements INetworkInterface implements IPeripheral { public final addr:String; + public var onMessage(default, null):Signal; + + private final onMessageTrigger:SignalTrigger = Signal.trigger(); + private final native:cc.periphs.Modem.Modem; @:allow(kernel.peripherals) private function new(nativePeripherals:cc.periphs.Modem.Modem, addr:String) { - this.nativ = nativePeripherals; + this.onMessage = onMessageTrigger.asSignal(); + this.native = nativePeripherals; this.addr = addr; + + KernelEvents.instance.onModemMessage.handle(params ->{ + if (params.addr == this.addr){ + var pack:Package = { + fromID: params.replyChannel, + toID: params.channel, + msgID: params.message.msgID, + type: params.message.type, + data: params.message.data, + }; + + this.onMessageTrigger.trigger(pack); + } + }); } - public function open(chan:Int) { - nativ.open(chan); + public function listen(chan:Int) { + native.open(chan); } - public function isOpen(chan:Int):Bool { - return nativ.isOpen(chan); + public function isListening(chan:Int):Bool { + return native.isOpen(chan); + } + + public function closeAll() { + native.closeAll(); + } + + public function send(chan:Int, replyChan:Int, payload:Any) { + native.transmit(chan, replyChan, payload); + } + + public function name():String { + return addr; } public function close(chan:Int) { - nativ.close(chan); + native.close(chan); } - public function closAll() { - nativ.closeAll(); + public function getAddr():String { + return this.addr; } - public function transmit(chan:Int, replyChan:Int, payload:Any) { - nativ.transmit(chan, replyChan, payload); - } - - public function isWireless():Bool { - return nativ.isWireless(); - } - - public function getNamesRemote():Array { - if (isWireless()) { - throw new Exception("'getNamesRemote' only works with wired modems"); + public function getBaseRoutingCost():Int { + if (this.native.isWireless()){ + return 2; // Prefere messages over cable + }else{ + return 1; } - - return nativ.getNamesRemote().toArray(); - } - - public function isPresentRemote(name:String):Bool { - if (isWireless()) { - throw new Exception("'isPresentRemote' only works with wired modems"); - } - - return nativ.isPresentRemote(name); - } - - public function getTypeRemote(name:String):String { - if (isWireless()) { - throw new Exception("'getTypeRemote' only works with wired modems"); - } - - return nativ.getTypeRemote(name); - } - - public function hasTypeRemote(name:String, type:String):Bool { - if (isWireless()) { - throw new Exception("'hasTypeRemote' only works with wired modems"); - } - - // Missing in upstream API - throw new haxe.exceptions.NotImplementedException(); - // return nativ.hasRemoteType(name,type); - } - - public function getMethodsRemote(name:String):Array { - if (isWireless()) { - throw new Exception("'getMethodsRemote' only works with wired modems"); - } - - return nativ.getMethodsRemote(name).toArray(); - } - - public function callRemote(remoteName:String, method:String):Dynamic { - if (isWireless()) { - throw new Exception("'callRemote' only works with wired modems"); - } - - // TODO: implment or solve differently - throw new haxe.exceptions.NotImplementedException(); - } - - public function getNameLocal():String { - if (isWireless()) { - throw new Exception("'getNameLocal' only works with wired modems"); - } - - return nativ.getNameLocal(); } } diff --git a/src/kernel/peripherals/Peripherals.hx b/src/kernel/peripherals/Peripherals.hx index 1e64220..a64a23e 100644 --- a/src/kernel/peripherals/Peripherals.hx +++ b/src/kernel/peripherals/Peripherals.hx @@ -1,5 +1,6 @@ package kernel.peripherals; +import kernel.net.INetworkInterface; import kernel.peripherals.Modem; import kernel.peripherals.Screen; @@ -10,50 +11,51 @@ using Lambda; Class responseable for retrieving peripherals. **/ class Peripheral { + /** + Depends on: KernelEvents + **/ public static var instance:Peripheral; + private var screens: Array = []; + private var modes: Array = []; + @:allow(kernel.Init) - private function new() {} + private function new() { + KernelEvents.instance.onPeripheral.handle(this.updatePeripherals); + KernelEvents.instance.onPeripheralDetach.handle(this.updatePeripherals); + updatePeripherals(); + } + + private function updatePeripherals() { + findScreens(); + findModems(); + } /** Get all connected screens. **/ public function getScreens():Array { - var allScreens = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "monitor"); - return allScreens.map(s -> return new Screen((cc.Peripheral.wrap(s) : Dynamic), s)); + return this.screens; } - public function getScreen(addr:String):Screen { - if (!getAllPeripheralsAddr().exists(item -> item == addr)) { - return null; - } + private function findScreens():Void { + var allScreens = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "monitor"); + this.screens = allScreens.map(s -> return new Screen((cc.Peripheral.wrap(s) : Dynamic), s)); + } - return new Screen((cc.Peripheral.wrap(addr) : Dynamic), addr); + public function getScreen(addr: String): Screen { + return this.screens.find(item -> item.getAddr() == addr); } /** Get all connected modems. **/ public function getModems():Array { + return this.modes; + } + + private function findModems():Void { var allModems = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "modem"); - return allModems.map(s -> return new Modem((cc.Peripheral.wrap(s) : Dynamic), s)); - } - - /** - Get all connected wireless modems. - **/ - public function getWirelessModems():Array { - return getModems().filter(modem -> return modem.isWireless()); - } - - /** - Get all connected wired modems. - **/ - public function getWiredModems():Array { - return getModems().filter(modem -> return !modem.isWireless()); - } - - public function getAllPeripheralsAddr():Array { - return cc.Peripheral.getNames().toArray(); + this.modes = allModems.map(s -> return new Modem((cc.Peripheral.wrap(s) : Dynamic), s)); } } diff --git a/src/kernel/peripherals/Screen.hx b/src/kernel/peripherals/Screen.hx index f4f24ae..581c695 100644 --- a/src/kernel/peripherals/Screen.hx +++ b/src/kernel/peripherals/Screen.hx @@ -7,7 +7,7 @@ import lib.TermWriteable; import util.Vec.Vec2; import util.Color; -class Screen implements TermWriteable { +class Screen implements TermWriteable implements IPeripheral { private final nativ:cc.periphs.Monitor.Monitor; private final addr:String; diff --git a/src/kernel/ui/WindowManager.hx b/src/kernel/ui/WindowManager.hx index 0a014c4..a58e72a 100644 --- a/src/kernel/ui/WindowManager.hx +++ b/src/kernel/ui/WindowManager.hx @@ -4,6 +4,9 @@ import lib.TermWriteable; import kernel.peripherals.Peripherals.Peripheral; class WindowManager { + /** + Depends on: KernelEvents, Peripheral + **/ public static var instance:WindowManager; @:allow(kernel.Init) diff --git a/src/lib/IUserProgramm.hx b/src/lib/IUserProgramm.hx deleted file mode 100644 index c868bcc..0000000 --- a/src/lib/IUserProgramm.hx +++ /dev/null @@ -1,5 +0,0 @@ -package lib; - -interface IUserProgramm { - public function getName():String; -} diff --git a/src/lib/ui/IElement.hx b/src/lib/ui/reactive/IElement.hx similarity index 87% rename from src/lib/ui/IElement.hx rename to src/lib/ui/reactive/IElement.hx index 7da5e65..7289ab9 100644 --- a/src/lib/ui/IElement.hx +++ b/src/lib/ui/reactive/IElement.hx @@ -1,4 +1,4 @@ -package lib.ui; +package lib.ui.reactive; using tink.CoreApi; diff --git a/src/lib/ui/ReactiveUI.hx b/src/lib/ui/reactive/ReactiveUI.hx similarity index 98% rename from src/lib/ui/ReactiveUI.hx rename to src/lib/ui/reactive/ReactiveUI.hx index 387595e..7b1a307 100644 --- a/src/lib/ui/ReactiveUI.hx +++ b/src/lib/ui/reactive/ReactiveUI.hx @@ -1,4 +1,4 @@ -package lib.ui; +package lib.ui.reactive; import kernel.Log; import util.Color; diff --git a/src/lib/ui/TextElement.hx b/src/lib/ui/reactive/TextElement.hx similarity index 95% rename from src/lib/ui/TextElement.hx rename to src/lib/ui/reactive/TextElement.hx index 3bd4802..9f2eef2 100644 --- a/src/lib/ui/TextElement.hx +++ b/src/lib/ui/reactive/TextElement.hx @@ -1,5 +1,6 @@ -package lib.ui; +package lib.ui.reactive; +import util.Observable; using tink.CoreApi; import util.Color; diff --git a/src/util/EventBus.hx b/src/util/EventBus.hx deleted file mode 100644 index 6cfcce2..0000000 --- a/src/util/EventBus.hx +++ /dev/null @@ -1,58 +0,0 @@ -package util; - -using tink.CoreApi; - -class EventBusListner { - @:allow(util.EventBus) - private final link:CallbackLink; - - @:allow(util.EventBus) - private final eventName:String; - - @:allow(util.EventBus) - private function new(link:CallbackLink, eventName:String) { - this.link = link; - this.eventName = eventName; - } -} - -/** - Generic event handler. -**/ -class EventBus { - private var listner:Map> = new Map(); - - public function new() {} - - public function on(eventName:String, callback:Callback):EventBusListner { - if (!listner.exists(eventName)) { - listner[eventName] = Signal.trigger(); - } - - var link = listner[eventName].asSignal().handle(callback); - return new EventBusListner(link, eventName); - } - - public function once(eventName:String, callback:Callback):EventBusListner { - if (!listner.exists(eventName)) { - listner[eventName] = Signal.trigger(); - } - - var link = listner[eventName].asSignal().handle(callback); - return new EventBusListner(link, eventName); - } - - public function emit(eventName:String, data:T) { - if (listner.exists(eventName)) { - var trigger = listner[eventName]; - trigger.trigger(data); - } - } - - public function removeListner(id:EventBusListner) { - if (!listner.exists(id.eventName)) { - return; - } - id.link.cancel(); - } -} diff --git a/src/lib/ui/Observable.hx b/src/util/Observable.hx similarity index 96% rename from src/lib/ui/Observable.hx rename to src/util/Observable.hx index 46b9855..01299b6 100644 --- a/src/lib/ui/Observable.hx +++ b/src/util/Observable.hx @@ -1,4 +1,4 @@ -package lib.ui; +package util; using tink.CoreApi; diff --git a/src/util/Promise.hx b/src/util/Promise.hx deleted file mode 100644 index 9745e7d..0000000 --- a/src/util/Promise.hx +++ /dev/null @@ -1,39 +0,0 @@ -package util; - -import haxe.Exception; - -/** - JS-like promise class. -**/ -class Promise { - private var thenCB:T->Void; - private var errorCB:Exception->Void; - - public function then(cb:(data:T) -> Void):Promise { - thenCB = cb; - - return this; - } - - public function error(cb:(err:Exception) -> Void) { - errorCB = cb; - } - - public function new(func:(resolve:(T) -> Void, reject:(Exception) -> Void)->Void) { - try { - func(data -> { - if (thenCB != null) { - thenCB(data); - } - }, e -> { - if (errorCB != null) { - errorCB(e); - } - }); - } catch (e:Exception) { - if (errorCB != null) { - errorCB(e); - } - } - } -}