diff --git a/src/kernel/Init.hx b/src/kernel/Init.hx index acde5ab..766eeb3 100644 --- a/src/kernel/Init.hx +++ b/src/kernel/Init.hx @@ -1,5 +1,6 @@ package kernel; +import kernel.service.ServiceManager; import kernel.binstore.BinStore; import kernel.gps.INS; import kernel.fs.FS; @@ -56,5 +57,7 @@ class Init { Init.mainEvent = MainLoop.add(()->{ KernelEvents.instance.startEventLoop(); }); + + ServiceManager.instace = new ServiceManager(); } } diff --git a/src/kernel/service/Service.hx b/src/kernel/service/Service.hx new file mode 100644 index 0000000..cce3b8b --- /dev/null +++ b/src/kernel/service/Service.hx @@ -0,0 +1,38 @@ +package kernel.service; + +import kernel.ps.ProcessManager; +import kernel.ps.ProcessHandle; +import kernel.binstore.BinStore; + +using tink.CoreApi; + +class Service { + private final binName:String; + private final name:String; + private final args:Array; + private var pid:PID; + + @:allow(kernel.service.ServiceManager) + private function new(binName: String,name: String,?args: Array ) { + this.binName = binName; + this.name = name; + this.args = args ?? []; + } + + public function start() { + var bin = BinStore.instance.getBinByAlias(this.binName); + + if (bin == null){ + throw new Error('Bin ${this.binName} not found'); + } + + var ps = Type.createInstance(bin.c,this.args); + + this.pid = ProcessManager.run(ps,{}); + } + + public function stop() { + ProcessManager.kill(this.pid); + } + +} diff --git a/src/kernel/service/ServiceManager.hx b/src/kernel/service/ServiceManager.hx new file mode 100644 index 0000000..5a0c728 --- /dev/null +++ b/src/kernel/service/ServiceManager.hx @@ -0,0 +1,123 @@ +package kernel.service; + +import kernel.log.Log; +import kernel.binstore.BinStore; +import lib.KVStore; + +using tink.CoreApi; + +class ServiceManager { + public static var instace: ServiceManager; + + private final services:Map = new Map(); + + @:allow(kernel.Init) + private function new() { + this.startAllEnabled(); + } + + /** + Add a service to be automatically started. + **/ + private function enable(name: String) { + if (!this.services.exists(name)){ + return; // Service must be started + } + + var store = KVStore.getStoreForClass(); + + var enabled = store.get("enabled",[]); + enabled.push(name); + store.set("enabled",enabled); + + store.save(); + } + + /** + Remove a service from being automatically started. + **/ + private function disable(name: String) { + var store = KVStore.getStoreForClass(); + var enabled: Array = store.get("enabled"); + var index = enabled.indexOf(name); + if (index == -1){ + return; + } + + enabled.splice(index,1); + store.save(); + } + + private function startAllEnabled() { + var store = KVStore.getStoreForClass(); + var enabled: Array = store.get("enabled",[]); + for (name in enabled){ + this.start(name); + } + } + + private function load(name: String): Null { + var store = new KVStore('service/${name}'); + store.load(); + if (!store.exists("service")){ + return null; + } + + return store.get("service"); + } + + public function register(name: String, binName: String,args: Array): Outcome { + if (BinStore.instance.getBinByAlias(binName) == null){ + return Failure("bin not found"); + } + + if (this.load(name) != null){ + return Failure("service already exists"); + } + + var service = new Service(binName,name,args); + + var store = new KVStore('service/${name}'); + store.set("service",service); + store.save(); + + Log.info('Service ${name} registered'); + return Success(Noise); + } + + public function unregister(name: String): Outcome { + if (this.services.exists(name)){ + return Failure("service is running"); + } + + KVStore.removeNamespace('service/${name}'); + Log.info('Service ${name} unregistered'); + return Success(Noise); + } + + public function start(name: String): Outcome { + var service = this.load(name); + if (service == null){ + return Failure("service not found"); + } + + service.start(); + this.services.set(name,service); + + Log.info('Service ${name} started'); + return Success(Noise); + } + + public function stop(name: String): Outcome { + if (!this.services.exists(name)){ + return Failure("service not found"); + } + + var service = this.services.get(name); + service.stop(); + this.services.remove(name); + + Log.info('Service ${name} stopped'); + return Success(Noise); + } +}