Compare commits
4 Commits
bca366d7e5
...
8318cc5c21
| Author | SHA1 | Date | |
|---|---|---|---|
| 8318cc5c21 | |||
| eb43c51e50 | |||
| d65b06a9b4 | |||
| 66aa84d896 |
@@ -24,6 +24,8 @@ run `make deps && make`. The `bundle.min.lua` inside the `build` dir is the fina
|
|||||||
|
|
||||||
[CC wiki](https://tweaked.cc/)
|
[CC wiki](https://tweaked.cc/)
|
||||||
|
|
||||||
|
[Tinkerbell Core Library](https://haxetink.github.io/tink_core/#/)
|
||||||
|
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
There are a couple of tool to your disposal that makes working easier.
|
There are a couple of tool to your disposal that makes working easier.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Net {
|
|||||||
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 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<Package>> = new Map();
|
private final responseBus:Map<Int, Callback<Package>> = new Map();
|
||||||
@@ -48,6 +49,7 @@ class Net {
|
|||||||
Called when a new package comes in.
|
Called when a new package comes in.
|
||||||
**/
|
**/
|
||||||
private function handle(pack:Package,interf: INetworkInterface) {
|
private function handle(pack:Package,interf: INetworkInterface) {
|
||||||
|
if (pack.toID == this.networkID || pack.toID == Net.BRODCAST_PORT){
|
||||||
switch pack.type {
|
switch pack.type {
|
||||||
case Data(_) | DataNoResponse(_):
|
case Data(_) | DataNoResponse(_):
|
||||||
// Let a local proccess handle it
|
// Let a local proccess handle it
|
||||||
@@ -57,10 +59,14 @@ class Net {
|
|||||||
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(_) | RouteDiscoverUpdate(_):
|
||||||
// Delegate to Routing
|
// Delegate to Routing
|
||||||
Routing.instance.handleRoutePackage(pack,interf);
|
Routing.instance.handleRoutePackage(pack,interf);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
// New message received but its not ment for us. Forward if possible.
|
||||||
|
forwardPackage(pack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateMessageID():Int {
|
private function generateMessageID():Int {
|
||||||
@@ -76,12 +82,26 @@ class Net {
|
|||||||
fromID: networkID,
|
fromID: networkID,
|
||||||
msgID: generateMessageID(),
|
msgID: generateMessageID(),
|
||||||
type: DataNoResponse(proto),
|
type: DataNoResponse(proto),
|
||||||
data: data
|
data: data,
|
||||||
|
ttl: Net.DEFAULT_TTL,
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRaw(pack);
|
sendRaw(pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function forwardPackage(pack: Package) {
|
||||||
|
if (pack.ttl == 0){
|
||||||
|
// Drop package
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pack.ttl--;
|
||||||
|
|
||||||
|
if (sendRaw(pack)){
|
||||||
|
// Cant forward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function respondTo(pack:Package, data:Dynamic) {
|
public function respondTo(pack:Package, 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");
|
||||||
@@ -97,16 +117,17 @@ 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:Package) {
|
||||||
var proto:String = switch pack.type {
|
var proto = switch pack.type {
|
||||||
case Data(proto):
|
case Data(proto):
|
||||||
proto;
|
proto;
|
||||||
case DataNoResponse(proto):
|
case DataNoResponse(proto):
|
||||||
proto;
|
proto;
|
||||||
case _:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!protoHandlers.exists(proto) && protoHandlers[proto] != null) {
|
if (!protoHandlers.exists(proto)) {
|
||||||
|
Log.warn("Trying to route package to proto: \"" + proto + "\" but nothing was register");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,24 +136,30 @@ class Net {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Just send the package to the right modem.
|
Just send the package to the right modem.
|
||||||
|
Returns true if message was send
|
||||||
**/
|
**/
|
||||||
private function sendRaw(pack:Package) {
|
private function sendRaw(pack:Package): Bool {
|
||||||
|
var route = Routing.instance.getRouteToID(pack.toID);
|
||||||
|
if (route == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Routing.instance.getIterfaceToId(pack.toID).send(pack.toID,pack.fromID,pack);
|
route.interf.send(route.rep,this.networkID,pack);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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(dest:NetworkID, proto:String, data:Dynamic):Promise<Package> {
|
||||||
|
|
||||||
return new Promise<Package>((resolve, reject) -> {
|
return new Promise<Package>((resolve, reject) -> {
|
||||||
var pack:Package = {
|
var pack:Package = {
|
||||||
toID: dest,
|
toID: dest,
|
||||||
fromID: networkID,
|
fromID: networkID,
|
||||||
msgID: generateMessageID(),
|
msgID: generateMessageID(),
|
||||||
type: Data(proto),
|
type: Data(proto),
|
||||||
data: data
|
data: data,
|
||||||
|
ttl: Net.DEFAULT_TTL,
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout:Timer = null;
|
var timeout:Timer = null;
|
||||||
@@ -149,7 +176,9 @@ class Net {
|
|||||||
reject(new Error(InternalError,"Message timeout"));
|
reject(new Error(InternalError,"Message timeout"));
|
||||||
});
|
});
|
||||||
|
|
||||||
sendRaw(pack);
|
if (!sendRaw(pack)){
|
||||||
|
reject(new Error("ID unreachable"));
|
||||||
|
}
|
||||||
|
|
||||||
// No callback link for you
|
// No callback link for you
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ enum PackageTypes {
|
|||||||
Response;
|
Response;
|
||||||
RouteDiscover(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
RouteDiscover(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||||
RouteDiscoverResponse(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
RouteDiscoverResponse(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||||
|
RouteDiscoverUpdate(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,6 +20,7 @@ enum PackageTypes {
|
|||||||
public final msgID:Int;
|
public final msgID:Int;
|
||||||
public final type:PackageTypes;
|
public final type:PackageTypes;
|
||||||
public final data:Dynamic;
|
public final data:Dynamic;
|
||||||
|
public var ttl: Int;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Parse package from an `modem_message` event.
|
Parse package from an `modem_message` event.
|
||||||
@@ -32,6 +34,7 @@ enum PackageTypes {
|
|||||||
msgID: payload.msgID,
|
msgID: payload.msgID,
|
||||||
type: payload.type,
|
type: payload.type,
|
||||||
data: payload.data,
|
data: payload.data,
|
||||||
|
ttl: payload.ttl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +47,8 @@ enum PackageTypes {
|
|||||||
fromID: toID,
|
fromID: toID,
|
||||||
msgID: msgID,
|
msgID: msgID,
|
||||||
type: Response,
|
type: Response,
|
||||||
data: newData
|
data: newData,
|
||||||
|
ttl: Net.DEFAULT_TTL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import kernel.net.Package.NetworkID;
|
|||||||
|
|
||||||
@:structInit typedef Route = {
|
@:structInit typedef Route = {
|
||||||
interf:INetworkInterface,
|
interf:INetworkInterface,
|
||||||
|
rep: NetworkID,
|
||||||
cost:Int
|
cost:Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +22,13 @@ class Routing {
|
|||||||
**/
|
**/
|
||||||
public static var instance:Routing;
|
public static var instance:Routing;
|
||||||
|
|
||||||
|
public static inline final UPDATE_WAIT_TIME:Float = 3;
|
||||||
|
|
||||||
public final onNewNeigbor:Signal<Int>;
|
public final onNewNeigbor:Signal<Int>;
|
||||||
|
|
||||||
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
||||||
private final routingTable:Map<NetworkID, Route> = new Map();
|
private final routingTable:Map<NetworkID, Route> = new Map();
|
||||||
|
private var routeUpdateInQueue: Bool = false;
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private function new() {
|
private function new() {
|
||||||
@@ -33,29 +37,63 @@ class Routing {
|
|||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private function init() {
|
private function init() {
|
||||||
routingTable.set(Net.instance.networkID,{interf: Loopback.instance,cost:0});
|
routingTable.set(Net.instance.networkID,{interf: Loopback.instance,cost:0,rep:Net.instance.networkID});
|
||||||
for (modem in Peripheral.instance.getModems()) {
|
for (modem in Peripheral.instance.getModems()) {
|
||||||
modem.send(Net.BRODCAST_PORT, Net.instance.networkID, newRoutDiscoverPackage());
|
modem.send(Net.BRODCAST_PORT, Net.instance.networkID, newRoutDiscoverPackage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function prepareRouteUpdate() {
|
||||||
|
if (this.routeUpdateInQueue){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.routeUpdateInQueue = true;
|
||||||
|
|
||||||
|
new Timer(UPDATE_WAIT_TIME,()->{
|
||||||
|
brodcastUpdatedRoutes();
|
||||||
|
this.routeUpdateInQueue = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function brodcastUpdatedRoutes() {
|
||||||
|
var pack: Package = {
|
||||||
|
type: RouteDiscoverUpdate(genRouteList()),
|
||||||
|
toID: Net.BRODCAST_PORT,
|
||||||
|
msgID: null,
|
||||||
|
fromID: Net.instance.networkID,
|
||||||
|
data: null,
|
||||||
|
ttl: 0, // Prevent forwarding
|
||||||
|
};
|
||||||
|
|
||||||
|
for (modem in Peripheral.instance.getModems()) {
|
||||||
|
|
||||||
|
modem.send(Net.BRODCAST_PORT, Net.instance.networkID,pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Handle incomming packages that involve route discovery.
|
Handle incomming packages that involve route discovery.
|
||||||
**/
|
**/
|
||||||
public function handleRoutePackage(pack:Package, interf:INetworkInterface):Void {
|
public function handleRoutePackage(pack:Package, interf:INetworkInterface):Void {
|
||||||
addPossibleRoute(pack.fromID,interf,0);
|
addPossibleRoute(pack.fromID,interf,0,pack.fromID);
|
||||||
|
|
||||||
var shouldRespond: Bool = switch pack.type {
|
var shouldRespond: Bool = switch pack.type {
|
||||||
case RouteDiscoverResponse(routes):
|
case RouteDiscoverResponse(routes):
|
||||||
for (route in routes) {
|
for (route in routes) {
|
||||||
addPossibleRoute(route.id,interf,route.cost);
|
addPossibleRoute(route.id,interf,route.cost,pack.fromID);
|
||||||
}
|
}
|
||||||
false;
|
false;
|
||||||
case RouteDiscover(routes):
|
case RouteDiscover(routes):
|
||||||
for (route in routes) {
|
for (route in routes) {
|
||||||
addPossibleRoute(route.id,interf,route.cost);
|
addPossibleRoute(route.id,interf,route.cost,pack.fromID);
|
||||||
}
|
}
|
||||||
true;
|
true;
|
||||||
|
case RouteDiscoverUpdate(routes):
|
||||||
|
for (route in routes) {
|
||||||
|
addPossibleRoute(route.id,interf,route.cost,pack.fromID);
|
||||||
|
}
|
||||||
|
false;
|
||||||
default:
|
default:
|
||||||
Log.error("Expected RouteDiscover or RouteDiscoverResponse type");
|
Log.error("Expected RouteDiscover or RouteDiscoverResponse type");
|
||||||
false;
|
false;
|
||||||
@@ -71,7 +109,8 @@ class Routing {
|
|||||||
fromID: Net.instance.networkID,
|
fromID: Net.instance.networkID,
|
||||||
msgID: null,
|
msgID: null,
|
||||||
type: RouteDiscoverResponse(genRouteList()),
|
type: RouteDiscoverResponse(genRouteList()),
|
||||||
data: null
|
data: null,
|
||||||
|
ttl: 0, // Prevent forwarding
|
||||||
}
|
}
|
||||||
|
|
||||||
interf.send(response.toID,Net.instance.networkID,response);
|
interf.send(response.toID,Net.instance.networkID,response);
|
||||||
@@ -95,6 +134,7 @@ class Routing {
|
|||||||
msgID: null,
|
msgID: null,
|
||||||
fromID: Net.instance.networkID,
|
fromID: Net.instance.networkID,
|
||||||
data: null,
|
data: null,
|
||||||
|
ttl: 0, // Prevent forwarding
|
||||||
}
|
}
|
||||||
|
|
||||||
return pack;
|
return pack;
|
||||||
@@ -104,7 +144,7 @@ class Routing {
|
|||||||
Called when a route to a client has been disoverd.
|
Called when a route to a client has been disoverd.
|
||||||
Its possible to be called multiple times with the same id but different addr.
|
Its possible to be called multiple times with the same id but different addr.
|
||||||
**/
|
**/
|
||||||
private function addPossibleRoute(toID:Int, interf:INetworkInterface, cost:Int) {
|
private function addPossibleRoute(toID:Int, interf:INetworkInterface, cost:Int, rep: NetworkID) {
|
||||||
if (toID == Net.instance.networkID){
|
if (toID == Net.instance.networkID){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -114,20 +154,28 @@ class Routing {
|
|||||||
if (this.routingTable.exists(toID)){
|
if (this.routingTable.exists(toID)){
|
||||||
if (this.routingTable[toID].cost > fullCost){
|
if (this.routingTable[toID].cost > fullCost){
|
||||||
Log.info("Better route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
Log.info("Better route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
||||||
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()};
|
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost(),rep: rep};
|
||||||
|
this.prepareRouteUpdate();
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()};
|
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost(),rep: rep};
|
||||||
Log.info("New route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
Log.info("New route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
||||||
this.onNewNeigborTrigger.trigger(toID);
|
this.onNewNeigborTrigger.trigger(toID);
|
||||||
|
this.prepareRouteUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getIterfaceToId(networkID:NetworkID):INetworkInterface {
|
public function getRouteToID(networkID:NetworkID):{interf: INetworkInterface, rep: NetworkID} {
|
||||||
if (networkID == Net.instance.networkID) {
|
if (networkID == Net.instance.networkID) {
|
||||||
return Loopback.instance;
|
return {interf: Loopback.instance,rep: Net.instance.networkID};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var route = this.routingTable[networkID];
|
||||||
|
|
||||||
|
if (route == null){
|
||||||
return null;
|
return null;
|
||||||
|
}else{
|
||||||
|
return {interf: route.interf,rep: route.rep};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class Modem implements INetworkInterface implements IPeripheral {
|
|||||||
msgID: params.message.msgID,
|
msgID: params.message.msgID,
|
||||||
type: params.message.type,
|
type: params.message.type,
|
||||||
data: params.message.data,
|
data: params.message.data,
|
||||||
|
ttl: params.message.ttl,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onMessageTrigger.trigger(pack);
|
this.onMessageTrigger.trigger(pack);
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package util;
|
package util;
|
||||||
|
|
||||||
import cc.HTTP;
|
|
||||||
import kernel.net.Net;
|
|
||||||
import cc.ComputerCraft;
|
import cc.ComputerCraft;
|
||||||
import kernel.Log;
|
import kernel.Log;
|
||||||
|
#if webconsole
|
||||||
|
import cc.HTTP;
|
||||||
|
import kernel.net.Net;
|
||||||
|
#end
|
||||||
|
|
||||||
class Debug {
|
class Debug {
|
||||||
public static function printBuildInfo() {
|
public static function printBuildInfo() {
|
||||||
@@ -18,7 +20,7 @@ class Debug {
|
|||||||
|
|
||||||
#if webconsole
|
#if webconsole
|
||||||
public static function printWeb(msg:String) {
|
public static function printWeb(msg:String) {
|
||||||
HTTP.post("http://127.0.0.1:8080/"+Net.instance.networkID, msg);
|
HTTP.request("http://127.0.0.1:8080/"+Net.instance.networkID,msg);
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user