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;
import kernel.service.ServiceManager;
import kernel.log.Log;
import kernel.Timer;
import kernel.ps.ProcessHandle;
import kernel.ps.Process;
class HelloWorldService implements Process {
private var timer:Timer;
public function new() {}
public function run(handle:ProcessHandle) {
Log.debug("HelloWorldService started");
handle.write("Hello World! Started\n");
// this.startTimer(handle);
var srv: HelloWorldService = ServiceManager.instance.get("HelloWorldService");
srv.startTimer(handle);
this.startTimer(handle);
handle.addDeferFunc(()->{
timer.cancle();
});
}
public function startTimer(handle: ProcessHandle) {
new Timer(1000, function() {
this.timer = new Timer(5, function() {
handle.write("Hello World!\n");
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;
import kernel.log.Log;
import kernel.binstore.BinStore;
import kernel.ps.ProcessHandle;
import kernel.ps.Process;
@@ -15,6 +16,7 @@ class Terminal implements Process {
private var backlog:Array<String> = [];
private var handle:ProcessHandle;
private var requestRender: () -> Void;
private var runningPID:PID = -1;
public function new() {}
@@ -28,27 +30,41 @@ class Terminal implements Process {
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.requestRender();
});
}));
this.context.onKey.handle(e -> {
if (e.keyCode == 259) { // Backspace
handle.addCallbackLink(this.context.onKey.handle(e -> {
switch (e.keyCode) {
case 259: // Backspace
if (this.runningPID > 0) return;
this.input = this.input.substr(0, this.input.length - 1);
this.requestRender();
} else if (e.keyCode == 257) { // Enter
case 257: // Enter
if (this.runningPID > 0) return;
this.backlog.push("> " + this.input);
var command = this.input;
this.input = "";
this.requestRender();
this.invokeCommand(command);
case 269: // END
this.stopCurrentPS();
}
});
}));
this.requestRender();
}
private function stopCurrentPS() {
if (this.runningPID < 0) {
return;
}
ProcessManager.kill(this.runningPID);
}
private function render() {
redrawBacklog();
redrawInput();
@@ -114,7 +130,7 @@ class Terminal implements Process {
return;
}
ProcessManager.run(ps,{
this.runningPID = ProcessManager.run(ps,{
args: commandArgs,
onWrite: (s:String) -> {
if (s == "") {
@@ -138,6 +154,7 @@ class Terminal implements Process {
this.requestRender();
},
onExit: (success:Bool) -> {
this.runningPID = -1;
if (this.backlog[this.backlog.length - 1] == "") {
this.backlog.pop();
}

View File

@@ -9,18 +9,12 @@ using tink.CoreApi;
class CLI extends CLIAppBase {
public function new() {
registerAsyncSubcommand("get", (args) -> {
if (args.length < 2) {
if (args.length < 1) {
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);
}
return RessourceNames.get(args[1], id).map((res) -> {
return RessourceNames.get(args[0]).map((res) -> {
switch (res) {
case Success(data):
if (data == null) {
@@ -33,51 +27,21 @@ class CLI extends CLIAppBase {
}
return true;
});
}, "<id> <name>");
}, "<name>");
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) {
handle.writeLine("Not enough arguments");
return Future.sync(false);
}
var id:NetworkID = Std.parseInt(args[0]);
var id:NetworkID = Std.parseInt(args[1]);
if (id == null) {
handle.writeLine("Invalid id");
return Future.sync(false);
}
return RessourceNames.unregister(args[1], id).map((res) -> {
return RessourceNames.register(args[0], id).map((res) -> {
switch (res) {
case Success(data):
handle.writeLine("Success");
@@ -87,6 +51,24 @@ class CLI extends CLIAppBase {
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.CLI(),
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]});
case "websocket_success":
this.onWebsocketSuccessTrigger.trigger({url: event[2], handle: event[3]});
case "endofloop":
EndOfLoop.run();
default:
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;
import bin.KSettings;
import bin.Perf;
import bin.srsc.CLI;
import bin.srsc.SiteRessourceController;
@@ -33,7 +34,8 @@ class BinStore {
{c: HelloWorldService, name: "HelloWorldService", aliases: ["hello-service"] },
{c: SiteRessourceController, name: "SiteRessourceController", aliases: ["srsc"]},
{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)

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;
import haxe.ds.ReadOnlyArray;
import kernel.peripherals.Modem;
import kernel.peripherals.Screen;

View File

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

View File

@@ -28,7 +28,8 @@ class ProcessManager {
public static function kill(pid: 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);

View File

@@ -1,5 +1,6 @@
package lib;
import kernel.KernelSettings;
import bin.srsc.PackageTypes.UnregisterRequest;
import kernel.log.Log;
import bin.srsc.PackageTypes.RegisterRequest;
@@ -11,15 +12,13 @@ import kernel.net.Package.NetworkID;
using tink.CoreApi;
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>> {
if (controllerID == -1) controllerID = SITE_CONTROLLER;
if (controllerID == -1) controllerID = KernelSettings.siteController;
var payload: GetRequest = {name: name, type: "get"};
return Net.instance.sendAndAwait(
SITE_CONTROLLER,
controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload
).map((res)->{
@@ -33,12 +32,12 @@ class RessourceNames {
}
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"};
return Net.instance.sendAndAwait(
SITE_CONTROLLER,
controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload
).map((res)->{
@@ -53,12 +52,12 @@ class RessourceNames {
}
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"};
return Net.instance.sendAndAwait(
SITE_CONTROLLER,
controllerID,
SiteRessourceController.SITE_CONTROLLER_RESSOURCE_MANAGER_PROTO,
payload
);