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()
        tplErrorpage.write(self, {
            "host": config.externalHost,
            "prefix": config.prefix,
            "code": int(code),
            "message": str(message),
            "waiting": False });

    def writeJpeg(self, path):
        if not path.endswith(".jpg") or not os.path.isfile(path):
            return self.err()
        with open(path, "rb") as f:
            self.send_response(200)
            self.send_header("Content-type", "image/jpeg")
            self.send_header("Cache-Control", "max-age=3600")
            self.end_headers()
            self.wfile.write(f.read())

    def writeStatus(self, player):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.write(json.dumps(player.status()))

    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"))
        word = str(fields.get("word", [""])[0])
        vocabulary = str(fields.get("vocabulary", [""])[0])

        with mutex:
            if not path: # create new game
                if not vocabulary in game.words:
                    return self.err()
                g = game.Game(vocabulary, word)
                self.send_response(303)
                self.send_header("Location", str(config.prefix) + "/" + str(g.players[0].id))
                self.end_headers()
                return

            player = game.players.get(path[0], None)
            if not player:
                return self.err()
            del path[0]

            if not path:
                player.join(word)
            elif len(path) == 2 and path[0] == "select":
                i = -1
                try:
                    i = int(path[1])
                except ValueError:
                    return self.err()
                player.select(i)
            elif len(path) == 1 and path[0] == "ready":
                player.nextturn(word)
            else:
                return self.err()

            self.send_response(303)
            self.send_header("Location", str(config.prefix) + "/" + str(player.id))
            self.end_headers()

    def do_GET(self):
        #loadTemplates()

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

        if self.path.startswith(config.cardsPrefix):
            p = str(self.path[len(config.cardsPrefix):])
            if p and p[0] == "/":
                if p.count("/") > 1 or p.count("..") > 0:
                    return self.err()
                return self.writeJpeg("cards" + p)

        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,
                "vocabularies": list(sorted(game.words.keys())),
                "waiting": False });
            return

        with mutex:
            if len(path) != 1:
                return self.err()
            j = False
            if path[0].endswith(".json"):
                j = True
                path[0] = path[0][0:-5]
            player = game.players.get(path[0], None)
            if not player:
                return self.err()
            if j:
                return self.writeStatus(player)
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            if player.game.started:
                tplPlayerpage.write(self, player.status());
            else:
                tplJoinpage.write(self, player.status());


def loadTemplates():
    global tplStartpage, tplJoinpage, tplPlayerpage, tplErrorpage
    tplStartpage = template.TplLoader.load("tpl/startpage.tpl")
    tplJoinpage = template.TplLoader.load("tpl/joinpage.tpl")
    tplPlayerpage = template.TplLoader.load("tpl/playerpage.tpl")
    tplErrorpage = template.TplLoader.load("tpl/errorpage.tpl")



mutex = threading.Lock()

loadTemplates()

game.mergeCards("cards")
game.mergeWords("words")

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.")