Esempio n. 1
0
 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
Esempio n. 2
0
 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
Esempio n. 3
0
 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
Esempio n. 4
0
    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
Esempio n. 5
0
 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
Esempio n. 6
0
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
Esempio n. 7
0
 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
Esempio n. 8
0
    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)
Esempio n. 9
0
 def on_heartbeat(self, context, data=None):
     context['heartbeat'] = time.time()
     util.print_info(f'Received heartbeat from {context["username"]}.')
     return context