diff --git a/config.ci.py b/config.ci.py index 24d6046..24e9224 100644 --- a/config.ci.py +++ b/config.ci.py @@ -44,6 +44,11 @@ class Config: WS_HOST = 'localhost' WS_PORT = 5001 + #: Where to host the VOICE websocket? + # (a local address the server will bind to) + VWS_HOST = 'localhost' + VWS_PORT = 5003 + # Postgres credentials POSTGRES = {} diff --git a/config.example.py b/config.example.py index e784e8e..532ae7b 100644 --- a/config.example.py +++ b/config.example.py @@ -52,6 +52,11 @@ class Config: WS_HOST = '0.0.0.0' WS_PORT = 5001 + #: Where to host the VOICE websocket? + # (a local address the server will bind to) + VWS_HOST = 'localhost' + VWS_PORT = 5003 + #: Mediaproxy URL on the internet # mediaproxy is made to prevent client IPs being leaked. MEDIA_PROXY = 'localhost:5002' diff --git a/litecord/voice/websocket.py b/litecord/voice/websocket.py new file mode 100644 index 0000000..48146af --- /dev/null +++ b/litecord/voice/websocket.py @@ -0,0 +1,27 @@ +""" + +Litecord +Copyright (C) 2018-2019 Luna Mendes + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +""" + +class VoiceWebsocket: + """Voice websocket class.""" + def __init__(self, ws, app): + self.ws = ws + self.app = app + + async def run(self): + pass diff --git a/litecord/voice/websocket_starter.py b/litecord/voice/websocket_starter.py new file mode 100644 index 0000000..936c143 --- /dev/null +++ b/litecord/voice/websocket_starter.py @@ -0,0 +1,42 @@ +""" + +Litecord +Copyright (C) 2018-2019 Luna Mendes + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +""" + +import urllib.urlparse +from litecord.voice.websocket import VoiceWebsocket + +async def voice_websocket_handle(app, ws, url): + """Main handler to instantiate a VoiceWebsocket + with the given url.""" + args = urllib.parse.parse_qs( + urllib.parse.urlparse(url).query + ) + + try: + gw_version = args['v'][0] + except (KeyError, IndexError): + gw_version = '3' + + if gw_version not in ('1', '2', '3'): + return await ws.close(1000, 'Invalid gateway version') + + # TODO: select a different VoiceWebsocket runner depending on + # version. however i do not have docs on voice websockets + # earlier than v3. + vws = VoiceWebsocket(ws, app) + await vws.run() diff --git a/run.py b/run.py index 1c11556..edc67fb 100644 --- a/run.py +++ b/run.py @@ -61,7 +61,6 @@ from litecord.blueprints.user.billing_job import ( from litecord.ratelimits.handler import ratelimit_handler from litecord.ratelimits.main import RatelimitManager -from litecord.gateway import websocket_handler from litecord.errors import LitecordError from litecord.gateway.state_manager import StateManager from litecord.storage import Storage @@ -72,6 +71,9 @@ from litecord.images import IconManager from litecord.jobs import JobManager from litecord.voice.manager import VoiceManager +from litecord.gateway import websocket_handler +from litecord.voice.websocket_starter import voice_websocket_handler + from litecord.utils import LitecordJSONEncoder # setup logbook @@ -295,6 +297,19 @@ async def post_app_start(app_): app_.sched.spawn(api_index(app_)) +def start_websocket(host, port, ws_handler) -> asyncio.Future: + """Start a websocket. Returns the websocket future""" + 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 ws_handler(app, ws, url) + + return websockets.serve(_wrapper, host, port) + + @app.before_serving async def app_before_serving(): log.info('opening db') @@ -307,19 +322,21 @@ async def app_before_serving(): init_app_managers(app) - # start the websocket, etc - host, port = app.config['WS_HOST'], app.config['WS_PORT'] - log.info(f'starting websocket at {host} {port}') + # start gateway websocket and voice websocket + ws_fut = start_websocket( + app.config['WS_HOST'], app.config['WS_PORT'], + websocket_handler + ) - async def _wrapper(ws, url): - # We wrap the main websocket_handler - # so we can pass quart's app object. - await websocket_handler(app, ws, url) + vws_fut = start_websocket( + app.config['VWS_HOST'], app.config['VWS_PORT'], + voice_websocket_handler + ) - ws_future = websockets.serve(_wrapper, host, port) await post_app_start(app) - await ws_future + await ws_fut + await vws_fut @app.after_serving