From 183013f8f95438d6d0cafd57a60db4c12d8fffe6 Mon Sep 17 00:00:00 2001 From: Luna Mendes Date: Thu, 21 Jun 2018 03:16:13 -0300 Subject: [PATCH] blueprints: add guilds blueprint - gateway.websocket: merge get_guild and get_guild_extra - gateway.websocket: only apply too many shards close when guilds > 2500 - storage: detach state usage - storage: fix large calc on get_guild_extra --- litecord/blueprints/__init__.py | 1 + litecord/blueprints/guilds.py | 60 +++++++++++++++++++++++++++++++++ litecord/blueprints/users.py | 2 +- litecord/dispatcher.py | 4 +++ litecord/gateway/websocket.py | 13 ++++--- litecord/storage.py | 20 +++++------ run.py | 3 +- 7 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 litecord/blueprints/guilds.py create mode 100644 litecord/dispatcher.py diff --git a/litecord/blueprints/__init__.py b/litecord/blueprints/__init__.py index d36112f..54ae434 100644 --- a/litecord/blueprints/__init__.py +++ b/litecord/blueprints/__init__.py @@ -1,3 +1,4 @@ from .gateway import bp as gateway from .auth import bp as auth from .users import bp as users +from .guilds import bp as guilds diff --git a/litecord/blueprints/guilds.py b/litecord/blueprints/guilds.py new file mode 100644 index 0000000..8220228 --- /dev/null +++ b/litecord/blueprints/guilds.py @@ -0,0 +1,60 @@ +from quart import Blueprint, request, current_app as app, jsonify + +from ..auth import token_check +from ..snowflake import get_snowflake +from ..enums import ChannelType + +bp = Blueprint('guilds', __name__) + + +@bp.route('', methods=['POST']) +async def create_guild(): + user_id = await token_check() + j = await request.get_json() + + guild_id = get_snowflake() + + await app.db.execute( + """ + INSERT INTO guilds (id, name, region, icon, owner_id, + verification_level, default_message_notifications, + explicit_content_filter) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + """, guild_id, j['name'], j['region'], j['icon'], user_id, + j.get('verification_level', 0), + j.get('default_message_notifications', 0), + j.get('explicit_content_filter', 0)) + + await app.db.execute(""" + INSERT INTO members (user_id, guild_id) + VALUES ($1, $2) + """, user_id, guild_id) + + everyone_role_id = get_snowflake() + + await app.db.execute(""" + INSERT INTO roles (id, guild_id, name, position, permissions) + VALUES ($1, $2, $3, $4, $5) + """, everyone_role_id, guild_id, '@everyone', 0, 104324161) + + general_id = get_snowflake() + + await app.db.execute(""" + INSERT INTO channels (id, channel_type) + VALUES ($1, $2) + """, general_id, ChannelType.GUILD_TEXT) + + await app.db.execute(""" + INSERT INTO guild_channels (id, guild_id, name, position) + VALUES ($1, $2, $3, $4) + """, general_id, guild_id, 'general', 0) + + await app.db.execute(""" + INSERT INTO guild_text_channels (id) + VALUES ($1) + """, general_id) + + guild_json = await app.storage.get_guild(guild_id, user_id) + guild_extra = await app.storage.get_guild_extra(guild_id, user_id, 250) + + return jsonify({**guild_json, **guild_extra}) diff --git a/litecord/blueprints/users.py b/litecord/blueprints/users.py index 05984f6..6c080fd 100644 --- a/litecord/blueprints/users.py +++ b/litecord/blueprints/users.py @@ -96,7 +96,7 @@ async def leave_guild(guild_id): return '', 204 -@bp.route('/@me/connections', methods=['GET']) +# @bp.route('/@me/connections', methods=['GET']) async def get_connections(): pass diff --git a/litecord/dispatcher.py b/litecord/dispatcher.py new file mode 100644 index 0000000..f0b9512 --- /dev/null +++ b/litecord/dispatcher.py @@ -0,0 +1,4 @@ + +class EventDispatcher: + """Pub/Sub routines for litecord.""" + pass diff --git a/litecord/gateway/websocket.py b/litecord/gateway/websocket.py index c84f2af..c319bdb 100644 --- a/litecord/gateway/websocket.py +++ b/litecord/gateway/websocket.py @@ -109,7 +109,11 @@ class GatewayWebsocket: } for row in guild_ids] return [ - await self.storage.get_guild(row[0], self.state) + { + **await self.storage.get_guild(row[0], user_id), + **await self.storage.get_guild_extra(row[0], user_id, + self.state.large) + } for row in guild_ids ] @@ -122,7 +126,7 @@ class GatewayWebsocket: for guild_obj in unavailable_guilds: guild = await self.storage.get_guild(guild_obj['id'], - self.state) + self.state.user_id) if not guild: continue @@ -162,8 +166,9 @@ class GatewayWebsocket: raise ShardingRequired('Too many guilds for shard ' f'{current_shard}') - if guilds / shard_count > 0.8: - raise ShardingRequired('Too many shards.') + if guilds > 2500 and guilds / shard_count > 0.8: + raise ShardingRequired('Too many shards. ' + f'(g={guilds} sc={shard_count})') if current_shard > shard_count: raise InvalidShard('Shard count > Total shards') diff --git a/litecord/storage.py b/litecord/storage.py index 10cb1a1..44cb4ba 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -28,11 +28,10 @@ class Storage: duser.pop('email') duser.pop('mfa_enabled') duser.pop('verified') - duser.pop('mfa_enabled') return duser - async def get_guild(self, guild_id: int, state=None) -> Dict: + async def get_guild(self, guild_id: int, user_id=None) -> Dict: """Get gulid payload.""" row = await self.db.fetchrow(""" SELECT * @@ -45,8 +44,8 @@ class Storage: drow = dict(row) - if state: - drow['owner'] = drow['owner_id'] == state.user_id + if user_id: + drow['owner'] = drow['owner_id'] == user_id # TODO: Probably a really bad idea to repeat str() calls # Any ideas to make this simpler? @@ -76,7 +75,7 @@ class Storage: async def get_member_data(self, guild_id) -> List[Dict[str, Any]]: """Get member information on a guild.""" members_basic = await self.db.fetch(""" - SELECT user_id, nickname, joined_at + SELECT user_id, nickname, joined_at, deafened, muted FROM members WHERE guild_id = $1 """, guild_id) @@ -145,7 +144,7 @@ class Storage: # type is a SQL keyword, so we can't do # 'overwrite_type AS type' overwrite_rows = await self.db.fetch(""" - SELECT user_id::text AS id, overwrite_type, allow, deny + SELECT target_id::text AS id, overwrite_type, allow, deny FROM channel_overwrites WHERE channel_id = $1 """, row['id']) @@ -165,7 +164,8 @@ class Storage: return channels - async def get_guild_extra(self, guild_id: int, state=None) -> Dict: + async def get_guild_extra(self, guild_id: int, + user_id=None, large=None) -> Dict: """Get extra information about a guild.""" res = {} @@ -175,14 +175,14 @@ class Storage: WHERE guild_id = $1 """, guild_id) - if state: + if user_id and large: joined_at = await self.db.fetchval(""" SELECT joined_at FROM members WHERE guild_id = $1 AND user_id = $2 - """, guild_id, state.user_id) + """, guild_id, user_id) - res['large'] = state.large > member_count + res['large'] = member_count > large res['joined_at'] = joined_at.isoformat() members = await self.get_member_data(guild_id) diff --git a/run.py b/run.py index 96adeb8..537cc87 100644 --- a/run.py +++ b/run.py @@ -8,7 +8,7 @@ from quart import Quart, g, jsonify from logbook import StreamHandler, Logger import config -from litecord.blueprints import gateway, auth, users +from litecord.blueprints import gateway, auth, users, guilds from litecord.gateway import websocket_handler from litecord.errors import LitecordError from litecord.gateway.state_manager import StateManager @@ -36,6 +36,7 @@ app = make_app() app.register_blueprint(gateway, url_prefix='/api/v6') app.register_blueprint(auth, url_prefix='/api/v6') app.register_blueprint(users, url_prefix='/api/v6/users') +app.register_blueprint(guilds, url_prefix='/api/v6/guilds') @app.before_serving