Blob Blame Raw
#!/usr/bin/python3

import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))
import sys
if len(sys.argv) == 2 and sys.argv[1] == "daemon":
    sys.stdout = open('log/server.log', 'a')
    sys.stderr = sys.stdout


import config
import game
import template

import json
import threading
import http.server
import urllib.parse


class Server(http.server.BaseHTTPRequestHandler):
    def write(self, *texts):
        for text in texts:
            self.wfile.write(bytes(str(text), "utf8"))

    def parsePath(self, path):
        if not path.startswith(config.prefix):
            return None
        path = path[len(config.prefix):]
        if len(path) and path[0] != '/':
            return None
        return list(filter(None, path.split("/")))

    def err(self, code = 404, message = ""):
        self.send_response(int(code))
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.write(str(code) + " " + str(message));

    def do_POST(self):
        if self.command != 'POST':
            return self.err()
        path = self.parsePath(self.path)
        if path is None:
            return self.err()

        length = int(self.headers.get('content-length'))
        data = self.rfile.read(length)
        fields = urllib.parse.parse_qs(str(data,"UTF-8"))
        answers = fields.get("answer", [])
        questions = str(fields.get("questions", [""])[0])

        with mutex:
            if not path: # create new game
                q = game.questions.get(questions)
                if not q:
                    print("questions not found: %s" % str(questions))
                    return self.err()
                gm = game.Game(q)
                self.send_response(303)
                self.send_header("Location", str(config.prefix) + "/" + str(gm.id))
                self.end_headers()
                return
            if len(path) == 1: # post answers
                gm = game.games.get(path[0])
                if not gm or not answers:
                    return self.err()
                gm.addAnswers([str(a).strip() for a in answers])
                self.send_response(303)
                self.send_header("Location", str(config.prefix) + "/" + str(gm.id) + "/wait")
                self.end_headers()
                return
        return self.err()

    def do_GET(self):
        #loadTemplates

        if self.command != 'GET':
            return self.err()

        path = self.parsePath(self.path)
        if path is None:
            return self.err()

        if not path:
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            tplStartPage.write(self, {
                "host": config.externalHost,
                "prefix": config.prefix,
                "waiting": False,
                "questions": list(sorted(game.questions.keys())) });
            return

        with mutex:
            gm = game.games.get(path[0])
            if len(path) == 2 and path[1] == 'story':
                story = ''
                if gm:
                    story = gm.getStory()
                    try:
                        with open('history/' + gm.id + '.txt', 'w') as f:
                            f.write(story)
                    except IOError:
                        pass
                else:
                    try:
                        with open('history/' + game.filterId(path[0]) + '.txt', 'r') as f:
                            story = f.read()
                    except IOError:
                        return self.err()
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                tplStoryPage.write(self, {
                    "host": config.externalHost,
                    "prefix": config.prefix,
                    "waiting": False,
                    "story": story });
                return
            if not gm:
                return self.err()
            if len(path) == 1:
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                tplQuestionsPage.write(self, {
                    "host": config.externalHost,
                    "prefix": config.prefix,
                    "id": gm.id,
                    "waiting": False,
                    "questions": gm.questions });
                return
            if len(path) == 2 and path[1] == 'wait':
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                tplWaitPage.write(self, {
                    "host": config.externalHost,
                    "prefix": config.prefix,
                    "id": gm.id,
                    "waiting": True,
                    "answers": len(gm.answers) });
                return
            if len(path) == 2 and path[1] == 'status':
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                self.write(json.dumps({ "id": gm.id, "answers": len(gm.answers) }))
                return
        return self.err()


def loadQuestions():
    for f in os.scandir("questions"):
        if f.is_file() and f.name.endswith(".txt"):
            n = f.name[:-4]
            q = []
            with open("questions/" + f.name, "r") as ff:
                for l in ff.readlines():
                    ll = l.strip();
                    if ll != "":
                        q.append(ll)
            if q:
                game.questions[n] = q

def loadTemplates():
    global tplStartPage, tplQuestionsPage, tplWaitPage, tplStoryPage
    tplStartPage = template.TplLoader.load("tpl/startpage.tpl")
    tplQuestionsPage = template.TplLoader.load("tpl/questionspage.tpl")
    tplWaitPage = template.TplLoader.load("tpl/waitpage.tpl")
    tplStoryPage = template.TplLoader.load("tpl/storypage.tpl")



mutex = threading.Lock()

loadQuestions()
loadTemplates()


webServer = http.server.HTTPServer((
    config.hostName,
    config.serverPort ), Server )


print("Server started http://%s:%s" % (
    config.hostName,
    config.serverPort ))
try:
    webServer.serve_forever()
except KeyboardInterrupt:
    pass
webServer.server_close()
print("Server stopped.")