litecord/run.py

146 lines
3.9 KiB
Python

import asyncio
import sys
import asyncpg
import logbook
import logging
import websockets
from quart import Quart, g, jsonify
from logbook import StreamHandler, Logger
from logbook.compat import redirect_logging
import config
from litecord.blueprints import gateway, auth, users, guilds, channels, \
webhooks, science, voice
from litecord.gateway import websocket_handler
from litecord.errors import LitecordError
from litecord.gateway.state_manager import StateManager
from litecord.storage import Storage
from litecord.dispatcher import EventDispatcher
from litecord.presence import PresenceManager
# setup logbook
handler = StreamHandler(sys.stdout, level=logbook.INFO)
handler.push_application()
log = Logger('litecord.boot')
redirect_logging()
def make_app():
app = Quart(__name__)
app.config.from_object(f'config.{config.MODE}')
is_debug = app.config.get('DEBUG', False)
app.debug = is_debug
if is_debug:
log.info('on debug')
handler.level = logbook.DEBUG
app.logger.level = logbook.DEBUG
# always keep websockets on INFO
logging.getLogger('websockets').setLevel(logbook.INFO)
return app
app = make_app()
bps = {
gateway: None,
auth: '/auth',
users: '/users',
guilds: '/guilds',
channels: '/channels',
webhooks: None,
science: None,
voice: '/voice'
}
for bp, suffix in bps.items():
suffix = suffix or ''
app.register_blueprint(bp, url_prefix=f'/api/v6{suffix}')
@app.after_request
async def app_after_request(resp):
resp.headers['Access-Control-Allow-Origin'] = 'https://ptb.discordapp.com'
resp.headers['Access-Control-Allow-Headers'] = ('*, X-Super-Properties, '
'X-Fingerprint, '
'X-Context-Properties, '
'X-Failed-Requests, '
'Content-Type, '
'Authorization, '
'Origin, '
'If-None-Match')
resp.headers['Access-Control-Allow-Methods'] = '*'
return resp
@app.before_serving
async def app_before_serving():
log.info('opening db')
app.db = await asyncpg.create_pool(**app.config['POSTGRES'])
g.app = app
app.loop = asyncio.get_event_loop()
g.loop = asyncio.get_event_loop()
app.state_manager = StateManager()
app.dispatcher = EventDispatcher(app.state_manager)
app.storage = Storage(app.db)
app.presence = PresenceManager(app.storage,
app.state_manager, app.dispatcher)
app.storage.presence = app.presence
# start the websocket, etc
host, port = app.config['WS_HOST'], app.config['WS_PORT']
log.info(f'starting websocket at {host} {port}')
async def _wrapper(ws, url):
# We wrap the main websocket_handler
# so we can pass quart's app object.
await websocket_handler((app.db, app.state_manager, app.storage,
app.loop, app.dispatcher, app.presence),
ws, url)
ws_future = websockets.serve(_wrapper, host, port)
await ws_future
@app.after_serving
async def app_after_serving():
log.info('closing db')
await app.db.close()
@app.errorhandler(LitecordError)
async def handle_litecord_err(err):
try:
ejson = err.json
except IndexError:
ejson = {}
return jsonify({
'error': True,
# 'code': err.code,
'status': err.status_code,
'message': err.message,
**ejson
}), err.status_code
@app.errorhandler(500)
async def handle_500(err):
return jsonify({
'error': True,
'message': repr(err),
'internal_server_error': True,
})
@app.route('/')
async def index():
return 'hewwo'