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

        with mutex:
            if not path: # create new game
                g = game.Game()
                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 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":
                word = str(fields.get("word", [""])[0])
                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):
        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});
            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()
            #tplPlayerpage = template.TplLoader.load("tpl/playerpage.tpl")
            tplPlayerpage.write(self, player.status());


mutex = threading.Lock()

tplStartpage = template.TplLoader.load("tpl/startpage.tpl")
tplPlayerpage = template.TplLoader.load("tpl/playerpage.tpl")

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

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