server.py
author Eugen Sawin <sawine@me73.com>
Mon, 20 Feb 2012 15:40:08 +0100
changeset 1 962dd7efaa05
child 2 b25c62d210f5
permissions -rw-r--r--
Minor CSS fix for links.
     1 #! /usr/bin/env python3
     2 """
     3 Name: 
     4 Author: Eugen Sawin <sawine@me73.com>
     5 """
     6 
     7 import socketserver
     8 import logging
     9 import os
    10 import os.path
    11 import shelve
    12 import json
    13 import re
    14 import urllib.request
    15 import subprocess
    16 import time
    17 from operator import itemgetter
    18 from urllib.parse import urlparse
    19 from urllib.request import urlopen
    20 from tempfile import NamedTemporaryFile
    21 from http.server import BaseHTTPRequestHandler, HTTPServer
    22 from pseudoword import Database
    23 
    24 try:
    25     from argparse import ArgumentParser
    26 except ImportError:
    27     from external.argparse import ArgumentParser
    28 
    29 ENCODING = 'utf-8'
    30 
    31 def parse_args():
    32     parser = ArgumentParser(description='')
    33     parser.add_argument('-p', type=int, default=8080, help='port')
    34     parser.add_argument('-a', default='localhost', help='host address')
    35     parser.add_argument('-l', default='log/server.log', help='log file')
    36     parser.add_argument('-w', default='data/names', help='word database')
    37     parser.add_argument('-d', default='httpdocs', help='http docs path')
    38     return parser.parse_args()	
    39 
    40 
    41 def main():        
    42     args = parse_args()
    43     logging.basicConfig(filename=args.l, level=logging.DEBUG,
    44                         format='[%(levelname)s@%(asctime)s] %(message)s',
    45                         datefmt='%d.%m.%Y %I:%M:%S')
    46     db = Database(args.w)
    47     server = Server(args.a, args.p, args.d, db, GetHandler)
    48     server.run()
    49 
    50 
    51 class GetHandler(BaseHTTPRequestHandler):
    52 
    53     def do_GET(self):
    54         request = Request(self.path, self.server.docs_path, self.server.db)
    55         logging.info('Request: %s' % request)
    56         code, content_type, data = request()
    57         self.send_response(code)       
    58         self.send_header('Content-type', content_type)
    59         self.end_headers()
    60         self.wfile.write(data)
    61         
    62     def log_message(self, format, *args):
    63         pass
    64 
    65 		
    66 class Server(HTTPServer):
    67 
    68     def __init__(self, host, port, docs_path, db, handler):
    69         HTTPServer.__init__(self, (host, port), handler)
    70         self.host = host
    71         self.port = port
    72         self.docs_path = docs_path
    73         self.db = db
    74 
    75     def run(self):
    76         logging.info('Server ready and listening at port {0}.'.format(self.port))
    77         self.serve_forever()
    78 
    79 
    80 class Request:    
    81 
    82     @classmethod
    83     def _content_type(cls, doc):
    84         if doc.endswith('.html'):
    85             return 'text/html'
    86         elif doc.endswith('.css'):
    87             return 'text/css'
    88         elif doc.endswith('.js'):
    89             return 'application/javascript'
    90         elif doc.endswith('.ttf'):           
    91             return 'application/octet-stream'
    92         else:            
    93             return 'text/plain'
    94             
    95     def __init__(self, query, docs_path, db):       
    96         self.docs_path = docs_path
    97         self.db = db
    98         self.parsed = urlparse(query)
    99         self.args = dict()
   100         if len(self.parsed.query):
   101             self.args = dict([a.split('=') for a in self.parsed.query.split('&')])
   102         if self.parsed.path[1:] in commands:
   103             self.__class__ = commands[self.parsed.path[1:]]
   104         else:
   105             self.__class__ = WebRequest     
   106             self.args['doc'] = self.parsed.path    
   107 
   108     def __str__(self):
   109         return '{0}({1})'.format(str(self.__class__).partition('.')[-1].rstrip('">'),
   110                            ', '.join(['{0}: {1}'.format(k, str(v))
   111                                       for k, v in self.args.items()]))
   112 
   113 
   114 def client_rating(rating):
   115     return int(rating * 1000)
   116 
   117 
   118 class WordsRequest(Request):
   119 
   120     def __call__(self):   
   121         w1, w2 = self.db.pick_words()    
   122         data = '{{"words":[["{w1}", {r1}], ["{w2}", {r2}]]}}'.format(w1=w1[0],
   123                                                                      r1=w1[1], 
   124                                                                      w2=w2[0],
   125                                                                      r2=w2[1])
   126         return (200, 'application/javascript', bytes(data, ENCODING))
   127 
   128 
   129 class RateRequest(Request):
   130 
   131     def __call__(self):
   132         w3 = self.args['bn']
   133         w4 = self.args['wn']
   134         w3, w4 = self.db.rate(w3, w4)
   135         w1, w2 = self.db.pick_words()
   136         data = '{{"words":[["{w1}",{r1}],["{w2}",{r2}],'.format(w1=w1[0], r1=client_rating(w1[1]), 
   137                                                                    w2=w2[0], r2=client_rating(w2[1]))
   138         data += '["{w3}",{r3}],["{w4}",{r4}]]}}'.format(w3=w3[0], r3=client_rating(w3[1]), 
   139                                                            w4=w4[0], r4=client_rating(w4[1]))
   140         return (200, 'application/javascript', bytes(data, ENCODING))
   141 
   142 
   143 commands = {'words': WordsRequest,
   144             'rate': RateRequest}
   145 
   146 
   147 class WebRequest(Request):
   148 
   149     def __call__(self):
   150         if self.args['doc'] == '/':
   151             self.args['doc'] = '/index.html'
   152         content_type = self._content_type(self.args['doc'])
   153         data = bytes('', ENCODING)
   154         rel_path = self.docs_path + self.args['doc']
   155         if os.path.exists(rel_path):
   156             with open(rel_path, 'r+b') as f:
   157                 data = f.read()
   158             code = 200
   159         else:
   160             code = 404
   161         return (code, content_type, data)
   162 
   163 
   164 if __name__ == '__main__':
   165 	main()