示例#1
0
    async def decode_tracks(self, tracks):
        """
        Decodes a list of base64-encoded track strings.
        
        Parameters
        ----------
        tracks : `list` of `str`
            A list of base64-encoded track strings.
        
        Returns
        -------
        tracks : `list` of ``Track``
            The decoded tracks.
        
        Raises
        ------
        RuntimeError
            - If there are no available nodes.
            - If the ``SolarClient``'s client is already deconstructed.
        SolarAuthenticationError
            Authentication failed towards the node.
        """
        client = self._client_reference()
        if client is None:
            raise RuntimeError(
                f'`{self.__class__.__name__}` client is deconstructed.')

        available_nodes = self.available_nodes
        if not available_nodes:
            raise RuntimeError('No available nodes!')

        node = choice(available_nodes)

        async with client.http.post(
                f'http://{node._host}:{node._port}/decodetracks',
                headers={
                    AUTHORIZATION: node._password,
                    CONTENT_TYPE: 'application/json',
                },
                data=to_json(tracks),
        ) as response:
            if response.status == 200:
                track_datas = await response.json()

            elif response.status in (401, 403):
                raise SolarAuthenticationError(node, response)

            else:
                track_datas = None

        if (track_datas is None) or (not track_datas):
            tracks = []
        else:
            tracks = [Track(track_data) for track_data in track_datas]

        return tracks
示例#2
0
    async def routeplanner_free_address(self, node, address):
        """
        Removes a single address from the addresses which are currently marked as failing.
        
        This method is a coroutine.
        
        Parameters
        ----------
        node : ``SolarNode``
            The node to use for the query.
        address : `str`
            The address to free.
        
        Returns
        -------
        success : `bool`
            Whether the address is freed up.
        
        Raises
        ------
        SolarAuthenticationError
            Authentication failed towards the node.
        RuntimeError
            If the ``SolarClient``'s client is already deconstructed.
        """
        client = self._client_reference()
        if client is None:
            raise RuntimeError(
                f'`{self.__class__.__name__}` client is deconstructed.')

        async with client.http.post(
                f'http://{node._host}:{node._port}/routeplanner/free/address',
                headers={
                    AUTHORIZATION: node._password,
                    CONTENT_TYPE: 'application/json',
                },
                data=to_json({'address': address}),
        ) as response:
            status = response.status
            if status in (401, 403):
                raise SolarAuthenticationError(node, response)

            if status == 204:
                # Success
                return True

            if status == 500:
                # The node has no routeplanner configured.
                return False

            # Unexpected case.
            return False
示例#3
0
文件: node.py 项目: HuyaneMatsu/hata
    async def _send(self, data):
        """
        Sends the passed data to the node via the websocket connection.
        
        Parameters
        ----------
        data : `dict`
            The dict to send to Lavalink.
        """
        data = to_json(data)

        websocket = self.websocket
        if (websocket is not None):
            await websocket.send(data)
示例#4
0
    def _save(self):
        """
        Saves the settings to it's respective path.
        """
        data = {}

        bot_directories = self.bot_directories
        if (bot_directories is not None):
            data[KEY_BOT_DIRECTORIES] = bot_directories

        raw_data = to_json(data)

        with open(join_paths(self.directory_path, SETTINGS_FILE_NAME),
                  'w') as file:
            file.write(raw_data)
示例#5
0
 async def send_as_json(self, data):
     """
     Sends the data as json to Discord on the gateway's ``.websocket``. If there is no websocket, or the websocket
     is closed will not raise.
     
     This method is a coroutine.
     
     Parameters
     ----------
     data : `dict` of (`str`, `Any`) items or `list` of `Any`
     """
     websocket = self.websocket
     if websocket is None:
         return
     
     if await self.rate_limit_handler:
         return
     
     try:
         await websocket.send(to_json(data))
     except ConnectionClosed:
         pass
示例#6
0
 async def send_as_json(self, data):
     """
     Sends the data as json to Discord on the gateway's ``.websocket``.
     
     This method is a coroutine.
     
     Parameters
     ----------
     data : `dict` of (`str`, `Any`) items or `list` of `Any`
     """
     data = to_json(data)
     
     tasks = []
     for gateway in self.gateways:
         task = Task(self._send_json(gateway, data), KOKORO)
         tasks.append(task)
     
     done, pending = await WaitTillExc(tasks, KOKORO)
     
     for task in pending:
         task.cancel()
     
     for task in done:
         task.result()
示例#7
0
    async def _request(self,
                       method,
                       url,
                       rate_limit_handler,
                       data=None,
                       query_parameters=None):
        """
        Does a request towards top.gg API.
        
        This method is a coroutine.
        
        Parameters
        ----------
        method : `str`
            Http method.
        url : `str`
            Endpoint to do request towards.
        rate_limit_handler : ``RateLimitHandlerBase`
            Rate limit handle to handle rate limit as.
        data : `None`, `Any` = `None`, Optional
            Json serializable data.
        query_parameters : `None`, `Any` = `None`, Optional
            Query parameters.
        
        Raises
        ------
        ConnectionError
            No internet connection.
        TopGGGloballyRateLimited
            If the client got globally rate limited by top.gg and `raise_on_top_gg_global_rate_limit` was given as
            `True`.
        TopGGHttpException
            Any exception raised by top.gg api.
        """
        headers = self._headers.copy()

        if (data is not None):
            headers[CONTENT_TYPE] = 'application/json'
            data = to_json(data)

        try_again = 2
        while try_again > 0:
            global_rate_limit_expires_at = self._global_rate_limit_expires_at
            if global_rate_limit_expires_at > LOOP_TIME():
                if self._raise_on_top_gg_global_rate_limit:
                    raise TopGGGloballyRateLimited(None)

                future = Future(KOKORO)
                KOKORO.call_at(global_rate_limit_expires_at,
                               Future.set_result_if_pending, future, None)
                await future

            async with rate_limit_handler.ctx():
                try:
                    async with RequestContextManager(
                            self.http._request(method, url, headers, data,
                                               query_parameters)) as response:
                        response_data = await response.text(encoding='utf-8')
                except OSError as err:
                    if not try_again:
                        raise ConnectionError(
                            'Invalid address or no connection with Top.gg.'
                        ) from err

                    await sleep(0.5 / try_again, KOKORO)

                    try_again -= 1
                    continue

                response_headers = response.headers
                status = response.status

                content_type_headers = response_headers.get(CONTENT_TYPE, None)
                if (content_type_headers is not None
                    ) and content_type_headers.startswith('application/json'):
                    response_data = from_json(response_data)

                if 199 < status < 305:
                    return response_data

                # Are we rate limited?
                if status == 429:
                    try:
                        retry_after = headers[RETRY_AFTER]
                    except KeyError:
                        retry_after = RATE_LIMIT_GLOBAL_DEFAULT_DURATION
                    else:
                        try:
                            retry_after = float(retry_after)
                        except ValueError:
                            retry_after = RATE_LIMIT_GLOBAL_DEFAULT_DURATION

                    self._global_rate_limit_expires_at = LOOP_TIME(
                    ) + retry_after

                    if self._raise_on_top_gg_global_rate_limit:
                        raise TopGGGloballyRateLimited(None)

                    await sleep(retry_after, KOKORO)
                    continue

                # Python casts sets to frozensets
                if (status in {400, 401, 402, 404}):
                    raise TopGGHttpException(response, response_data)

                if try_again and (status >= 500):
                    await sleep(10.0 / try_again, KOKORO)
                    try_again -= 1
                    continue

                raise TopGGHttpException(response, response_data)