Blame server.py

3c1a85
#!/usr/bin/python3
3c1a85
4bc4d1
import os
4bc4d1
os.chdir(os.path.dirname(os.path.abspath(__file__)))
4bc4d1
import sys
4bc4d1
if len(sys.argv) == 2 and sys.argv[1] == "daemon":
4bc4d1
    sys.stdout = open('log/server.log', 'a')
4bc4d1
    sys.stderr = sys.stdout
4bc4d1
4bc4d1
3c1a85
import config
3c1a85
import game
3c1a85
import template
3c1a85
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()
04af49
            #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.")