Blame server.py

3c1a85
#!/usr/bin/python3
3c1a85
3c1a85
import config
3c1a85
import game
3c1a85
import template
3c1a85
3c1a85
import os
3c1a85
import json
3c1a85
import threading
3c1a85
import http.server
3c1a85
import urllib.parse
3c1a85
3c1a85
3c1a85
class Server(http.server.BaseHTTPRequestHandler):
3c1a85
    def write(self, *texts):
3c1a85
        for text in texts:
3c1a85
            self.wfile.write(bytes(str(text), "utf8"))
3c1a85
3c1a85
    def parsePath(self, path):
3c1a85
        if not path.startswith(config.prefix):
3c1a85
            return None
3c1a85
        path = path[len(config.prefix):]
3c1a85
        if len(path) and path[0] != '/':
3c1a85
            return None
3c1a85
        return list(filter(None, path.split("/")))
3c1a85
3c1a85
    def err(self, code = 404, message = ""):
3c1a85
        self.send_response(int(code))
3c1a85
        self.send_header("Content-type", "text/html")
3c1a85
        self.end_headers()
3c1a85
        self.write(str(code) + " " + str(message));
3c1a85
3c1a85
    def writeJpeg(self, path):
3c1a85
        if not path.endswith(".jpg") or not os.path.isfile(path):
3c1a85
            return self.err()
3c1a85
        with open(path, "rb") as f:
3c1a85
            self.send_response(200)
3c1a85
            self.send_header("Content-type", "image/jpeg")
3c1a85
            self.send_header("Cache-Control", "max-age=3600")
3c1a85
            self.end_headers()
3c1a85
            self.wfile.write(f.read())
3c1a85
3c1a85
    def writeStatus(self, player):
3c1a85
        self.send_response(200)
3c1a85
        self.send_header("Content-type", "text/html")
3c1a85
        self.end_headers()
3c1a85
        self.write(json.dumps(player.status()))
3c1a85
3c1a85
    def do_POST(self):
3c1a85
        if self.command != 'POST':
3c1a85
            return self.err()
3c1a85
        path = self.parsePath(self.path)
3c1a85
        if path is None:
3c1a85
            return self.err()
3c1a85
3c1a85
        length = int(self.headers.get('content-length'))
3c1a85
        data = self.rfile.read(length)
3c1a85
        fields = urllib.parse.parse_qs(str(data,"UTF-8"))
3c1a85
3c1a85
        with mutex:
3c1a85
            if not path: # create new game
3c1a85
                g = game.Game()
3c1a85
                self.send_response(303)
3c1a85
                self.send_header("Location", str(config.prefix) + "/" + str(g.players[0].id))
3c1a85
                self.end_headers()
3c1a85
                return
3c1a85
3c1a85
            player = game.players.get(path[0], None)
3c1a85
            if not player:
3c1a85
                return self.err()
3c1a85
            del path[0]
3c1a85
3c1a85
            if len(path) == 2 and path[0] == "select":
3c1a85
                i = -1
3c1a85
                try:
3c1a85
                    i = int(path[1])
3c1a85
                except ValueError:
3c1a85
                    return self.err()
3c1a85
                player.select(i)
3c1a85
            elif len(path) == 1 and path[0] == "ready":
3c1a85
                word = str(fields.get("word", [""])[0])
3c1a85
                player.nextturn(word)
3c1a85
            else:
3c1a85
                return self.err()
3c1a85
3c1a85
            self.send_response(303)
3c1a85
            self.send_header("Location", str(config.prefix) + "/" + str(player.id))
3c1a85
            self.end_headers()
3c1a85
3c1a85
    def do_GET(self):
3c1a85
        if self.command != 'GET':
3c1a85
            return self.err()
3c1a85
3c1a85
        if self.path.startswith(config.cardsPrefix):
3c1a85
            p = str(self.path[len(config.cardsPrefix):])
3c1a85
            if p and p[0] == "/":
3c1a85
                if p.count("/") > 1 or p.count("..") > 0:
3c1a85
                    return self.err()
3c1a85
                return self.writeJpeg("cards" + p)
3c1a85
3c1a85
        path = self.parsePath(self.path)
3c1a85
        if path is None:
3c1a85
            return self.err()
3c1a85
3c1a85
        if not path:
3c1a85
            self.send_response(200)
3c1a85
            self.send_header("Content-type", "text/html")
3c1a85
            self.end_headers()
3c1a85
            tplStartpage.write(self, {"host": config.externalHost, "prefix": config.prefix});
3c1a85
            return
3c1a85
3c1a85
        with mutex:
3c1a85
            if len(path) != 1:
3c1a85
                return self.err()
3c1a85
            j = False
3c1a85
            if path[0].endswith(".json"):
3c1a85
                j = True
3c1a85
                path[0] = path[0][0:-5]
3c1a85
            player = game.players.get(path[0], None)
3c1a85
            if not player:
3c1a85
                return self.err()
3c1a85
            if j:
3c1a85
                return self.writeStatus(player)
3c1a85
            self.send_response(200)
3c1a85
            self.send_header("Content-type", "text/html")
3c1a85
            self.end_headers()
3c1a85
            tplPlayerpage = template.TplLoader.load("tpl/playerpage.tpl")
3c1a85
            tplPlayerpage.write(self, player.status());
3c1a85
3c1a85
3c1a85
mutex = threading.Lock()
3c1a85
3c1a85
tplStartpage = template.TplLoader.load("tpl/startpage.tpl")
3c1a85
tplPlayerpage = template.TplLoader.load("tpl/playerpage.tpl")
3c1a85
3c1a85
game.mergeCards("cards")
3c1a85
game.mergeWords("words/words.txt")
3c1a85
3c1a85
webServer = http.server.HTTPServer((
3c1a85
    config.hostName,
3c1a85
    config.serverPort ), Server )
3c1a85
3c1a85
3c1a85
print("Server started http://%s:%s" % (
3c1a85
    config.hostName,
3c1a85
    config.serverPort ))
3c1a85
try:
3c1a85
    webServer.serve_forever()
3c1a85
except KeyboardInterrupt:
3c1a85
    pass
3c1a85
webServer.server_close()
3c1a85
print("Server stopped.")