def dispatch_event(self, context, event, data): handler = 'on_' + event if hasattr(self, handler): context = getattr(self, handler)(context, data) else: util.print_info('Received invalid event.') return context
def redis(self): if self._redis is not None: try: self._redis.ping() except ConnectionError: util.print_info('Lost connection to Redis.', False) del self._redis if self._redis is None: self._redis = Redis.from_url(config.redis_uri) util.print_info('Connecting to Redis...', False) return self._redis
def handle_client_message(self, context, message): try: payload = json.loads(message.decode('utf-8')) if isinstance(payload, dict) and payload.get('ev'): event = payload['ev'] data = payload.get('d', {}) if not context['connected'] and event != 'connect': self.error('You are not connected.') return context context = self.dispatch_event(context, event, data) except (json.JSONDecodeError, KeyError): util.print_info('Received invalid websockets payload.') return context
def on_message(self, context, data): user = context['user'] username = context['username'] avatar_url = context['avatar_url'] # check if user has been banned if user.is_banned(): raise ClientError('You have been banned.') # check if user has been timed out timeout = util.shget(self.redis, 'timed-out-members', self.webchat_user_key(context)) if timeout: timeout = json.loads(timeout.decode('utf-8')) ttl = util.shttl(self.redis, 'timed-out-members', self.webchat_user_key(context)) detail = f'You have to wait another {ttl} seconds.' if timeout.get('reason'): detail += f'\nReason: {timeout["reason"]}' self.error('You have been timed out.', detail) return context # push to channel util.print_info(f'{username} says: {data["content"]}') message = { 'id': str(uuid.uuid4()), 'content': data['content'], 'channel_name': data['channel_name'], 'author': self.format_user(context), 'created_at': time.time(), } self.publish_event('message', message, 'channel') # add message to history util.zhaddex(self.redis, 'webchat-message-history', message['id'], config.message_history_ttl, json.dumps(message, separators=(',', ':')), message['created_at'], config.message_history_length) # push to bot for discord users self.publish_event( 'webchat_message', { 'channel_name': data['channel_name'], 'username': username, 'avatar_url': avatar_url, 'content': data['content'], }, 'bot') self.ack() return context
def handle_channel_message(self, context, message): if context.get('connected', False): self.check_client_alive(context) try: payload = json.loads(message.decode('utf-8')) if isinstance(payload, dict) and payload.get('ev'): event = payload['ev'] data = payload.get('d', {}) if event == 'whisper': self_key = self.webchat_user_key(context) author_key = self.webchat_user_key(data['author']) target_key = self.webchat_user_key(data['target']) if self_key not in [author_key, target_key]: # doesn't concern us return context except (json.JSONDecodeError, KeyError): util.print_info('Received invalid channel payload.') self.client_publish(message) return context
def remove_turbo_role(discord_id): member_url = f'{guild_url}/members/{discord_id}' # check if member exists, if not report success to prevent lock response = requests.get(member_url, headers=request_header) error = response.json if (response.status_code == 404 or error.get('key', 0) == 10007): return True # remove member from role response = requests.delete('%s/roles/%s' % (member_url, discord.turbo_role_id), headers=request_header) if (response.status_code == 204): return True # if we errored we want to log the error error = response.json print_info('Discord Error: ' + error.get('message')) return False
def on_connect(self, context, data=None): util.print_info(f'{context["username"]} connected to webchat.') context['heartbeat'] = time.time() client_count = self.redis.hincrby('webchat-clients', self.webchat_user_key(context), 1) member = self.format_user(context) # first client publishes connect if client_count == 1: self.publish_event('connect', member, 'channel') self.redis.hset('webchat-online-members', self.webchat_user_key(context), json.dumps(member, separators=(',', ':'))) self.publish_event( 'connection_success', { 'you': member, 'online_members': self.get_online_members(), 'message_history': self.get_message_history(), }, ) context['connected'] = True return context
def open_websocket(self, env): context = None try: user = self.authenticate(env) access_level = User.get_access_level(user) if access_level < self.min_access_level: return uwsgi.websocket_handshake() util.print_info('Opening websocket connection', False) client_count = self.redis.get('websocket-clients') if client_count: client_count = int(client_count.decode('utf-8')) if client_count >= config.websockets_max_clients: raise ClientError('No available slots.') self.redis.incr('websocket-clients') context = True channel = self.redis.pubsub() channel.subscribe(self.name) websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() context = self.init_context(env, user, redis_fd) while True: ready = gevent.select.select([websocket_fd, redis_fd], [], [], 4.0) if not ready[0]: # send ping on timeout uwsgi.websocket_recv_nb() for fd in ready[0]: if fd == websocket_fd: # client message context = self.fetch_and_handle_client_message(context) elif fd == redis_fd: # channel message message = channel.parse_response() if message[0] == b'message': context = self.handle_channel_message( context, message[2]) except ClientTimeout: util.print_info('Websocket connection client timeout.') except ClientDisconnect: util.print_info('Websocket connection client disconnected.') except ClientError as error: util.print_exception('Websocket client error', error, False, print_traceback=False) except IOError as error: # Socket Error util.print_exception('Websocket connection closed', error, False, print_traceback=False) except DBError as error: # Database Error util.print_exception('Database Error occured: ', error) except OAuth2Error as error: # OAuth 2.0 Error util.print_exception('OAuth 2.0 Error occured: ', error) except Exception as error: # Unknown Exception util.print_exception('Unexpected Error occured: ', error, False) finally: self.cleanup(context)
def on_heartbeat(self, context, data=None): context['heartbeat'] = time.time() util.print_info(f'Received heartbeat from {context["username"]}.') return context