diff --git a/bin/__init__.py b/bin/__init__.py deleted file mode 100644 index 1f7d74b..0000000 --- a/bin/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -import os - -imports = [ i[:-3] for i in os.listdir('/bin/') if i.endswith('.py') and not '__' in i ] -for module in imports: - exec(f'import bin.{module} as {module}') diff --git a/bin/background.py b/bin/background.py deleted file mode 100644 index 3403419..0000000 --- a/bin/background.py +++ /dev/null @@ -1,6 +0,0 @@ -import circuitos - -class App(circuitos.App): - def F_main(self): - self.os.launch(*self.argv[1:]) - self.exit() diff --git a/bin/init.py b/bin/init.py index c2f017f..f4f7049 100644 --- a/bin/init.py +++ b/bin/init.py @@ -1,16 +1,18 @@ -import circuitos import shlex -class App(circuitos.App): - def F_main(self): - with open('/etc/init/start') as f: - lines = f.readlines() - for line in lines: - if line.strip(): - last_pid = self.os.launch(*shlex.split(line)) +def get_app_class(template): + class App(template): + def F_main(self): + with open('/etc/init/start') as f: + lines = f.readlines() + for line in lines: + if line.strip(): + last_pid = self.os.launch(*shlex.split(line)) - self.transfer_console(last_pid) - self.next_function = 'loop' + self.transfer_console(last_pid) + self.next_function = 'loop' - def F_loop(self): - pass + def F_loop(self): + pass + + return App diff --git a/bin/kill.py b/bin/kill.py index 8a71999..c1cc04c 100644 --- a/bin/kill.py +++ b/bin/kill.py @@ -1,6 +1,7 @@ -import circuitos +def get_app_class(template): + class App(template): + def F_main(self): + self.os.kill(int(self.argv[1])) + self.exit() -class App(circuitos.App): - def F_main(self): - self.os.kill(int(self.argv[1])) - self.exit() + return App diff --git a/bin/ps.py b/bin/ps.py index e43d041..b0dde1a 100644 --- a/bin/ps.py +++ b/bin/ps.py @@ -1,10 +1,11 @@ -import circuitos +def get_app_class(template): + class App(template): + def F_main(self): + apps = self.os.apps + for pid, app in apps.items(): + args = app.argv[1:] + name = app.name + print(f'{pid} {name} {args}') + self.exit() -class App(circuitos.App): - def F_main(self): - apps = self.os.apps - for pid, app in apps.items(): - args = app.argv[1:] - name = app.name - print(f'{pid} {name} {args}') - self.exit() + return App diff --git a/bin/sh.py b/bin/sh.py index 6427fef..529dd42 100644 --- a/bin/sh.py +++ b/bin/sh.py @@ -1,33 +1,35 @@ -import circuitos +import circuitos.exceptions import shlex import console -class App(circuitos.App): - def F_main(self): - self.jump('prompt') - - def F_prompt(self): - self.console.write(b'CicuitOS sh # ') - self.store['buf'] = [] - self.jump('input') - - def F_input(self): - raw_line = console.read(self.console, self.store['buf']) - if raw_line is not None: - line = shlex.split(raw_line.decode('ascii')) - if line: - try: - if line[0] == 'bg': - self.os.launch(*line[1:]) - elif line[0] == 'exit': - self.exit() - else: - pid = self.os.launch(*line) - self.wait(pid) - self.transfer_console(pid) - except circuitos.AppNotFound as e: - print('error: app not found') +def get_app_class(template): + class App(template): + def F_main(self): self.jump('prompt') - def F_loop(self): - pass + def F_prompt(self): + self.console.write(b'CicuitOS sh # ') + self.store['buf'] = [] + self.jump('input') + + def F_input(self): + raw_line = console.read(self.console, self.store['buf']) + if raw_line is not None: + line = shlex.split(raw_line.decode('ascii')) + if line: + try: + if line[0] == 'bg': + self.os.launch(*line[1:]) + elif line[0] == 'exit': + self.exit() + else: + pid = self.os.launch(*line) + self.wait(pid) + self.transfer_console(pid) + except circuitos.exceptions.AppNotFound as e: + print('error: app not found') + self.jump('prompt') + + def F_loop(self): + pass + return App diff --git a/circuitos/__init__.py b/circuitos/__init__.py new file mode 100644 index 0000000..343091d --- /dev/null +++ b/circuitos/__init__.py @@ -0,0 +1,106 @@ +import bin #this is at the end of the script in case any functions from bin +#depend on anything here +from circuitos.exceptions import * +from circuitos.apploader import get_app +import circuitos.apploader # apploader hack +import time +import usb_cdc + +class App: + def __init__(self, os, pid, name, *argv): + self.os = os + self.pid = pid + self.name = name + self.store = {} + self.next_function = 'main' + self.run_at = -1 + self.argv = (self,) + argv + self.waiting_for = -1 + + def iterate(self): + if time.monotonic() >= self.run_at and not self.waiting_for in self.os.apps: + getattr(self, f'F_{self.next_function}')() + + @property + def console(self): + if self.pid == self.os.controllers[-1]: + return self.os.console + else: + raise NotConsoleController(self.os.controllers[-1]) + + def transfer_console(self, recipient): + if self.pid == self.os.controllers[-1]: + self.os.controllers.append(recipient) + else: + raise NotConsoleController(self.os.controllers[-1]) + + def jump(self, function): + self.next_function = function + + def sleep(self, seconds): + self.run_at = time.monotonic() + seconds + + def exec(self, command, *argv): + self.os.apps[self.pid] = get_app(command)(self.os, self.pid, command, *argv) + + def wait(self, pid): + self.waiting_for = pid + + def end_wait(self): + self.waiting_for = -1 + + def on_exit(self): + pass + + def exit(self): + del self.os.apps[self.pid] + +apploader.App = App # apploader hack + +class OS: + def __init__(self): + self.apps = {} + self.next_new = 0 + self.controllers = [0] + self.console = usb_cdc.console + usb_cdc.console.timeout = 0 + self.next_pidi = 0 + self.launch('init') + + def iterate(self): + pid = list(self.apps.keys())[self.next_pidi] + function = self.apps[pid].iterate + + function() + + try: + self.apps[pid] + # If this succeds, the app did not exit and next_pidi should + # be incremented + self.next_pidi += 1 + except KeyError: + # If self.apps[pid] failed, the app exited and next_pidi + # should not be incremented + pass + self.next_pidi = self.next_pidi % len(self.apps) + + while not self.controllers[-1] in self.apps.keys(): + self.controllers.pop() + + def launch(self, app, *argv): + self.apps[self.next_new] = get_app(app)(self, self.next_new, app, *argv) + self.next_new += 1 + return self.next_new - 1 + + def kill(self, pid): + try: + del self.apps[pid] + except KeyError: + raise(NoSuchProcess(pid)) + +def run(): + os = OS() + while True: + os.iterate() + + diff --git a/circuitos/apploader.py b/circuitos/apploader.py new file mode 100644 index 0000000..5f58239 --- /dev/null +++ b/circuitos/apploader.py @@ -0,0 +1,19 @@ +_cache = {} + +def get_app(app): + try: + return _cache[app] + except KeyError: + try: + module = __import__(f'/bin/{app}') + except AttributeError: + raise AppNotFound(app) + + try: + app_class = module.get_app_class(App) + except AttributeError: + raise InvalidApp(app) + + _cache[app] = app_class + + return app_class diff --git a/circuitos/exceptions.py b/circuitos/exceptions.py new file mode 100644 index 0000000..41aa265 --- /dev/null +++ b/circuitos/exceptions.py @@ -0,0 +1,18 @@ +class CircuitOSError(Exception): + pass + + +class NoSuchProcess(CircuitOSError): + pass + + +class AppNotFound(CircuitOSError): + pass + + +class InvalidApp(AppNotFound): + pass + + +class NotConsoleController(CircuitOSError): + pass