272 lines
6.2 KiB
Haxe
Raw Normal View History

2021-12-20 01:55:30 +01:00
package kernel.net;
2022-02-22 01:47:55 +01:00
using tink.CoreApi;
2022-02-24 02:05:43 +01:00
import kernel.net.Package.NetworkID;
2021-12-20 01:55:30 +01:00
import kernel.peripherals.Peripherals.Peripheral;
import kernel.Log;
import kernel.KernelEvents;
import haxe.Exception;
import kernel.Timer;
import cc.OS;
using Lambda;
using util.Extender.LambdaExtender;
/**
Class responsible for everything network related.
Used to send and recceive packages.
**/
2022-02-21 15:35:37 +01:00
class Net {
2022-02-21 01:50:19 +01:00
public static var instance:Net;
2022-02-22 02:28:53 +01:00
public static inline final BRODCAST_PORT:Int = 65533;
public static inline final MESSAGE_TIMEOUT:Int = 3;
2021-12-20 01:55:30 +01:00
2022-02-24 02:05:43 +01:00
public final onNewNeigbor:Signal<Int>;
2022-02-22 02:28:53 +01:00
2022-02-24 02:05:43 +01:00
public final networkID:NetworkID = OS.getComputerID();
private final responseBus:Map<Int, Callback<Package>> = new Map();
private final protoHandlers:Map<String, Callback<Package>> = new Map();
2022-02-22 02:28:53 +01:00
private var allModems:Array<kernel.peripherals.Modem>;
2022-02-24 02:05:43 +01:00
private final routingTable:Map<NetworkID, kernel.peripherals.Modem> = new Map();
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
2022-02-22 01:47:55 +01:00
2022-02-21 01:50:19 +01:00
@:allow(kernel.Init)
2022-02-21 15:35:37 +01:00
private function new() {
2022-02-22 01:47:55 +01:00
onNewNeigbor = onNewNeigborTrigger.asSignal();
2022-02-21 15:35:37 +01:00
KernelEvents.instance.onModemMessage.handle(params -> {
var pack:Package = {
2022-02-21 15:17:38 +01:00
fromID: params.replyChannel,
toID: params.channel,
msgID: params.message.msgID,
type: params.message.type,
data: params.message.data,
};
2022-02-21 15:35:37 +01:00
handelIncomming(pack, params.addr);
2021-12-20 01:55:30 +01:00
});
2022-02-21 15:17:38 +01:00
2021-12-20 01:55:30 +01:00
allModems = Peripheral.instance.getModems();
2022-02-22 02:28:53 +01:00
2021-12-20 01:55:30 +01:00
open();
discoverNeighbors();
}
2022-02-21 15:35:37 +01:00
2022-02-24 02:05:43 +01:00
/**
Called when a new package comes in.
**/
2022-02-21 15:35:37 +01:00
private function handelIncomming(pack:Package, ?addr:String) {
2021-12-20 01:55:30 +01:00
switch pack.type {
case Data(_):
2022-02-24 02:05:43 +01:00
routeToProto(pack);
2021-12-20 01:55:30 +01:00
case DataNoResponse(_):
2022-02-24 02:05:43 +01:00
routeToProto(pack);
case Response:
if (responseBus.exists(pack.msgID)) {
2022-02-22 02:28:53 +01:00
responseBus[pack.msgID].invoke(pack);
}
2022-02-24 02:05:43 +01:00
case RouteDiscover(_) | RouteDiscoverResponse(_):
handleRouteDiscover(pack, addr);
2021-12-20 01:55:30 +01:00
}
}
2022-02-24 02:05:43 +01:00
private function newRoutDiscoverPackage():Package {
2022-02-21 15:35:37 +01:00
var pack:Package = {
2022-02-24 02:05:43 +01:00
type: RouteDiscover(getAllNeighbors()),
2021-12-20 01:55:30 +01:00
toID: BRODCAST_PORT,
msgID: generateMessageID(),
fromID: networkID,
data: null,
}
return pack;
}
2022-02-24 02:05:43 +01:00
/**
Send out discover packages on all modems.
**/
2021-12-20 01:55:30 +01:00
private function discoverNeighbors() {
for (modem in allModems) {
2022-02-24 02:05:43 +01:00
var pack = newRoutDiscoverPackage();
2021-12-20 01:55:30 +01:00
2022-02-24 02:05:43 +01:00
modem.transmit(BRODCAST_PORT, networkID, pack);
2021-12-20 01:55:30 +01:00
}
}
2022-02-24 02:05:43 +01:00
/**
Handle incomming packages that involve route discovery.
**/
private function handleRouteDiscover(pack:Package, addr:String) {
2022-02-21 15:35:37 +01:00
addRoute(pack.fromID, addr);
2022-02-24 02:05:43 +01:00
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");
}
2021-12-20 01:55:30 +01:00
// Respond to peer
2022-02-21 15:35:37 +01:00
var response:Package = {
2021-12-20 01:55:30 +01:00
toID: pack.fromID,
2022-02-24 02:05:43 +01:00
fromID: networkID,
2021-12-20 01:55:30 +01:00
msgID: pack.msgID,
2022-02-24 02:05:43 +01:00
type: RouteDiscoverResponse(forward),
2021-12-20 01:55:30 +01:00
data: null
}
for (reponseModem in allModems.filter(m -> m.addr == addr)) {
2022-02-21 15:35:37 +01:00
reponseModem.transmit(pack.fromID, networkID, response);
2021-12-20 01:55:30 +01:00
}
}
2022-02-24 02:05:43 +01:00
/**
Called when a route to a client has been disoverd.
Its posible to be called multiple times with the same id but different addr.
**/
2022-02-21 15:35:37 +01:00
private function addRoute(toID:Int, addr:String) {
2022-02-24 02:05:43 +01:00
Log.info("Added new route to " + toID + " via " + addr);
2022-02-21 15:35:37 +01:00
routingTable.set(toID, allModems.find(item -> item.addr == addr));
2022-02-22 02:28:53 +01:00
this.onNewNeigborTrigger.trigger(toID);
2021-12-20 01:55:30 +01:00
}
2022-02-21 15:35:37 +01:00
public function getAllNeighbors():Array<Int> {
2021-12-20 01:55:30 +01:00
return routingTable.mapi((index, item) -> index);
}
2022-02-21 15:35:37 +01:00
private function generateMessageID():Int {
2021-12-20 01:55:30 +01:00
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.
**/
2022-02-21 15:35:37 +01:00
public function sendAndForget(dest:Int, proto:String, data:Dynamic) {
var pack:Package = {
2021-12-20 01:55:30 +01:00
toID: dest,
fromID: networkID,
msgID: generateMessageID(),
type: DataNoResponse(proto),
data: data
}
sendRaw(pack);
}
2022-02-21 15:35:37 +01:00
public function respondTo(pack:Package, data:Dynamic) {
if (pack.type.match(DataNoResponse(_))) {
2021-12-20 01:55:30 +01:00
Log.warn("Responed to a no response package. Ignoring");
return;
}
var response = pack.createResponse(data);
sendRaw(response);
}
2022-02-24 02:05:43 +01:00
/**
Send to package to the localy register handler based on the proto
**/
private function routeToProto(pack:Package) {
2022-02-21 15:35:37 +01:00
var proto:String = switch pack.type {
2021-12-20 01:55:30 +01:00
case Data(proto):
proto;
case DataNoResponse(proto):
proto;
case _:
return;
}
2022-02-21 15:35:37 +01:00
if (!protoHandlers.exists(proto) && protoHandlers[proto] != null) {
2021-12-20 01:55:30 +01:00
return;
}
2022-02-22 02:28:53 +01:00
protoHandlers[proto].invoke(pack);
2021-12-20 01:55:30 +01:00
}
2022-02-24 02:05:43 +01:00
/**
Just send the package to the right modem.
**/
2022-02-21 15:35:37 +01:00
private function sendRaw(pack:Package) {
if (pack.toID == networkID) {
2021-12-20 01:55:30 +01:00
// Loopback
handelIncomming(pack);
2022-02-21 15:35:37 +01:00
} else {
if (routingTable.exists(pack.toID)) {
routingTable[pack.toID].transmit(pack.toID, pack.fromID, pack);
} else {
2021-12-20 01:55:30 +01:00
// Route not found
// TODO: forward package or report not reachable
}
}
}
2022-02-24 02:05:43 +01:00
/**
Send a message and wait for a response.
**/
public function sendAndAwait(dest:NetworkID, proto:String, data:Dynamic):Promise<Package> {
2021-12-20 01:55:30 +01:00
return new Promise<Package>((resolve, reject) -> {
2022-02-21 15:35:37 +01:00
var pack:Package = {
2021-12-20 01:55:30 +01:00
toID: dest,
fromID: networkID,
msgID: generateMessageID(),
type: Data(proto),
data: data
}
2022-02-21 15:35:37 +01:00
var timeout:Timer = null;
2022-02-22 02:28:53 +01:00
2022-02-24 02:05:43 +01:00
responseBus[pack.msgID] = ((reponse:Package) -> {
2022-02-22 02:28:53 +01:00
resolve(reponse);
2022-02-21 15:35:37 +01:00
if (timeout != null) {
2021-12-20 01:55:30 +01:00
timeout.cancle();
}
});
2022-02-21 15:35:37 +01:00
timeout = new Timer(MESSAGE_TIMEOUT, () -> {
2022-02-22 02:28:53 +01:00
responseBus.remove(pack.msgID);
2022-02-24 02:05:43 +01:00
reject(new Error(InternalError,"Message timeout"));
2021-12-20 01:55:30 +01:00
});
2022-02-21 15:35:37 +01:00
2021-12-20 01:55:30 +01:00
sendRaw(pack);
2022-02-24 02:05:43 +01:00
// No callback link for you
return null;
2021-12-20 01:55:30 +01:00
});
}
2022-02-22 02:28:53 +01:00
public function registerProto(proto:String, callback:Callback<Package>) {
2022-02-21 15:35:37 +01:00
if (protoHandlers.exists(proto)) {
2021-12-20 01:55:30 +01:00
// Failed. Handler already exist.
// TODO: return error
return;
}
2022-02-22 02:28:53 +01:00
protoHandlers[proto] = callback;
2021-12-20 01:55:30 +01:00
}
2022-02-21 15:35:37 +01:00
public function removeProto(proto:String) {
2021-12-20 01:55:30 +01:00
protoHandlers.remove(proto);
}
}