#!/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.")