218 lines
5.9 KiB
Python
218 lines
5.9 KiB
Python
from Meh import Config, Option, ExceptionInConfigError
|
|
from Highway import Server, Route, DummyPipe
|
|
import Logging
|
|
|
|
import os
|
|
import subprocess
|
|
import re
|
|
import pwd
|
|
import platform
|
|
from subprocess import Popen, PIPE
|
|
from _thread import start_new_thread
|
|
|
|
from wsgiref.simple_server import make_server
|
|
from ws4py.server.wsgirefserver import WSGIServer, WebSocketWSGIRequestHandler
|
|
from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
|
|
|
from bottle.bottle import route, run, static_file
|
|
|
|
|
|
@route("/")
|
|
def index():
|
|
return static_file("index.html", root="Shared/dashb0ard")
|
|
|
|
@route("/static/<filepath:path>")
|
|
def static(filepath):
|
|
return static_file(filepath, root="Shared/dashb0ard/static")
|
|
|
|
class Info(Route):
|
|
def run(self, data, handler):
|
|
handler.send({"routes" : list(handler.routes.keys())}, "info")
|
|
|
|
|
|
|
|
class Subscribe(Route):
|
|
EDITOR = 1
|
|
WALLABY = 2
|
|
WEB = 3
|
|
CHANNELS = [EDITOR, WALLABY, WEB]
|
|
|
|
def run(self, data, handler):
|
|
if type(data) is dict:
|
|
if "channel" in data:
|
|
if data["channel"] in Subscribe.CHANNELS:
|
|
handler.channel = data["channel"]
|
|
if handler.debug:
|
|
Logging.info("'%s:%i' has identified as a %s client." % (handler.address, handler.port,
|
|
"Editor" if handler.channel == Subscribe.EDITOR else
|
|
"Controller" if handler.channel == Subscribe.WALLABY else
|
|
"Web" if handler.channel == Subscribe.WEB else
|
|
"Unknown"))
|
|
if "name" in data:
|
|
handler.name = data["name"]
|
|
handler.routes["peers"].push_changes(handler)
|
|
|
|
|
|
class WhoAmI(Route):
|
|
def run(self, data, handler):
|
|
handler.send({"id" : handler.id_,
|
|
"user" : pwd.getpwuid(os.getuid()).pw_name},
|
|
handler.reverse_routes[self])
|
|
|
|
|
|
class Peers(Route):
|
|
"""
|
|
{"subscribe" : [1, 2]}
|
|
{"unsubscribe" : [1, 2]}
|
|
{"channels" : [1, 2]}
|
|
"""
|
|
def __init__(self):
|
|
self.subscriptions = {}
|
|
|
|
def run(self, data, handler):
|
|
for event in ("subscribe", "unsubscribe", "channels"):
|
|
if event in data:
|
|
channels = []
|
|
for channel in data[event]:
|
|
if channel in Subscribe.CHANNELS:
|
|
channels.append(channel)
|
|
if event == "unsubscribe":
|
|
for channel in channels:
|
|
self.unsubscribe(handler, channel)
|
|
else:
|
|
if event == "subscribe":
|
|
for channel in channels:
|
|
self.subscribe(handler, channel)
|
|
# Send on channels and on subscribe
|
|
self.send_connected_peers(handler, channels)
|
|
|
|
|
|
def send_connected_peers(self, handler, channels):
|
|
out = {}
|
|
peers = handler.peers
|
|
for peer_id in peers:
|
|
# Only check for type inclusion if check_type is True
|
|
peer = peers[peer_id]
|
|
if peer.channel in channels:
|
|
if peer is not handler:
|
|
out[peer_id] = {"name" : peer.name,
|
|
"address" : peer.address, "port" : peer.port,
|
|
"channel" : peer.channel}
|
|
handler.send(out, handler.reverse_routes[self])
|
|
|
|
|
|
def subscribe(self, handler, channel):
|
|
if handler not in self.subscriptions:
|
|
self.subscriptions[handler] = [channel]
|
|
else:
|
|
if channel not in self.subscriptions[handler]:
|
|
self.subscriptions[handler].append(channel)
|
|
|
|
|
|
def unsubscribe(self, handler, channel):
|
|
if handler in self.subscriptions:
|
|
if channel in self.subscriptions[handler]:
|
|
del self.subscriptions[handler][self.subscriptions[handler].index(channel)]
|
|
|
|
|
|
def unsubscribe_all(self, handler):
|
|
if handler in self.subscriptions:
|
|
del self.subscriptions[handler]
|
|
|
|
|
|
def push_changes(self, handler):
|
|
out = {}
|
|
to_unsubscribe = []
|
|
peers = handler.peers
|
|
for handler_ in self.subscriptions:
|
|
try:
|
|
self.send_connected_peers(handler_, self.subscriptions[handler_])
|
|
except RuntimeError:
|
|
to_unsubscribe.append(handler_)
|
|
for handler in to_unsubscribe:
|
|
self.unsubscribe_all(handler)
|
|
|
|
|
|
class Handler(Server):
|
|
def setup(self, routes, websockets, debug=False):
|
|
super().setup(routes, websockets, debug=debug)
|
|
self.channel = None
|
|
self.name = "Unknown"
|
|
|
|
|
|
def ready(self):
|
|
if self.debug:
|
|
Logging.info("Handler for '%s:%d' ready." % (self.address, self.port))
|
|
|
|
|
|
def closed(self, code, reason):
|
|
if self.debug:
|
|
Logging.info("'%s:%d' disconnected." % (self.address, self.port))
|
|
self.routes["peers"].push_changes(self)
|
|
|
|
|
|
def folder_validator(folder):
|
|
if not os.path.isdir(folder):
|
|
try:
|
|
os.mkdir(folder)
|
|
except OSError:
|
|
return False
|
|
return True
|
|
|
|
|
|
CONFIG_PATH = "server.cfg"
|
|
|
|
|
|
config = Config()
|
|
config.add(Option("fl0w_address", ("127.0.0.1", 3077)))
|
|
config.add(Option("behem0th_address", ("127.0.0.1", 3078)))
|
|
config.add(Option("dashb0ard_address", ("127.0.0.1", 8080)))
|
|
config.add(Option("debug", True, validator=lambda x: True if True or False else False))
|
|
config.add(Option("path", "Content", validator=folder_validator))
|
|
|
|
try:
|
|
config = config.load(CONFIG_PATH)
|
|
except (IOError, ExceptionInConfigError):
|
|
config.dump(CONFIG_PATH)
|
|
config = config.load(CONFIG_PATH)
|
|
|
|
|
|
#compile = Compile(config.source_path, config.binary_path)
|
|
|
|
|
|
server = make_server(config.fl0w_address[0], config.fl0w_address[1],
|
|
server_class=WSGIServer, handler_class=WebSocketWSGIRequestHandler,
|
|
app=None)
|
|
server.initialize_websockets_manager()
|
|
|
|
server.set_app(WebSocketWSGIApplication(handler_cls=Handler,
|
|
handler_args={"debug" : config.debug,
|
|
"websockets" : server.manager.websockets,
|
|
"routes" : {"info" : Info(),
|
|
"whoami" : WhoAmI(),
|
|
"subscribe" : Subscribe(),
|
|
"hostname" : DummyPipe(),
|
|
"processes" : DummyPipe(),
|
|
"peers" : Peers(),
|
|
"sensor" : DummyPipe(),
|
|
"identify" : DummyPipe(),
|
|
"std_stream" : DummyPipe(),
|
|
"stop_programs" : DummyPipe(),
|
|
"shutdown" : DummyPipe(),
|
|
"reboot" : DummyPipe(),
|
|
"output" : DummyPipe()}}))
|
|
|
|
|
|
try:
|
|
Logging.header("Server loop starting.")
|
|
start_new_thread(run, (), {"host" : config.dashb0ard_address[0],
|
|
"port" : config.dashb0ard_address[1], "quiet" : True})
|
|
Logging.info("Starting dashb0ard on 'http://%s:%d'" % (config.dashb0ard_address[0],
|
|
config.dashb0ard_address[1]))
|
|
Logging.info("Starting fl0w on 'ws://%s:%d'" % (config.fl0w_address[0],
|
|
config.fl0w_address[1]))
|
|
server.serve_forever()
|
|
except KeyboardInterrupt:
|
|
Logging.header("Gracefully shutting down server.")
|
|
server.server_close()
|
|
Logging.success("Server shutdown successful.")
|