#!/usr/bin/env python3 import subprocess import select import time import config import logging.config logging.config.dictConfig(config.logging) log = logging.getLogger('progrunner') from flask import Flask, request, session from flask_restful import Api, Resource app = Flask(__name__) api = Api(app) app.config.from_object(config) class Authenticator(Resource): def post(self): if request.json and request.json.get("token", None) == config.token: session["authorized"] = True log.info("session: %s", session) return { "authorized": True } else: session["authorized"] = False log.info("session: %s", session) return { "authorized": False } running = [] class Starter(Resource): def post(self): log.info("session: %s", session) if not session.get("authorized", False): return {} log.info("json: %s", request.json) args = [ request.json["program"] ] if "args" in request.json: args += request.json["args"] log.info("args: %s", args) proc = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) procinfo = { "popen": proc, "pid": proc.pid, "started": time.time(), "stdout": [] } running.append(procinfo) pid = proc.pid log.info("pid: %s", pid) timeout = request.json.get("timeout", 0.0) if timeout: fd = proc.stdout p = select.poll() p.register(fd) t0 = time.time() t1 = t0 + timeout while True: dt = t1 - time.time() if dt < 0: break ready = p.poll(dt * 1000) log.debug("ready: %s", ready) if ready: ln = fd.readline() log.debug("ln: %s", ln) if ln == "": break; procinfo["stdout"].append(ln) try: procinfo["status"] = proc.wait(0.1) for ln in proc.stdout: procinfo["stdout"].append(ln) procinfo["finished"] = time.time() except subprocess.TimeoutExpired: pass return { x: procinfo[x] for x in ["pid", "started", "stdout", "status", "finished"] if x in procinfo } class Status(Resource): def get(self, pid): for procinfo in running: if "finished" not in procinfo: p = select.poll() p.register(procinfo["popen"].stdout) t1 = time.time() + 1.0 while True: dt = t1 - time.time() if dt < 0: break ready = p.poll(dt * 1000) log.debug("ready: %s", ready) if ready: ln = procinfo["popen"].stdout.readline() log.debug("ln: %s", ln) if ln == "": break; procinfo["stdout"].append(ln) try: procinfo["status"] = procinfo["popen"].wait(0.1) procinfo["finished"] = time.time() except subprocess.TimeoutExpired: pass for procinfo in running: if procinfo["pid"] == pid: return { x: procinfo[x] for x in ["pid", "started", "stdout", "status", "finished"] if x in procinfo } api.add_resource( Authenticator, "/login" ) api.add_resource( Starter, "/start" ) api.add_resource( Status, "/status/" ) if __name__ == '__main__': app.run()