|
|
|
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 + "."
|
|
|
|
#bc = barcode.generate("code128", prefix + cmd + ".", writer=barcode.writer.ImageWriter(), output=barcode_png)
|
|
|
|
bc = kode256.svg(cmd_code)
|
|
|
|
encoded_svg = b64encode(bc.encode()).decode()
|
|
|
|
encoded_data = "data:image/svg+xml;charset=utf-8;base64," + encoded_svg
|
|
|
|
bc = '<img src="%s" />' % encoded_data
|
|
|
|
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()
|