--- /dev/null
+# -*- coding: utf-8
+'''router: Routing and preprocess system for Web applications'''
+
+import httplib
+import json
+
+class Response(object):
+ def __init__(self, start_response):
+ self.status = None
+ self.response_headers = []
+ self.finished = False
+ self.response_bodies = []
+ self.start_response = start_response
+
+ def add_response(self, response):
+ self.response_bodies.append(response)
+
+ def add_header(self, name, value):
+ self.response_headers.append((name, value))
+
+ def set_status_code(self, code):
+ self.status = "{} {}".format(code, httplib.responses[code])
+
+ def render_json(self, data):
+ self.add_header("Content-Type", "application/json")
+ raw_json = json.dumps(data, ensure_ascii=False)
+ self.add_response(raw_json.encode('utf-8'))
+
+ def render(self, code=None, **kwargs):
+ if code is not None:
+ self.set_status_code(code)
+ if 'json' in kwargs:
+ return self.render_json(kwargs["json"])
+
+ def finish(self, code=None, body=None):
+ if code is not None:
+ self.set_status_code(code)
+
+ if self.status is None:
+ self.set_status_code(200)
+
+ if body is not None:
+ self.add_response(body)
+
+ self.start_response(self.status, self.response_headers)
+ self.finished = True
+
+
+class Request(object):
+ def __init__(self, environ):
+ self.environ = environ
+ self.body = self.decode_request_body()
+
+ def decode_request_body(self):
+ content_type = self.environ['CONTENT_TYPE']
+ if content_type == 'application/json':
+ return self._decode_json()
+ return None
+
+ def _decode_json(self):
+ body_len = int(self.environ.get('CONTENT_LENGTH', 0))
+ if body_len > 0:
+ raw_req = self.environ['wsgi.input']
+ raw_json = raw_req.read(body_len)
+ return json.loads(raw_json)
+ return None
+
+
+class Router(object):
+ def __init__(self):
+ pass
+
+ def __call__(self, environ, start_response):
+ req = Request(environ)
+ resp = Response(start_response)
+
+ method = environ['REQUEST_METHOD']
+ try:
+ if method == 'GET':
+ self.get(req, resp)
+ elif method == 'POST':
+ self.post(req, resp)
+ else:
+ self.fallback(req, resp)
+ except AttributeError:
+ self.fallback(req, resp)
+
+ if not resp.finished:
+ resp.finish()
+
+ return resp.response_bodies
+
+ def fallback(self, req, resp):
+ resp.finish(500, "Internal Server Error")
+
+
+
--- /dev/null
+# -*- coding: utf-8
+''' searchd: Search daemon for Newslash'''
+
+from router import Router
+import lucene_wrapper
+
+class Searchd(Router):
+ def __init__(self):
+ super(Searchd, self).__init__()
+
+ def get(self, req, resp):
+ resp.render(200, json={"error": 0})
+
+ def post(self, req, resp):
+ # check request body is valid
+ if req.body is None:
+ resp.render(400)
+ return
+
+ # start query
+ query = req.body.get('query', '')
+ limit = req.body.get('limit', 10)
+
+ searcher = lucene_wrapper.Searcher(index_directory="./lucene_index")
+ query = lucene_wrapper.Query("content_text", query)
+ result = searcher.search(query, limit)
+
+ resp_body = {
+ "total_hits": result.total_hits,
+ "hits": []
+ }
+
+ for item in result:
+ resp_body["hits"].append({ "number": item.number,
+ "id": item.id,
+ "title": item.title,
+ "content_text": item.content_text})
+
+ resp.render(200, json=resp_body)