You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
12 KiB
Python

#!/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('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head> <body>')
for i in self.config.keys():
if "main" not in i:
self.wfile.write('<a href="/%s">%s</a><br />'%(i,i))
self.wfile.write('</body></html>')
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()