idk routing stuff i guess
This commit is contained in:
parent
ebd9709c3d
commit
c96d06653a
@ -5,6 +5,7 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
[*.hx]
|
[*.hx]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
4
Makefile
4
Makefile
@ -2,7 +2,7 @@ BUNDLE_NAME = bundle.lua
|
|||||||
HAXE_NAME = haxe.lua
|
HAXE_NAME = haxe.lua
|
||||||
MINIFYD_NAME = bundle.min.lua
|
MINIFYD_NAME = bundle.min.lua
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
HAXE_FLAGS = -D webconsole
|
HAXE_FLAGS = -D webconsole --debug
|
||||||
POLYFILLED_NAME = bundle.polyfill.lua
|
POLYFILLED_NAME = bundle.polyfill.lua
|
||||||
POLYFILL_SRC = src/polyfill.lua
|
POLYFILL_SRC = src/polyfill.lua
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ all: clean build
|
|||||||
|
|
||||||
build: $(MIN_PATH)
|
build: $(MIN_PATH)
|
||||||
|
|
||||||
$(HAXE_PATH): $(shell find src -name '*.hx') $(POLYFILL_SRC)
|
$(HAXE_PATH): $(shell find src -name '*.hx')
|
||||||
haxe build.hxml $(HAXE_FLAGS)
|
haxe build.hxml $(HAXE_FLAGS)
|
||||||
|
|
||||||
$(MIN_PATH): $(POLYFILL_PATH)
|
$(MIN_PATH): $(POLYFILL_PATH)
|
||||||
|
@ -1,41 +1,11 @@
|
|||||||
import haxe.MainLoop;
|
import kernel.Log;
|
||||||
import kernel.Init;
|
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;
|
using util.Extender.LambdaExtender;
|
||||||
|
|
||||||
class Startup {
|
class Startup {
|
||||||
public static function main() {
|
public static function main() {
|
||||||
Init.initKernel();
|
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,7 @@
|
|||||||
package kernel;
|
package kernel;
|
||||||
|
|
||||||
|
import haxe.MainLoop;
|
||||||
|
import kernel.net.Routing;
|
||||||
import cc.OS;
|
import cc.OS;
|
||||||
import util.Debug;
|
import util.Debug;
|
||||||
import kernel.ui.WindowManager;
|
import kernel.ui.WindowManager;
|
||||||
@ -10,13 +12,20 @@ class Init {
|
|||||||
public static function initKernel() {
|
public static function initKernel() {
|
||||||
// Init singeltons here because haxe is confused about the order to create them.
|
// Init singeltons here because haxe is confused about the order to create them.
|
||||||
KernelEvents.instance = new KernelEvents();
|
KernelEvents.instance = new KernelEvents();
|
||||||
|
MainLoop.add(() -> {
|
||||||
|
KernelEvents.instance.startEventLoop();
|
||||||
|
},1);
|
||||||
|
|
||||||
Peripheral.instance = new Peripheral();
|
Peripheral.instance = new Peripheral();
|
||||||
|
|
||||||
WindowManager.instance = new WindowManager();
|
WindowManager.instance = new WindowManager();
|
||||||
MainTerm.instance = new MainTerm();
|
MainTerm.instance = new MainTerm();
|
||||||
Log.init();
|
Log.init();
|
||||||
|
|
||||||
|
Routing.instance = new Routing();
|
||||||
Net.instance = new Net();
|
Net.instance = new Net();
|
||||||
|
|
||||||
|
Routing.instance.init();
|
||||||
|
|
||||||
// Register default terminate handler
|
// Register default terminate handler
|
||||||
KernelEvents.instance.onTerminate.handle(_->{
|
KernelEvents.instance.onTerminate.handle(_->{
|
||||||
@ -24,5 +33,8 @@ class Init {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Debug.printBuildInfo();
|
Debug.printBuildInfo();
|
||||||
|
|
||||||
|
|
||||||
|
Log.moveToOutput("main");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ using lua.Table;
|
|||||||
Class for interacting with the native pullEvent system.
|
Class for interacting with the native pullEvent system.
|
||||||
**/
|
**/
|
||||||
class KernelEvents {
|
class KernelEvents {
|
||||||
|
/**
|
||||||
|
Depends on: (Nothing)
|
||||||
|
**/
|
||||||
public static var instance:KernelEvents;
|
public static var instance:KernelEvents;
|
||||||
|
|
||||||
public final onAlarm:Signal<Int>;
|
public final onAlarm:Signal<Int>;
|
||||||
|
@ -4,9 +4,10 @@ import kernel.ui.WindowContext;
|
|||||||
import kernel.ui.WindowManager;
|
import kernel.ui.WindowManager;
|
||||||
import lib.TermWriteable;
|
import lib.TermWriteable;
|
||||||
import lib.TermIO;
|
import lib.TermIO;
|
||||||
|
#if webconsole
|
||||||
import kernel.net.Net;
|
import kernel.net.Net;
|
||||||
import util.Debug;
|
import util.Debug;
|
||||||
|
#end
|
||||||
/**
|
/**
|
||||||
Log messages to specified output.
|
Log messages to specified output.
|
||||||
**/
|
**/
|
||||||
@ -14,6 +15,9 @@ class Log {
|
|||||||
private static var context:WindowContext;
|
private static var context:WindowContext;
|
||||||
private static var writer:TermIO;
|
private static var writer:TermIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Depends on: WindowManager
|
||||||
|
**/
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private static function init() {
|
private static function init() {
|
||||||
Log.context = WindowManager.instance.createNewContext();
|
Log.context = WindowManager.instance.createNewContext();
|
||||||
|
@ -11,6 +11,9 @@ import util.Color;
|
|||||||
Represents the main computer screen.
|
Represents the main computer screen.
|
||||||
**/
|
**/
|
||||||
class MainTerm implements TermWriteable {
|
class MainTerm implements TermWriteable {
|
||||||
|
/**
|
||||||
|
Depends on: KernelEvents,
|
||||||
|
**/
|
||||||
public static var instance:MainTerm;
|
public static var instance:MainTerm;
|
||||||
|
|
||||||
public var onResize(default, null):Signal<Vec2<Int>>;
|
public var onResize(default, null):Signal<Vec2<Int>>;
|
||||||
|
17
src/kernel/net/INetworkInterface.hx
Normal file
17
src/kernel/net/INetworkInterface.hx
Normal file
@ -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<Package>;
|
||||||
|
}
|
47
src/kernel/net/Loopback.hx
Normal file
47
src/kernel/net/Loopback.hx
Normal file
@ -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<Package>;
|
||||||
|
|
||||||
|
private final onMessageTrigger: SignalTrigger<Package> = Signal.trigger();
|
||||||
|
private var openChans: Array<Int> = [];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,6 @@ using tink.CoreApi;
|
|||||||
import kernel.net.Package.NetworkID;
|
import kernel.net.Package.NetworkID;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import kernel.Log;
|
import kernel.Log;
|
||||||
import kernel.KernelEvents;
|
|
||||||
import haxe.Exception;
|
|
||||||
import kernel.Timer;
|
import kernel.Timer;
|
||||||
import cc.OS;
|
import cc.OS;
|
||||||
|
|
||||||
@ -18,145 +16,53 @@ using util.Extender.LambdaExtender;
|
|||||||
Used to send and recceive packages.
|
Used to send and recceive packages.
|
||||||
**/
|
**/
|
||||||
class Net {
|
class Net {
|
||||||
|
/**
|
||||||
|
Depends on: KernelEvents
|
||||||
|
**/
|
||||||
public static var instance:Net;
|
public static var instance:Net;
|
||||||
public static inline final BRODCAST_PORT:Int = 65533;
|
public static inline final BRODCAST_PORT:Int = 65533;
|
||||||
public static inline final MESSAGE_TIMEOUT:Int = 3;
|
public static inline final MESSAGE_TIMEOUT:Int = 3;
|
||||||
|
|
||||||
public final onNewNeigbor:Signal<Int>;
|
|
||||||
|
|
||||||
public final networkID:NetworkID = OS.getComputerID();
|
public final networkID:NetworkID = OS.getComputerID();
|
||||||
private final responseBus:Map<Int, Callback<Package>> = new Map();
|
private final responseBus:Map<Int, Callback<Package>> = new Map();
|
||||||
private final protoHandlers:Map<String, Callback<Package>> = new Map();
|
private final protoHandlers:Map<String, Callback<Package>> = new Map();
|
||||||
private var allModems:Array<kernel.peripherals.Modem>;
|
private var interfaces:Array<INetworkInterface>;
|
||||||
private final routingTable:Map<NetworkID, kernel.peripherals.Modem> = new Map();
|
|
||||||
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private function new() {
|
private function new() {
|
||||||
onNewNeigbor = onNewNeigborTrigger.asSignal();
|
this.interfaces = [for (e in Peripheral.instance.getModems()) e ]; // TODO: is this the way to do it?
|
||||||
KernelEvents.instance.onModemMessage.handle(params -> {
|
this.interfaces.push(Loopback.instance);
|
||||||
var pack:Package = {
|
|
||||||
fromID: params.replyChannel,
|
|
||||||
toID: params.channel,
|
|
||||||
msgID: params.message.msgID,
|
|
||||||
type: params.message.type,
|
|
||||||
data: params.message.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
handelIncomming(pack, params.addr);
|
for (interf in interfaces){
|
||||||
});
|
interf.onMessage.handle(pack -> handle(pack,interf));
|
||||||
|
interf.listen(networkID);
|
||||||
allModems = Peripheral.instance.getModems();
|
interf.listen(BRODCAST_PORT);
|
||||||
|
}
|
||||||
open();
|
|
||||||
discoverNeighbors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Called when a new package comes in.
|
Called when a new package comes in.
|
||||||
**/
|
**/
|
||||||
private function handelIncomming(pack:Package, ?addr:String) {
|
private function handle(pack:Package,interf: INetworkInterface) {
|
||||||
switch pack.type {
|
switch pack.type {
|
||||||
case Data(_):
|
case Data(_) | DataNoResponse(_):
|
||||||
routeToProto(pack);
|
// Let a local proccess handle it
|
||||||
case DataNoResponse(_):
|
|
||||||
routeToProto(pack);
|
routeToProto(pack);
|
||||||
case Response:
|
case Response:
|
||||||
|
// Got a response to a send message. Invoke the callback
|
||||||
if (responseBus.exists(pack.msgID)) {
|
if (responseBus.exists(pack.msgID)) {
|
||||||
responseBus[pack.msgID].invoke(pack);
|
responseBus[pack.msgID].invoke(pack);
|
||||||
}
|
}
|
||||||
case RouteDiscover(_) | RouteDiscoverResponse(_):
|
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<Int> {
|
|
||||||
return routingTable.mapi((index, item) -> index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateMessageID():Int {
|
private function generateMessageID():Int {
|
||||||
return Std.random(2147483647); // TODO: better uniqe number
|
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.
|
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.
|
Just send the package to the right modem.
|
||||||
**/
|
**/
|
||||||
private function sendRaw(pack:Package) {
|
private function sendRaw(pack:Package) {
|
||||||
if (pack.toID == networkID) {
|
|
||||||
// Loopback
|
Routing.instance.getIterfaceToId(pack.toID).send(pack.toID,pack.fromID,pack);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,8 +6,8 @@ enum PackageTypes {
|
|||||||
Data(proto:String);
|
Data(proto:String);
|
||||||
DataNoResponse(proto:String);
|
DataNoResponse(proto:String);
|
||||||
Response;
|
Response;
|
||||||
RouteDiscover(reachableIDs: Array<NetworkID>);
|
RouteDiscover(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||||
RouteDiscoverResponse(reachableIDs: Array<NetworkID>);
|
RouteDiscoverResponse(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
135
src/kernel/net/Routing.hx
Normal file
135
src/kernel/net/Routing.hx
Normal file
@ -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<Int>;
|
||||||
|
|
||||||
|
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
||||||
|
private final routingTable:Map<NetworkID, Route> = 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;
|
||||||
|
}
|
||||||
|
}
|
5
src/kernel/peripherals/IPeripheral.hx
Normal file
5
src/kernel/peripherals/IPeripheral.hx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
interface IPeripheral {
|
||||||
|
public function getAddr(): String;
|
||||||
|
}
|
@ -1,101 +1,71 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import haxe.exceptions.NotImplementedException;
|
using tink.CoreApi;
|
||||||
import haxe.Exception;
|
|
||||||
|
|
||||||
using lua.Table;
|
import kernel.net.Package;
|
||||||
|
import kernel.net.INetworkInterface;
|
||||||
class Modem {
|
|
||||||
private final nativ:cc.periphs.Modem.Modem;
|
|
||||||
|
|
||||||
|
class Modem implements INetworkInterface implements IPeripheral {
|
||||||
public final addr:String;
|
public final addr:String;
|
||||||
|
public var onMessage(default, null):Signal<Package>;
|
||||||
|
|
||||||
|
private final onMessageTrigger:SignalTrigger<Package> = Signal.trigger();
|
||||||
|
private final native:cc.periphs.Modem.Modem;
|
||||||
|
|
||||||
@:allow(kernel.peripherals)
|
@:allow(kernel.peripherals)
|
||||||
private function new(nativePeripherals:cc.periphs.Modem.Modem, addr:String) {
|
private function new(nativePeripherals:cc.periphs.Modem.Modem, addr:String) {
|
||||||
this.nativ = nativePeripherals;
|
this.onMessage = onMessageTrigger.asSignal();
|
||||||
|
this.native = nativePeripherals;
|
||||||
this.addr = addr;
|
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) {
|
public function listen(chan:Int) {
|
||||||
nativ.open(chan);
|
native.open(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOpen(chan:Int):Bool {
|
public function isListening(chan:Int):Bool {
|
||||||
return nativ.isOpen(chan);
|
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) {
|
public function close(chan:Int) {
|
||||||
nativ.close(chan);
|
native.close(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function closAll() {
|
public function getAddr():String {
|
||||||
nativ.closeAll();
|
return this.addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transmit(chan:Int, replyChan:Int, payload:Any) {
|
public function getBaseRoutingCost():Int {
|
||||||
nativ.transmit(chan, replyChan, payload);
|
if (this.native.isWireless()){
|
||||||
}
|
return 2; // Prefere messages over cable
|
||||||
|
}else{
|
||||||
public function isWireless():Bool {
|
return 1;
|
||||||
return nativ.isWireless();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNamesRemote():Array<String> {
|
|
||||||
if (isWireless()) {
|
|
||||||
throw new Exception("'getNamesRemote' only works with wired modems");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<String> {
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import kernel.net.INetworkInterface;
|
||||||
import kernel.peripherals.Modem;
|
import kernel.peripherals.Modem;
|
||||||
import kernel.peripherals.Screen;
|
import kernel.peripherals.Screen;
|
||||||
|
|
||||||
@ -10,50 +11,51 @@ using Lambda;
|
|||||||
Class responseable for retrieving peripherals.
|
Class responseable for retrieving peripherals.
|
||||||
**/
|
**/
|
||||||
class Peripheral {
|
class Peripheral {
|
||||||
|
/**
|
||||||
|
Depends on: KernelEvents
|
||||||
|
**/
|
||||||
public static var instance:Peripheral;
|
public static var instance:Peripheral;
|
||||||
|
|
||||||
|
private var screens: Array<Screen> = [];
|
||||||
|
private var modes: Array<Modem> = [];
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@: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.
|
Get all connected screens.
|
||||||
**/
|
**/
|
||||||
public function getScreens():Array<Screen> {
|
public function getScreens():Array<Screen> {
|
||||||
var allScreens = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "monitor");
|
return this.screens;
|
||||||
return allScreens.map(s -> return new Screen((cc.Peripheral.wrap(s) : Dynamic), s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScreen(addr:String):Screen {
|
private function findScreens():Void {
|
||||||
if (!getAllPeripheralsAddr().exists(item -> item == addr)) {
|
var allScreens = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "monitor");
|
||||||
return null;
|
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.
|
Get all connected modems.
|
||||||
**/
|
**/
|
||||||
public function getModems():Array<Modem> {
|
public function getModems():Array<Modem> {
|
||||||
|
return this.modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findModems():Void {
|
||||||
var allModems = cc.Peripheral.getNames().toArray().filter(s -> cc.Peripheral.getType(s) == "modem");
|
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));
|
this.modes = allModems.map(s -> return new Modem((cc.Peripheral.wrap(s) : Dynamic), s));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get all connected wireless modems.
|
|
||||||
**/
|
|
||||||
public function getWirelessModems():Array<Modem> {
|
|
||||||
return getModems().filter(modem -> return modem.isWireless());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get all connected wired modems.
|
|
||||||
**/
|
|
||||||
public function getWiredModems():Array<Modem> {
|
|
||||||
return getModems().filter(modem -> return !modem.isWireless());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAllPeripheralsAddr():Array<String> {
|
|
||||||
return cc.Peripheral.getNames().toArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import lib.TermWriteable;
|
|||||||
import util.Vec.Vec2;
|
import util.Vec.Vec2;
|
||||||
import util.Color;
|
import util.Color;
|
||||||
|
|
||||||
class Screen implements TermWriteable {
|
class Screen implements TermWriteable implements IPeripheral {
|
||||||
private final nativ:cc.periphs.Monitor.Monitor;
|
private final nativ:cc.periphs.Monitor.Monitor;
|
||||||
private final addr:String;
|
private final addr:String;
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ import lib.TermWriteable;
|
|||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
|
||||||
class WindowManager {
|
class WindowManager {
|
||||||
|
/**
|
||||||
|
Depends on: KernelEvents, Peripheral
|
||||||
|
**/
|
||||||
public static var instance:WindowManager;
|
public static var instance:WindowManager;
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package lib;
|
|
||||||
|
|
||||||
interface IUserProgramm {
|
|
||||||
public function getName():String;
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package lib.ui;
|
package lib.ui.reactive;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package lib.ui;
|
package lib.ui.reactive;
|
||||||
|
|
||||||
import kernel.Log;
|
import kernel.Log;
|
||||||
import util.Color;
|
import util.Color;
|
@ -1,5 +1,6 @@
|
|||||||
package lib.ui;
|
package lib.ui.reactive;
|
||||||
|
|
||||||
|
import util.Observable;
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
import util.Color;
|
import util.Color;
|
@ -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<T> {
|
|
||||||
private var listner:Map<String, SignalTrigger<T>> = new Map();
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function on(eventName:String, callback:Callback<T>):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<T>):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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package lib.ui;
|
package util;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
package util;
|
|
||||||
|
|
||||||
import haxe.Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
JS-like promise class.
|
|
||||||
**/
|
|
||||||
class Promise<T> {
|
|
||||||
private var thenCB:T->Void;
|
|
||||||
private var errorCB:Exception->Void;
|
|
||||||
|
|
||||||
public function then(cb:(data:T) -> Void):Promise<T> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user