from base64 import b64encode import json import os import signal import socket import subprocess import threading import kode256 from lxml import etree from bureau import Bureau, add_command, add_api from . import ihrweb class InhumanResources(Bureau): """ This is a core functional bureau of the Screenless office it keeps track of all published methods provided by all other bureaus and can print the menu for the whole system or an individual item """ name = "Inhuman Resources" prefix = "IR" version = 0 def __init__(self): Bureau.__init__(self) self.menu = {} self.webapp = ihrweb.IhrApp() webargs = { "host": "0.0.0.0", "port": 8000 } self.webthread = threading.Thread(target=self.webapp.run, kwargs=webargs, daemon=True) self.webthread.start() def start_msg(): msg = "HELLO WORLD\r\n\r\nAVAILABLE BUREAUS:\r\n" for prefix in self.menu.keys(): msg += " " + self.menu[prefix]["name"] + " (" + prefix + ")\r\n" self.print_small(msg) self.print_my_ip() msgtimer = threading.Timer(10, start_msg) # wait for the other bureux @add_api("addbureau", "Register Bureau") def add_bureau(self, data): """ Register Bureau with Inhuman Resources data = { prefix: "IR", name: "Inhuman Resources", desc: "Keep track of public resources provided by bureaus" } """ try: name = data["name"] prefix = data["prefix"] desc = data["desc"] self.webapp.register_bureau(prefix) except KeyError as e: print("cannot add invalid bureau:", str(e)) return str(e) print("added menu") self.menu[prefix] = {"name": name, "desc": desc, "commands": {}, "apis": {}, "webviews": {}} @add_api("addcommand", "Register Command") def add_cmd(self, data): try: prefix = data["prefix"] cmd = data["cmd"] cmdname = data["cmdname"] desc = data["desc"] cmd_code = prefix + cmd + "." in_menu = data["in_menu"] #bc = barcode.generate("code128", prefix + cmd + ".", writer=barcode.writer.ImageWriter(), output=barcode_png) if in_menu: bc = kode256.svg(cmd_code) encoded_svg = b64encode(bc.encode()).decode() encoded_data = "data:image/svg+xml;charset=utf-8;base64," + encoded_svg bc = '' % encoded_data else: bc = "" except KeyError as e: print("cannot add invalid command:", str(e)) return if prefix not in self.menu: # TODO: this should throw some kind of error message/log print("error: cannot add command ", cmd, "to non-existent prefix", prefix) else: self.menu[prefix]["commands"][cmd] = {"name": cmdname, "desc": desc, "barcode": bc } @add_api("addapi", "Register API Method") def add_api_method(self, data): try: prefix = data["prefix"] cmd = data["api"] cmdname = data["apiname"] desc = data["desc"] except KeyError as e: print("cannot add invalid command:", str(e)) return if prefix not in self.menu: # TODO: this should throw some kind of error message/log print("error: cannot add command ", cmd, "to non-existent prefix", prefix) else: self.menu[prefix]["apis"][cmd] = {"name": cmdname, "desc": desc} @add_api("addweb", "Register Custom Web View") def add_webview(self, data): try: prefix = data["prefix"] webview = data["webview"] viewname = data["name"] desc = data["desc"] except KeyError as e: self.log.error("cannot add invalid command:", e) return if prefix not in self.menu: self.log.error("cannot add web view" + webview + "to non-existent prefix" + prefix) else: self.menu[prefix]["webviews"][webview] = {"name": viewname, "desc": desc} def callback(request): return self.send(prefix, webview, data=request) self.webapp.register_webview(prefix, webview, callback) @add_command("menu", "Print Menu") def print_menu(self): """ Prints the menu of commands for all operational bureaus. """ self.print_full("menu.html", menu=self.menu) @add_command("getmyip", "Print Office IP Address") def print_my_ip(self): """ Print out the current network address of the office. Useful for necessary screen-based maintainance tasks. """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.connect(("8.8.8.8", 80)) self.print_small("This Screenless Office currently resides at:\r\n" + sock.getsockname()[0] + "\r\n") sock.close() @add_command("update", "Restructure Organization") def update(self): """ Restructure the organization. This may include firing, hiring, refinancing and organizational changes. This will update the Office to the latest software but it may be disruptive to your current personal and social situation. After pulling the latest updates, all bureaus other than management will be restarted. """ subprocess.call("git pull") self.restart() @add_command("restart", "Furlough") def restart(self): """ Send the entire organization on a very short unpaid vacation. This will restart all bureaus, so it may cause disruption, loss of work and other psycho-social side effects of a loss of state. It may also help restore a messed up office to normal operation. """ # TODO: find the PID of mgmt and send it a HUP signal with open("mgmt.pid") as pfile: pid = int(pfile.read()) os.kill(pid, signal.SIGHUP) def main(): hr = InhumanResources() hr.run() if __name__ == "__main__": main()