Compare commits

..

8 Commits

Author SHA1 Message Date
7c7529ae39 use new kernel settings 2023-06-07 21:29:29 +02:00
6fcbcfce8d added kernel settings 2023-06-07 21:29:10 +02:00
86793bfdc1 terminal kill runnig apps 2023-06-07 20:10:51 +02:00
644ebe1c05 improved HelloWord service 2023-06-07 20:09:54 +02:00
7aa5698486 improved Processhandle 2023-06-07 20:09:34 +02:00
9a9041bd98 killing non existing process does not throw error 2023-06-07 20:07:37 +02:00
f92d777ee1 added EndOfLoop 2023-06-07 20:07:03 +02:00
f85ff77728 added energyStorage perf 2023-06-07 15:15:50 +02:00
14 changed files with 263 additions and 75 deletions

View File

@@ -1,24 +1,24 @@
package bin; package bin;
import kernel.service.ServiceManager;
import kernel.log.Log;
import kernel.Timer; import kernel.Timer;
import kernel.ps.ProcessHandle; import kernel.ps.ProcessHandle;
import kernel.ps.Process; import kernel.ps.Process;
class HelloWorldService implements Process { class HelloWorldService implements Process {
private var timer:Timer;
public function new() {} public function new() {}
public function run(handle:ProcessHandle) { public function run(handle:ProcessHandle) {
Log.debug("HelloWorldService started");
handle.write("Hello World! Started\n"); handle.write("Hello World! Started\n");
// this.startTimer(handle); this.startTimer(handle);
var srv: HelloWorldService = ServiceManager.instance.get("HelloWorldService"); handle.addDeferFunc(()->{
srv.startTimer(handle); timer.cancle();
});
} }
public function startTimer(handle: ProcessHandle) { public function startTimer(handle: ProcessHandle) {
new Timer(1000, function() { this.timer = new Timer(5, function() {
handle.write("Hello World!\n"); handle.write("Hello World!\n");
this.startTimer(handle); this.startTimer(handle);
}); });

67
src/bin/KSettings.hx Normal file
View File

@@ -0,0 +1,67 @@
package bin;
import kernel.KernelSettings;
import lib.CLIAppBase;
class KSettings extends CLIAppBase {
public function new() {
registerSyncSubcommand("get", (args)->{
var key = args[0];
if (key == null) {
handle.writeLine("Key not specified");
return false;
}
var value = switch (key){
case "hostname":
KernelSettings.hostname;
case "sitecontroller":
Std.string(KernelSettings.siteController);
default:
null;
}
if (value == null) {
handle.writeLine("Key not found or not set");
return false;
}
handle.writeLine(value);
return true;
}," <key>");
registerSyncSubcommand("set", (args)->{
var key = args[0];
if (key == null) {
handle.writeLine("Key not specified");
return false;
}
var value = args[1];
if (value == null) {
handle.writeLine("Value not specified");
return false;
}
switch (key){
case "hostname":
KernelSettings.hostname = value;
case "sitecontroller":
KernelSettings.siteController = Std.parseInt(value);
default:
handle.writeLine("Key not found");
return false;
}
return true;
}," <key> <value>");
registerSyncSubcommand("list", (args)->{
handle.writeLine("hostname");
handle.writeLine("sitecontroller");
return true;
});
}
}

View File

@@ -1,5 +1,6 @@
package bin; package bin;
import kernel.log.Log;
import kernel.binstore.BinStore; import kernel.binstore.BinStore;
import kernel.ps.ProcessHandle; import kernel.ps.ProcessHandle;
import kernel.ps.Process; import kernel.ps.Process;
@@ -15,6 +16,7 @@ class Terminal implements Process {
private var backlog:Array<String> = []; private var backlog:Array<String> = [];
private var handle:ProcessHandle; private var handle:ProcessHandle;
private var requestRender: () -> Void; private var requestRender: () -> Void;
private var runningPID:PID = -1;
public function new() {} public function new() {}
@@ -28,27 +30,41 @@ class Terminal implements Process {
statelessContext.setRenderFunc(this.render); statelessContext.setRenderFunc(this.render);
this.context.onChar.handle(char -> { handle.addCallbackLink(this.context.onChar.handle(char -> {
if (this.runningPID > 0) return;
this.input += char; this.input += char;
this.requestRender(); this.requestRender();
}); }));
this.context.onKey.handle(e -> { handle.addCallbackLink(this.context.onKey.handle(e -> {
if (e.keyCode == 259) { // Backspace switch (e.keyCode) {
case 259: // Backspace
if (this.runningPID > 0) return;
this.input = this.input.substr(0, this.input.length - 1); this.input = this.input.substr(0, this.input.length - 1);
this.requestRender(); this.requestRender();
} else if (e.keyCode == 257) { // Enter case 257: // Enter
if (this.runningPID > 0) return;
this.backlog.push("> " + this.input); this.backlog.push("> " + this.input);
var command = this.input; var command = this.input;
this.input = ""; this.input = "";
this.requestRender(); this.requestRender();
this.invokeCommand(command); this.invokeCommand(command);
case 269: // END
this.stopCurrentPS();
} }
}); }));
this.requestRender(); this.requestRender();
} }
private function stopCurrentPS() {
if (this.runningPID < 0) {
return;
}
ProcessManager.kill(this.runningPID);
}
private function render() { private function render() {
redrawBacklog(); redrawBacklog();
redrawInput(); redrawInput();
@@ -114,7 +130,7 @@ class Terminal implements Process {
return; return;
} }
ProcessManager.run(ps,{ this.runningPID = ProcessManager.run(ps,{
args: commandArgs, args: commandArgs,
onWrite: (s:String) -> { onWrite: (s:String) -> {
if (s == "") { if (s == "") {
@@ -138,6 +154,7 @@ class Terminal implements Process {
this.requestRender(); this.requestRender();
}, },
onExit: (success:Bool) -> { onExit: (success:Bool) -> {
this.runningPID = -1;
if (this.backlog[this.backlog.length - 1] == "") { if (this.backlog[this.backlog.length - 1] == "") {
this.backlog.pop(); this.backlog.pop();
} }

View File

@@ -9,18 +9,12 @@ using tink.CoreApi;
class CLI extends CLIAppBase { class CLI extends CLIAppBase {
public function new() { public function new() {
registerAsyncSubcommand("get", (args) -> { registerAsyncSubcommand("get", (args) -> {
if (args.length < 2) { if (args.length < 1) {
handle.writeLine("Not enough arguments"); handle.writeLine("Not enough arguments");
return Future.sync(false); return Future.sync(false);
} }
var id:NetworkID = Std.parseInt(args[0]); return RessourceNames.get(args[0]).map((res) -> {
if (id == null) {
handle.writeLine("Invalid id");
return Future.sync(false);
}
return RessourceNames.get(args[1], id).map((res) -> {
switch (res) { switch (res) {
case Success(data): case Success(data):
if (data == null) { if (data == null) {
@@ -33,51 +27,21 @@ class CLI extends CLIAppBase {
} }
return true; return true;
}); });
}, "<id> <name>"); }, "<name>");
registerAsyncSubcommand("register", (args) -> { registerAsyncSubcommand("register", (args) -> {
if (args.length < 3) {
handle.writeLine("Not enough arguments");
return Future.sync(false);
}
var id:NetworkID = Std.parseInt(args[0]);
if (id == null) {
handle.writeLine("Invalid id");
return Future.sync(false);
}
var id2:NetworkID = Std.parseInt(args[2]);
if (id2 == null) {
handle.writeLine("Invalid id");
return Future.sync(false);
}
return RessourceNames.register(args[1], id2, id).map((res) -> {
switch (res) {
case Success(data):
handle.writeLine("Success");
case Failure(error):
handle.writeLine("Error: " + error);
}
return true;
});
}, "<id> <name> <id>");
registerAsyncSubcommand("unregister", (args) -> {
if (args.length < 2) { if (args.length < 2) {
handle.writeLine("Not enough arguments"); handle.writeLine("Not enough arguments");
return Future.sync(false); return Future.sync(false);
} }
var id:NetworkID = Std.parseInt(args[0]); var id:NetworkID = Std.parseInt(args[1]);
if (id == null) { if (id == null) {
handle.writeLine("Invalid id"); handle.writeLine("Invalid id");
return Future.sync(false); return Future.sync(false);
} }
return RessourceNames.unregister(args[1], id).map((res) -> { return RessourceNames.register(args[0], id).map((res) -> {
switch (res) { switch (res) {
case Success(data): case Success(data):
handle.writeLine("Success"); handle.writeLine("Success");
@@ -87,6 +51,24 @@ class CLI extends CLIAppBase {
return true; return true;
}); });
}, "<id> <name>"); }, "<name> <id>");
registerAsyncSubcommand("unregister", (args) -> {
if (args.length < 1) {
handle.writeLine("Not enough arguments");
return Future.sync(false);
}
return RessourceNames.unregister(args[0]).map((res) -> {
switch (res) {
case Success(data):
handle.writeLine("Success");
case Failure(error):
handle.writeLine("Error: " + error);
}
return true;
});
}, "<name>");
} }
} }

View File

@@ -19,6 +19,7 @@ class DCEHack {
new bin.srsc.SiteRessourceController(), new bin.srsc.SiteRessourceController(),
new bin.srsc.CLI(), new bin.srsc.CLI(),
new bin.Perf(), new bin.Perf(),
new bin.KSettings(),
]; ];
} }
} }

24
src/kernel/EndOfLoop.hx Normal file
View File

@@ -0,0 +1,24 @@
package kernel;
import cc.OS;
/**
Make sure that a function is called at the end of the current event loop.
Like setTimeout(func, 0) in JavaScript.
**/
class EndOfLoop {
private static var backlog:Array<Void -> Void> = [];
private static var isQueued = false;
public static function endOfLoop(func: Void -> Void) {
backlog.push(func);
if (!isQueued) { OS.queueEvent("endofloop", null); }
}
@:allow(kernel.KernelEvents)
private static function run() {
for (func in backlog) { func(); }
backlog = [];
isQueued = false;
}
}

View File

@@ -228,6 +228,8 @@ class KernelEvents {
this.onWebsocketMessageTrigger.trigger({url: event[2], message: event[3], isBinary: event[4]}); this.onWebsocketMessageTrigger.trigger({url: event[2], message: event[3], isBinary: event[4]});
case "websocket_success": case "websocket_success":
this.onWebsocketSuccessTrigger.trigger({url: event[2], handle: event[3]}); this.onWebsocketSuccessTrigger.trigger({url: event[2], handle: event[3]});
case "endofloop":
EndOfLoop.run();
default: default:
Log.error('Unknown event: $eventName'); Log.error('Unknown event: $eventName');
} }

View File

@@ -0,0 +1,56 @@
package kernel;
import cc.OS;
import kernel.net.Package.NetworkID;
import lib.KVStore;
import cc.Settings;
class KernelSettings {
private static inline function setAllowStartup(value: Bool) {
Settings.set("shell.allow_startup", value);
}
private static inline function setAllowStartupFromFloppy(value: Bool) {
Settings.set("shell.allow_disk_startup", value);
}
private static function set(name: String, value: Dynamic) {
var kvstore = new KVStore("kernel");
kvstore.set(name, value);
kvstore.save();
}
private static function get(name: String): Null<Dynamic> {
var kvstore = new KVStore("kernel");
return kvstore.get(name);
}
public static var hostname(get,set): String;
private static var _hostname:String = get("hostname");
private static inline function get_hostname():String {
return _hostname;
}
private static inline function set_hostname(value:String):String {
OS.setComputerLabel(value);
set("hostname", value);
_hostname = value;
return value;
}
public static var siteController(get,set): NetworkID;
private static var _siteController:NetworkID = get("siteController");
private static function get_siteController():NetworkID {
return _siteController;
}
private static function set_siteController(value:NetworkID):NetworkID {
if (value == null) {
return get_siteController();
}
set("siteController", value);
_siteController = value;
return value;
}
}

View File

@@ -1,5 +1,6 @@
package kernel.binstore; package kernel.binstore;
import bin.KSettings;
import bin.Perf; import bin.Perf;
import bin.srsc.CLI; import bin.srsc.CLI;
import bin.srsc.SiteRessourceController; import bin.srsc.SiteRessourceController;
@@ -33,7 +34,8 @@ class BinStore {
{c: HelloWorldService, name: "HelloWorldService", aliases: ["hello-service"] }, {c: HelloWorldService, name: "HelloWorldService", aliases: ["hello-service"] },
{c: SiteRessourceController, name: "SiteRessourceController", aliases: ["srsc"]}, {c: SiteRessourceController, name: "SiteRessourceController", aliases: ["srsc"]},
{c: CLI, name: "SRSC CLI", aliases: ["srsc-cli"]}, {c: CLI, name: "SRSC CLI", aliases: ["srsc-cli"]},
{c: Perf, name: "Perf", aliases: ["perf"]} {c: Perf, name: "Perf", aliases: ["perf"]},
{c: KSettings, name: "KSettings", aliases: ["ksettings","ks"]},
]; ];
@:allow(kernel.Init) @:allow(kernel.Init)

View File

@@ -0,0 +1,25 @@
package kernel.peripherals;
class EnergyStorage implements IPeripheral{
public static inline final TYPE_NAME:String = "energyCell";
private final addr:String;
private final native: cc.periphs.EnergyStorage;
public function new(addr: String) {
this.addr = addr;
this.native = cc.Peripheral.wrap(addr);
}
public function getEnergy(): Int {
return this.native.getEnergy();
}
public function getEnergyCapacity(): Int {
return this.native.getEnergyCapacity();
}
public function getAddr():String {
return this.addr;
}
}

View File

@@ -1,6 +1,5 @@
package kernel.peripherals; package kernel.peripherals;
import haxe.ds.ReadOnlyArray;
import kernel.peripherals.Modem; import kernel.peripherals.Modem;
import kernel.peripherals.Screen; import kernel.peripherals.Screen;

View File

@@ -21,6 +21,8 @@ class ProcessHandle {
private var closeFutureResolev: Bool -> Void; private var closeFutureResolev: Bool -> Void;
private final windowContexts: Array<WindowContext> = []; private final windowContexts: Array<WindowContext> = [];
private final cbLinks:Array<CallbackLink> = []; private final cbLinks:Array<CallbackLink> = [];
private final deferFuncs:Array<Void -> Void> = [];
private var hasExited: Bool = false;
@:allow(kernel.ps.ProcessManager) @:allow(kernel.ps.ProcessManager)
private function new(config: HandleConfig,pid: PID) { private function new(config: HandleConfig,pid: PID) {
@@ -42,12 +44,15 @@ class ProcessHandle {
} }
public function close(success: Bool = true): Void { public function close(success: Bool = true): Void {
this.hasExited = true;
this.dispose(); this.dispose();
this.closeFutureResolev(success);
EndOfLoop.endOfLoop(() ->{this.closeFutureResolev(success);});
ProcessManager.removeProcess(this.pid); ProcessManager.removeProcess(this.pid);
} }
public function write(message: String): Void { public function write(message: String): Void {
if (this.hasExited) return;
if (this.config.onWrite != null){ if (this.config.onWrite != null){
this.config.onWrite.invoke(message); this.config.onWrite.invoke(message);
} }
@@ -77,6 +82,10 @@ class ProcessHandle {
for (link in this.cbLinks) { for (link in this.cbLinks) {
link.cancel(); link.cancel();
} }
for (func in this.deferFuncs) {
func();
}
} }
public function getPid(): PID { public function getPid(): PID {
@@ -87,6 +96,10 @@ class ProcessHandle {
this.cbLinks.push(link); this.cbLinks.push(link);
} }
public function addDeferFunc(func: Void -> Void) {
this.deferFuncs.push(func);
}
function get_args():ReadOnlyArray<String> { function get_args():ReadOnlyArray<String> {
return this.config.args; return this.config.args;
} }

View File

@@ -28,7 +28,8 @@ class ProcessManager {
public static function kill(pid: PID) { public static function kill(pid: PID) {
if (!processList.exists(pid)){ if (!processList.exists(pid)){
throw new Error("Process with PID " + pid + " does not exist"); Log.warn("Trying to kill non-existing process: " + pid);
return;
} }
var handle = processList.get(pid); var handle = processList.get(pid);

View File

@@ -1,5 +1,6 @@
package lib; package lib;
import kernel.KernelSettings;
import bin.srsc.PackageTypes.UnregisterRequest; import bin.srsc.PackageTypes.UnregisterRequest;
import kernel.log.Log; import kernel.log.Log;
import bin.srsc.PackageTypes.RegisterRequest; import bin.srsc.PackageTypes.RegisterRequest;
@@ -11,15 +12,13 @@ import kernel.net.Package.NetworkID;
using tink.CoreApi; using tink.CoreApi;
class RessourceNames { class RessourceNames {
private static final SITE_CONTROLLER:NetworkID = 0; // Temporary TODO: Change to real ID
public static function get(name: String, controllerID: NetworkID = -1): Promise<Null<NetworkID>> { public static function get(name: String, controllerID: NetworkID = -1): Promise<Null<NetworkID>> {
if (controllerID == -1) controllerID = SITE_CONTROLLER; if (controllerID == -1) controllerID = KernelSettings.siteController;
var payload: GetRequest = {name: name, type: "get"}; var payload: GetRequest = {name: name, type: "get"};
return Net.instance.sendAndAwait( return Net.instance.sendAndAwait(
SITE_CONTROLLER, controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO, SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload payload
).map((res)->{ ).map((res)->{
@@ -33,12 +32,12 @@ class RessourceNames {
} }
public static function register(name: String, netID: NetworkID, controllerID: NetworkID = -1): Promise<Bool> { public static function register(name: String, netID: NetworkID, controllerID: NetworkID = -1): Promise<Bool> {
if (controllerID == -1) controllerID = SITE_CONTROLLER; if (controllerID == -1) controllerID = KernelSettings.siteController;
var payload: RegisterRequest = {name: name, netID: netID, type: "register"}; var payload: RegisterRequest = {name: name, netID: netID, type: "register"};
return Net.instance.sendAndAwait( return Net.instance.sendAndAwait(
SITE_CONTROLLER, controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO, SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload payload
).map((res)->{ ).map((res)->{
@@ -53,12 +52,12 @@ class RessourceNames {
} }
public static function unregister(name: String, controllerID: NetworkID = -1): Promise<Noise> { public static function unregister(name: String, controllerID: NetworkID = -1): Promise<Noise> {
if (controllerID == -1) controllerID = SITE_CONTROLLER; if (controllerID == -1) controllerID = KernelSettings.siteController;
var payload: UnregisterRequest = {name: name, type: "unregister"}; var payload: UnregisterRequest = {name: name, type: "unregister"};
return Net.instance.sendAndAwait( return Net.instance.sendAndAwait(
SITE_CONTROLLER, controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO, SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload payload
); );