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