155 lines
5.4 KiB
Python
155 lines
5.4 KiB
Python
# python3 by 121
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
'''
|
|
async web application.
|
|
'''
|
|
|
|
import logging; logging.basicConfig(level=logging.INFO)
|
|
|
|
import asyncio, os, json, time
|
|
from datetime import datetime
|
|
|
|
from aiohttp import web
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
from config import configs
|
|
|
|
import orm
|
|
from coroweb import add_routes, add_static
|
|
|
|
from handlers import cookie2user, COOKIE_NAME
|
|
|
|
def init_jinja2(app, **kw):
|
|
logging.info('init jinja2...')
|
|
options = dict(
|
|
autoescape = kw.get('autoescape', True),
|
|
block_start_string = kw.get('block_start_string', '{%'),
|
|
block_end_string = kw.get('block_end_string', '%}'),
|
|
variable_start_string = kw.get('variable_start_string', '{{'),
|
|
variable_end_string = kw.get('variable_end_string', '}}'),
|
|
auto_reload = kw.get('auto_reload', True)
|
|
)
|
|
path = kw.get('path', None)
|
|
if path is None:
|
|
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
|
|
logging.info('set jinja2 template path: %s' % path)
|
|
env = Environment(loader=FileSystemLoader(path), **options)
|
|
filters = kw.get('filters', None)
|
|
if filters is not None:
|
|
for name, f in filters.items():
|
|
env.filters[name] = f
|
|
app['__templating__'] = env
|
|
|
|
@asyncio.coroutine
|
|
def logger_factory(app, handler):
|
|
@asyncio.coroutine
|
|
def logger(request):
|
|
logging.info('Request: %s %s' % (request.method, request.path))
|
|
# yield from asyncio.sleep(0.3)
|
|
return (yield from handler(request))
|
|
return logger
|
|
|
|
@asyncio.coroutine
|
|
def auth_factory(app, handler):
|
|
@asyncio.coroutine
|
|
def auth(request):
|
|
logging.info('check user: %s %s' % (request.method, request.path))
|
|
request.__user__ = None
|
|
cookie_str = request.cookies.get(COOKIE_NAME)
|
|
if cookie_str:
|
|
user = yield from cookie2user(cookie_str)
|
|
if user:
|
|
logging.info('set current user: %s' % user.email)
|
|
request.__user__ = user
|
|
if request.path.startswith('/manage/') and (request.__user__ is None or not request.__user__.admin):
|
|
return web.HTTPFound('/signin')
|
|
return (yield from handler(request))
|
|
return auth
|
|
|
|
@asyncio.coroutine
|
|
def data_factory(app, handler):
|
|
@asyncio.coroutine
|
|
def parse_data(request):
|
|
if request.method == 'POST':
|
|
if request.content_type.startswith('application/json'):
|
|
request.__data__ = yield from request.json()
|
|
logging.info('request json: %s' % str(request.__data__))
|
|
elif request.content_type.startswith('application/x-www-form-urlencoded'):
|
|
request.__data__ = yield from request.post()
|
|
logging.info('request form: %s' % str(request.__data__))
|
|
return (yield from handler(request))
|
|
return parse_data
|
|
|
|
@asyncio.coroutine
|
|
def response_factory(app, handler):
|
|
@asyncio.coroutine
|
|
def response(request, t=None):
|
|
logging.info('Response handler...')
|
|
r = yield from handler(request)
|
|
if isinstance(r, web.StreamResponse):
|
|
return r
|
|
if isinstance(r, bytes):
|
|
resp = web.Response(body=r)
|
|
resp.content_type = 'application/octet-stream'
|
|
return resp
|
|
if isinstance(r, str):
|
|
if r.startswith('redirect:'):
|
|
return web.HTTPFound(r[9:])
|
|
resp = web.Response(body=r.encode('utf-8'))
|
|
resp.content_type = 'text/html;charset=utf-8'
|
|
return resp
|
|
if isinstance(r, dict):
|
|
template = r.get('__template__')
|
|
if template is None:
|
|
resp = web.Response(body=json.dumps(r, ensure_ascii=False, default=lambda o: o.__dict__).encode('utf-8'))
|
|
resp.content_type = 'application/json;charset=utf-8'
|
|
return resp
|
|
else:
|
|
r['__user__'] = request.__user__
|
|
resp = web.Response(body=app['__templating__'].get_template(template).render(**r).encode('utf-8'))
|
|
resp.content_type = 'text/html;charset=utf-8'
|
|
return resp
|
|
if isinstance(r, int) and t >= 100 and t < 600:
|
|
return web.Response(t)
|
|
if isinstance(r, tuple) and len(r) == 2:
|
|
t, m = r
|
|
if isinstance(t, int) and t >= 100 and t < 600:
|
|
return web.Response(t, str(m))
|
|
# default:
|
|
resp = web.Response(body=str(r).encode('utf-8'))
|
|
resp.content_type = 'text/plain;charset=utf-8'
|
|
return resp
|
|
return response
|
|
|
|
def datetime_filter(t):
|
|
delta = int(time.time() - t)
|
|
if delta < 60:
|
|
return u'1分钟前'
|
|
if delta < 3600:
|
|
return u'%s分钟前' % (delta // 60)
|
|
if delta < 86400:
|
|
return u'%s小时前' % (delta // 3600)
|
|
if delta < 604800:
|
|
return u'%s天前' % (delta // 86400)
|
|
dt = datetime.fromtimestamp(t)
|
|
return u'%s年%s月%s日' % (dt.year, dt.month, dt.day)
|
|
|
|
@asyncio.coroutine
|
|
def init(loop):
|
|
yield from orm.create_pool(loop=loop, **configs.db)
|
|
app = web.Application(loop=loop, middlewares=[
|
|
logger_factory, auth_factory, response_factory
|
|
])
|
|
init_jinja2(app, filters=dict(datetime=datetime_filter))
|
|
add_routes(app, 'handlers')
|
|
add_static(app)
|
|
srv = yield from loop.create_server(app.make_handler(), '127.0.0.1', 9000)
|
|
logging.info('server started at http://127.0.0.1:9000...')
|
|
return srv
|
|
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_until_complete(init(loop))
|
|
loop.run_forever()
|