#!/usr/bin/python # coding=utf8 import sys import os from cgi import parse_qs from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from urllib import unquote_plus, unquote, quote from ConfigParser import ConfigParser from opendir import opendir from xml.sax import saxutils from shutil import copyfileobj from bsddb import rnopen from getopt import getopt from random import randint from sphinxsearch import SphinxClient, SPH_MATCH_ANY from mako.lookup import TemplateLookup from mako import exceptions from mimetypes import guess_type class Config(object): data = None def __getitem__(self, k): return Config.data.get(k) def keys(self): return Config.data.keys() def __init__(self): if Config.data is None: config_file = "mokopedia.cfg" opts, args = getopt(sys.argv[1:], "c:", ["config=",]) for o, a in opts: if o in ("-c", "--config"): if os.path.exists(a): config_file = a config = ConfigParser() try: if not config.read(config_file): raise except: sys.exit("config file not valid") sphinx_port = 3312 Config.data = {} class Dummy(object): pass Config.data["main"] = Dummy() Config.data["main"].__dict__["iw"] = [] for section in config.sections(): if "main" not in section and config.getint(section, "enabled"): Config.data[section] = Dummy() Config.data["main"].__dict__["iw"].append(section) for (name, value) in config.items(section): Config.data[section].__dict__[name] = value Config.data[section].__dict__["lookup"] = TemplateLookup(directories=[os.path.join(section, "templates")], module_directory=os.path.join(section, "modules"), input_encoding='utf-8', output_encoding='utf-8') db = config.get(section, "title_index") if db: print "opening titles bsddb..." Config.data[section].__dict__["titles"] = rnopen(db) if config.get(section, "title_search") or config.get(section, "fulltext_search"): print "starting sphinx daemon for %s wiki..."%section print "-----------------------------" L = ['searchd', '--port', '%s'%sphinx_port, '--config', '%s/sphinx.conf'%section, '--console'] os.spawnvp(os.P_NOWAIT, 'searchd', L) print "-----------------------------" print "successfully started" Config.data[section].__dict__["sphinx"] = SphinxClient() Config.data[section].__dict__["sphinx"].SetServer ( "localhost", sphinx_port ) Config.data[section].__dict__["sphinx"].SetMatchMode ( SPH_MATCH_ANY ) sphinx_port+=1 elif "main" in section: for (name, value) in config.items(section): Config.data[section].__dict__[name] = value class MyHandler(BaseHTTPRequestHandler): def output_wiki_page(self, lang, article): try: file = open(os.path.join(self.config["main"].dump_folder, lang, article), "r") except IOError: self.output_error_page(lang, article) else: self.write_header() template = self.config[lang].lookup.get_template("header.mako") self.wfile.write(template.render(article=unicode(saxutils.escape(article), "utf8"), title=unicode(file.readline(), "utf8"), iw=self.config["main"].iw)) copyfileobj(file, self.wfile ) template = self.config[lang].lookup.get_template("footer.mako") self.wfile.write(template.render()) def output_category_page(self, lang, article, page): folder = os.path.join(self.config["main"].dump_folder, lang, article) try: index = open(os.path.join(folder, "index"), "r") except IOError: self.output_error_page(lang, article) else: d = opendir(folder) #seek to page if necessary if page > 1: for i in xrange(int(self.config["main"].category_size)*(page-1)): d.read() last_page = False items = [] for i in xrange(int(self.config["main"].category_size)): filename = d.read() if filename: if filename not in [".","..","index"]: items.append( (unicode(saxutils.escape(quote(os.readlink(os.path.join(folder,filename))[3:])), "utf8"), unicode(saxutils.escape(filename), "utf8")) ) else: last_page = True break self.write_header() template = self.config[lang].lookup.get_template("category.mako") self.wfile.write(template.render( article=unicode(article, "utf8"), title=unicode(index.readline(), "utf8"), items=items, last_page=last_page, page=page, article=unicode(article, "utf8"), text=unicode(index.read(), "utf8"), iw=self.config["main"].iw, )) def output_result_page(self, lang, text, page): last_page = False page_size = int(self.config["main"].result_size) self.config[lang].sphinx.SetLimits ( page_size*(page-1), page_size) res = self.config[lang].sphinx.Query( text ) items = [] for match in res['matches']: article = unicode(saxutils.escape(self.config[lang].titles[int(match['id'])]), "utf8") items.append((article, article.replace("_", " "))) if res['total_found']/page_size < page: last_page = True if res['total_found'] is 0: page = 0 self.write_header() template = self.config[lang].lookup.get_template("result.mako") self.wfile.write(template.render( items=items, last_page=last_page, page=page, text=unicode(saxutils.escape(text), "utf8"), iw=self.config["main"].iw, )) def output_error_page(self, lang, article): self.send_response(404) self.send_header('Content-type', 'application/xml') self.end_headers() template = self.config[lang].lookup.get_template("error.mako") self.wfile.write(template.render(article=unicode(saxutils.escape(article), "utf8"), iw=self.config["main"].iw)) def output_language_chooser(self): self.write_header() self.wfile.write(' ') for i in self.config.keys(): if "main" not in i: self.wfile.write('%s
'%(i,i)) self.wfile.write('') def output_language_index(self, lang): self.write_header() template = self.config[lang].lookup.get_template("index.mako") self.wfile.write(template.render(iw=self.config["main"].iw)) def output_image_redirect(self, lang, article): self.write_header() template = self.config[lang].lookup.get_template("image_redirect.mako") self.wfile.write(template.render(article=unicode(saxutils.escape(article), "utf8"))) def output_random_redirect(self, lang): article = self.config[lang].titles[randint(1,len(self.config[lang].titles))] self.write_header() template = self.config[lang].lookup.get_template("random_redirect.mako") self.wfile.write(template.render(article=unicode(saxutils.escape(article), "utf8"))) def output_title_redirect(self, lang, article): article = article.replace(' ', '_') self.write_header() template = self.config[lang].lookup.get_template("title_redirect.mako") self.wfile.write(template.render(article=unicode(saxutils.escape(article), "utf8"))) def output_raw(self, lang, file): print os.path.join(lang, file) if os.path.exists(os.path.join(lang, file)): self.send_response(200) self.send_header('Content-type', guess_type(file)) self.end_headers() copyfileobj(open(os.path.join(lang, file)), self.wfile) else: self.output_error_page(lang, file) def write_header(self): #wos.stat = os.fos.stat(file.fileno()) self.send_response(200) self.send_header('Content-type', 'application/xml') #self.send_header("Content-Length", str(wos.stat.st_size + os.stat("de/os.static/header").st_size + os.stat("de/os.static/middle").st_size + os.stat("de/os.static/footer").st_size)) #self.send_header("Last-Modified", self.date_time_string(wos.stat.st_mtime)) self.end_headers() def do_GET(self): self.config = Config() i = self.path.rfind('?') text = '' search = '' page = 1 if i >= 0: self.path, query = self.path[:i], self.path[i+1:] if query: dict = parse_qs(query) if "page" in dict.keys(): page = int(dict["page"][0]) if "text" in dict.keys(): text = dict["text"][0] search = dict.get("search", "") addr = [ unquote(i) for i in self.path.split('/') if i ] if len(addr) > 0 and addr[0] in self.config.keys() and "main" not in addr[0]: lang = addr[0] if len(addr) > 1: addr[1] = '/'.join(addr[1:]) if addr[1].startswith(self.config[lang].special+":"): action = addr[1].split(':', 1)[1] if action == "Random": self.output_random_redirect(lang=lang) else: self.output_error_page(lang=lang, article=addr[1]) elif addr[1].startswith(self.config[lang].image+":"): self.output_image_redirect(lang=lang, article=addr[1]) elif addr[1].startswith(self.config[lang].category+":"): self.output_category_page(lang=lang, article=addr[1], page=page) elif addr[1].startswith("static"): self.output_raw(lang=lang, file=addr[1]) else: self.output_wiki_page(lang=lang, article=addr[1]) else: if text: if search and (self.config[lang].title_search or self.config[lang].fulltext_search): self.output_result_page(lang, text, page) else: self.output_title_redirect(lang, text) else: self.output_language_index(lang=lang) else: self.output_language_chooser() def main(): config = Config() try: server = HTTPServer(('', int(config["main"].port)), MyHandler) print 'httpserver started' server.serve_forever() except KeyboardInterrupt: print '^C received, shutting down server' server.socket.close() if __name__ == '__main__': main()