219 lines
5.0 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.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-24 19:47:27 +01:00
/**
Depends on: KernelEvents
**/
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;
2022-03-01 16:59:53 +01:00
public static inline final DEFAULT_TTL:Int = 10;
2021-12-20 01:55:30 +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-24 19:47:27 +01:00
private var interfaces:Array<INetworkInterface>;
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-24 19:47:27 +01:00
this.interfaces = [for (e in Peripheral.instance.getModems()) e ]; // TODO: is this the way to do it?
this.interfaces.push(Loopback.instance);
for (interf in interfaces){
2022-03-01 12:56:15 +01:00
setupInterf(interf);
2022-02-24 19:47:27 +01:00
}
2021-12-20 01:55:30 +01:00
}
2022-02-21 15:35:37 +01:00
2022-03-01 12:56:15 +01:00
private function setupInterf(interf: INetworkInterface) {
interf.onMessage.handle(pack -> handle(pack,interf));
interf.listen(networkID);
interf.listen(BRODCAST_PORT);
}
2022-02-24 02:05:43 +01:00
/**
Called when a new package comes in.
**/
2022-02-24 19:47:27 +01:00
private function handle(pack:Package,interf: INetworkInterface) {
2022-03-01 16:59:53 +01:00
if (pack.toID == this.networkID || pack.toID == Net.BRODCAST_PORT){
switch pack.type {
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);
}
2022-03-01 17:28:15 +01:00
case RouteDiscover(_) | RouteDiscoverResponse(_) | RouteDiscoverUpdate(_):
2022-03-01 16:59:53 +01:00
// Delegate to Routing
Routing.instance.handleRoutePackage(pack,interf);
}
}else{
// New message received but its not ment for us. Forward if possible.
forwardPackage(pack);
2021-12-20 01:55:30 +01:00
}
}
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
}
/**
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),
2022-03-01 16:59:53 +01:00
data: data,
ttl: Net.DEFAULT_TTL,
2021-12-20 01:55:30 +01:00
}
sendRaw(pack);
}
2022-03-01 16:59:53 +01:00
private function forwardPackage(pack: Package) {
if (pack.ttl == 0){
// Drop package
return;
}
pack.ttl--;
2022-03-02 11:51:17 +01:00
if (!sendRaw(pack)){
2022-03-01 16:59:53 +01:00
// Cant forward
}
}
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-03-01 16:59:53 +01:00
var proto = switch pack.type {
2021-12-20 01:55:30 +01:00
case Data(proto):
proto;
case DataNoResponse(proto):
proto;
2022-03-01 16:59:53 +01:00
default:
2021-12-20 01:55:30 +01:00
return;
}
2022-03-01 16:59:53 +01:00
if (!protoHandlers.exists(proto)) {
2022-03-04 13:28:25 +01:00
Log.warn('Trying to route package to proto: $proto but nothing was register');
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-03-01 16:59:53 +01:00
Returns true if message was send
2022-02-24 02:05:43 +01:00
**/
2022-03-01 16:59:53 +01:00
private function sendRaw(pack:Package): Bool {
var route = Routing.instance.getRouteToID(pack.toID);
if (route == null){
return false;
}
2022-02-24 19:47:27 +01:00
2022-03-01 16:59:53 +01:00
route.interf.send(route.rep,this.networkID,pack);
return true;
2021-12-20 01:55:30 +01:00
}
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),
2022-03-01 16:59:53 +01:00
data: data,
ttl: Net.DEFAULT_TTL,
2021-12-20 01:55:30 +01:00
}
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
2022-03-01 16:59:53 +01:00
if (!sendRaw(pack)){
reject(new Error("ID unreachable"));
}
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);
}
2022-12-17 15:08:07 +01:00
/**
Sends a ping package to the given id. Returns true if there was a response.
**/
public function ping(toID: NetworkID): Promise<Bool> {
return new Promise<Bool>((resolve,reject)->{
this.sendAndAwait(toID,"ping",null).map(pack -> {
switch pack {
case Success(_):
resolve(true);
case Failure(err):
resolve(false);
}
});
return null;
});
}
2021-12-20 01:55:30 +01:00
}