progrunner/app.py

127 lines
3.8 KiB
Python

#!/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/<int:pid>"
)
if __name__ == '__main__':
app.run()