mirror of https://gitlab.com/litecord/litecord.git
lvsp_conn: add basic INFO handling for channel assign
- lvsp: finish defining data for channel info messages - lvsp_conn: add send_info() - lvsp_opcodes: add InfoTable, InfoReverse - voice.manager: handle channels without bitrate
This commit is contained in:
parent
00100f9abb
commit
579a71dd9b
21
docs/lvsp.md
21
docs/lvsp.md
|
|
@ -175,24 +175,37 @@ Request a channel to be created inside the voice server.
|
||||||
The Server MUST reply back with a CHANNEL\_ASSIGN when resources are
|
The Server MUST reply back with a CHANNEL\_ASSIGN when resources are
|
||||||
allocated for the channel.
|
allocated for the channel.
|
||||||
|
|
||||||
**TODO:** fields
|
| field | type | description |
|
||||||
|
| --: | :-- | :-- |
|
||||||
|
| channel\_id | snowflake | channel id |
|
||||||
|
| guild\_id | Optional[snowflake] | guild id, not provided if dm / group dm |
|
||||||
|
| channel\_properties | ChannelProperties | channel properties |
|
||||||
|
|
||||||
|
#### ChannelProperties
|
||||||
|
|
||||||
|
| field | type | description |
|
||||||
|
| --: | :-- | :-- |
|
||||||
|
| bitrate | integer | channel bitrate |
|
||||||
|
|
||||||
### CHANNEL\_ASSIGN
|
### CHANNEL\_ASSIGN
|
||||||
|
|
||||||
Sent by the Server to signal the successful creation of a voice channel.
|
Sent by the Server to signal the successful creation of a voice channel.
|
||||||
|
|
||||||
**TODO:** fields
|
| field | type | description |
|
||||||
|
| --: | :-- | :-- |
|
||||||
|
| channel\_id | snowflake | channel id |
|
||||||
|
| guild\_id | Optional[snowflake] | guild id, not provided if dm / group dm |
|
||||||
|
|
||||||
### CHANNEL\_UPDATE
|
### CHANNEL\_UPDATE
|
||||||
|
|
||||||
Sent by the client to signal an update to the properties of a channel,
|
Sent by the client to signal an update to the properties of a channel,
|
||||||
such as its bitrate.
|
such as its bitrate.
|
||||||
|
|
||||||
**TODO:** fields
|
Same data as CHANNEL\_REQ.
|
||||||
|
|
||||||
### CHANNEL\_DESTROY
|
### CHANNEL\_DESTROY
|
||||||
|
|
||||||
Sent by the client to signal the destruction of a voice channel. Be it
|
Sent by the client to signal the destruction of a voice channel. Be it
|
||||||
a channel being deleted, or all members in it leaving.
|
a channel being deleted, or all members in it leaving.
|
||||||
|
|
||||||
**TODO:** fields
|
Same data as CHANNEL\_ASSIGN.
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
import websockets
|
import websockets
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
from litecord.voice.lvsp_opcodes import OPCodes as OP
|
from litecord.voice.lvsp_opcodes import OPCodes as OP, InfoTable, InfoReverse
|
||||||
|
|
||||||
log = Logger(__name__)
|
log = Logger(__name__)
|
||||||
|
|
||||||
|
|
@ -65,6 +66,16 @@ class LVSPConnection:
|
||||||
'd': data
|
'd': data
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async def send_info(self, info_type: str, info_data: Dict):
|
||||||
|
"""Send an INFO message down the websocket."""
|
||||||
|
await self.send({
|
||||||
|
'op': OP.info,
|
||||||
|
'd': {
|
||||||
|
'type': InfoTable[info_type.upper()],
|
||||||
|
'data': info_data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async def _heartbeater(self, hb_interval: int):
|
async def _heartbeater(self, hb_interval: int):
|
||||||
try:
|
try:
|
||||||
await asyncio.sleep(hb_interval)
|
await asyncio.sleep(hb_interval)
|
||||||
|
|
@ -121,6 +132,35 @@ class LVSPConnection:
|
||||||
await self._update_health(msg['health'])
|
await self._update_health(msg['health'])
|
||||||
self._start_hb()
|
self._start_hb()
|
||||||
|
|
||||||
|
async def _handle_6(self, msg):
|
||||||
|
"""Handle INFO messages."""
|
||||||
|
info = msg['d']
|
||||||
|
info_type_str = InfoReverse[info['type']].lower()
|
||||||
|
|
||||||
|
try:
|
||||||
|
info_handler = getattr(self, f'_handle_info_{info_type_str}')
|
||||||
|
except AttributeError:
|
||||||
|
return
|
||||||
|
|
||||||
|
await info_handler(info['data'])
|
||||||
|
|
||||||
|
async def _handle_info_channel_assign(self, data: dict):
|
||||||
|
"""called by the server once we got a channel assign."""
|
||||||
|
try:
|
||||||
|
channel_id = data['channel_id']
|
||||||
|
channel_id = int(channel_id)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
guild_id = data['guild_id']
|
||||||
|
guild_id = int(guild_id)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
guild_id = None
|
||||||
|
|
||||||
|
main_key = guild_id if guild_id is not None else channel_id
|
||||||
|
await self.lvsp.assign(main_key, self.hostname)
|
||||||
|
|
||||||
async def _loop(self):
|
async def _loop(self):
|
||||||
while True:
|
while True:
|
||||||
msg = await self.recv()
|
msg = await self.recv()
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ class LVSPManager:
|
||||||
# maps regions to server hostnames
|
# maps regions to server hostnames
|
||||||
self.servers = defaultdict(list)
|
self.servers = defaultdict(list)
|
||||||
|
|
||||||
# maps guilds to server hostnames
|
# maps Union[GuildID, DMId, GroupDMId] to server hostnames
|
||||||
self.guild_servers = {}
|
self.assign = {}
|
||||||
|
|
||||||
self.app.loop.create_task(self._spawn())
|
self.app.loop.create_task(self._spawn())
|
||||||
|
|
||||||
|
|
@ -119,12 +119,12 @@ class LVSPManager:
|
||||||
|
|
||||||
return conn.health
|
return conn.health
|
||||||
|
|
||||||
async def get_server(self, guild_id: int) -> str:
|
async def get_guild_server(self, guild_id: int) -> str:
|
||||||
"""Get a voice server for the given guild, assigns
|
"""Get a voice server for the given guild, assigns
|
||||||
one if there isn't any."""
|
one if there isn't any"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hostname = self.guild_servers[guild_id]
|
hostname = self.assign[guild_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
region = await self.guild_region(guild_id)
|
region = await self.guild_region(guild_id)
|
||||||
|
|
||||||
|
|
@ -137,3 +137,7 @@ class LVSPManager:
|
||||||
hostname = sorted_servers[0]
|
hostname = sorted_servers[0]
|
||||||
|
|
||||||
return hostname
|
return hostname
|
||||||
|
|
||||||
|
async def assign_conn(self, key: int, hostname: str):
|
||||||
|
"""Assign a connection to a given key in the assign map"""
|
||||||
|
self.assign[key] = hostname
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,16 @@ class OPCodes:
|
||||||
heartbeat = 4
|
heartbeat = 4
|
||||||
heartbeat_ack = 5
|
heartbeat_ack = 5
|
||||||
info = 6
|
info = 6
|
||||||
|
|
||||||
|
|
||||||
|
InfoTable = {
|
||||||
|
'CHANNEL_REQ': 0,
|
||||||
|
'CHANNEL_ASSIGN': 1,
|
||||||
|
'CHANNEL_UPDATE': 2,
|
||||||
|
'CHANNEL_DESTROY': 3,
|
||||||
|
'VST_CREATE': 4,
|
||||||
|
'VST_UPDATE': 5,
|
||||||
|
'VST_LEAVE': 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoReverse = {v: k for k, v in InfoTable.items()}
|
||||||
|
|
|
||||||
|
|
@ -156,24 +156,19 @@ class VoiceManager:
|
||||||
await self.create_state(old_voice_key, {'channel_id': channel_id})
|
await self.create_state(old_voice_key, {'channel_id': channel_id})
|
||||||
|
|
||||||
async def _lvsp_info_guild(self, guild_id, info_type, info_data):
|
async def _lvsp_info_guild(self, guild_id, info_type, info_data):
|
||||||
hostname = await self.lvsp.get_server(guild_id)
|
hostname = await self.lvsp.get_guild_server(guild_id)
|
||||||
conn = self.lvsp.get_conn(hostname)
|
conn = self.lvsp.get_conn(hostname)
|
||||||
|
|
||||||
# TODO: impl send_info
|
|
||||||
await conn.send_info(info_type, info_data)
|
await conn.send_info(info_type, info_data)
|
||||||
|
|
||||||
async def _create_ctx_guild(self, guild_id, channel_id):
|
async def _create_ctx_guild(self, guild_id, channel_id):
|
||||||
chan = await self.app.storage.get_channel(channel_id)
|
chan = await self.app.storage.get_channel(channel_id)
|
||||||
|
|
||||||
# TODO: this, but properly
|
await self._lvsp_info_guild(guild_id, 'CHANNEL_REQ', {
|
||||||
# TODO: when the server sends a reply to CHAN_REQ, we need to update
|
|
||||||
# LVSPManager.guild_servers.
|
|
||||||
await self._lvsp_info_guild(guild_id, 'CHAN_REQ', {
|
|
||||||
'guild_id': str(guild_id),
|
'guild_id': str(guild_id),
|
||||||
'channel_id': str(channel_id),
|
'channel_id': str(channel_id),
|
||||||
|
|
||||||
'channel_properties': {
|
'channel_properties': {
|
||||||
'bitrate': chan['bitrate']
|
'bitrate': chan.get('bitrate', 96)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue