Ejemplo n.º 1
0
    async def check(self, aio_client: aiohttp.ClientSession,
                    usernames: AbstractSet[str]) -> ni_abc.Status:
        base_url = "https://bugs.python.org/user?@template=clacheck&github_names="
        url = base_url + ','.join(usernames)
        self.server.log("Checking CLA status: " + url)
        async with aio_client.get(url) as response:
            if response.status >= 300:
                msg = f'unexpected response for {response.url!r}: {response.status}'
                raise client.HTTPException(msg)
            # Explicitly decode JSON as b.p.o doesn't set the content-type as
            # `application/json`.
            results = json.loads(await response.text())
        self.server.log("Raw CLA status: " + str(results))
        status_results = [results[k] for k in results.keys() if k in usernames]
        self.server.log("Filtered CLA status: " + str(status_results))
        if len(status_results) != len(usernames):
            raise ValueError("# of usernames don't match # of results "
                             "({} != {})".format(len(usernames), len(status_results)))
        elif any(x not in (True, False, None) for x in status_results):
            raise TypeError("unexpected value in " + str(status_results))

        if all(status_results):
            return ni_abc.Status.signed
        elif any(value is None for value in status_results):
            return ni_abc.Status.username_not_found
        else:
            return ni_abc.Status.not_signed
Ejemplo n.º 2
0
async def query_imdb(*, imdb_id: Optional[int],
                     year: int,
                     session: ClientSession) -> Dict[str, Any]:
    params = dict(i=f'tt{imdb_id:0>{IMDB_ID_LENGTH}}',
                  y=year,
                  plot='full',
                  tomatoes='true',
                  r='json')
    while True:
        attempt_num = 0
        async with session.get(IMDB_API_URL, params=params) as response:
            attempt_num += 1
            if response.status == A_TIMEOUT_OCCURRED:
                logger.debug(f'Attempt #{attempt_num} failed: '
                             f'server "{IMDB_API_URL}" answered with '
                             f'status code {A_TIMEOUT_OCCURRED}. '
                             f'Waiting {RETRY_INTERVAL_IN_SECONDS} second(s) '
                             'before next attempt.')
                await sleep(RETRY_INTERVAL_IN_SECONDS)
                continue
            try:
                response_json = await response.json()
            except JSONDecodeError:
                logger.exception('')
                return dict()
            return response_json
Ejemplo n.º 3
0
def github_action(action, plugin, config, sort_by='updated'):
    url = API_URL.format(
        api=API_URL,
        user=config['user'],
        repo=config['repository'],
        action=action,
    )
    query = {
        'sort': sort_by,
        'direction': 'desc',
        'sha': config.get('branch', 'master')
    }
    headers = {'Accept': 'application/vnd.github.v3+json'}
    etag = plugin.temp.get(action)
    if etag is not None:
        headers['If-None-Match'] = etag

    session = ClientSession()
    try:
        resp = yield from asyncio.wait_for(
            session.get(url, params=query, headers=headers),
            timeout=5
        )
        try:
            plugin.temp[action] = resp.headers.get('etag')
            if resp.status != 200 or etag is None:  # etag must be cached first
                raise NothingChangeException(etag)
            data = yield from resp.json()
        finally:
            resp.close()
    finally:
        session.close()
    return data[0]
Ejemplo n.º 4
0
 def go():
     _, srv, url = yield from self.create_server(None, '/', None)
     client = ClientSession(loop=self.loop)
     resp = yield from client.get(url)
     self.assertEqual(404, resp.status)
     yield from resp.release()
     client.close()
Ejemplo n.º 5
0
async def _fetch_url(
        url: str,
        session: aiohttp.ClientSession,
        timeout: float = 10.0) -> str:
    with async_timeout.timeout(timeout):
        async with session.get(url) as response:
            response.raise_for_status()
            return await response.text()
Ejemplo n.º 6
0
async def fetch_with_sleep(session: aiohttp.ClientSession,
                           url: str,
                           sleep_time: int) -> Response:
    async with session.get(url) as response:
        print(f"request {url} with {sleep_time}s")
        await sleep(sleep_time)
        print(f"request {url} sleep done")
        return response
Ejemplo n.º 7
0
 def go():
     _, srv, url = yield from self.create_server('GET', '/', handler)
     client = ClientSession(loop=self.loop)
     resp = yield from client.get(url)
     self.assertEqual(200, resp.status)
     data = yield from resp.read()
     self.assertEqual(b'xyz', data)
     yield from resp.release()
Ejemplo n.º 8
0
 def go():
     _, srv, url = yield from self.create_server('GET', '/', handler)
     client = ClientSession(loop=self.loop)
     resp = yield from client.get(url)
     self.assertEqual(200, resp.status)
     data = yield from resp.read()
     self.assertEqual(b'mydata', data)
     self.assertEqual(resp.headers.get('CONTENT-ENCODING'), 'deflate')
     yield from resp.release()
     client.close()
Ejemplo n.º 9
0
async def afetch(session: ClientSession, url: str):
    """
    Asynchronous fetch.  Do a GET request,  return text,  properly  shutdown

    :param session: ClientSession object for aiohttp connection
    :param url: The URL we want
    :return:
    """
    async with session.get(url) as response:
        return await response.text()
Ejemplo n.º 10
0
async def process_partition(
    loop: asyncio.BaseEventLoop,
    results_queue: asyncio.Queue,
    server_address: URL,
    http: aiohttp.ClientSession,
    partition: PointsPartition,
    mission_template: Template,
    mission_loader: str,
    mission_name: str,
    width: int,
    scale: int,
) -> Awaitable[None]:
    LOG.debug(
        f"query range [{partition.start}:{partition.end}] on server "
        f"{server_address}"
    )

    file_name = f"{mission_name}_{partition.start}_{partition.end}.mis"
    missions_url = server_address / "missions"
    mission_dir_url = missions_url / "heightmap"
    mission_url = mission_dir_url / file_name

    points = (
        index_to_point(i, width, scale)
        for i in range(partition.start, partition.end + 1)
    )
    mission = mission_template.render(
        loader=mission_loader,
        points=points,
    )

    data = FormData()
    data.add_field(
        'mission',
        mission.encode(),
        filename=file_name,
        content_type='plain/text',
    )

    await http.post(mission_dir_url, data=data)
    await http.post(mission_url / "load")
    await http.post(missions_url / "current" / "begin")

    async with http.get(server_address / "radar" / "stationary-objects") as response:
        data = await response.json()
        data = [
            pack(HEIGHT_PACK_FORMAT, int(point['pos']['z']))
            for point in data
        ]
        data = b''.join(data)

    await http.post(missions_url / "current" / "unload")
    await http.delete(mission_url)

    await results_queue.put((partition, data))
Ejemplo n.º 11
0
def get_html(url):
    session = ClientSession()
    try:
        resp = yield from session.get(url)
        try:
            raw_data = yield from resp.read()
            data = raw_data.decode('utf-8', errors='xmlcharrefreplace')
            return fromstring_to_html(data)
        finally:
            resp.close()
    finally:
        session.close()
Ejemplo n.º 12
0
async def bfetch(session: ClientSession, url: str):
    """
    Asynchronous binary fetch.  Do a GET request,  return binary data,  properly  shutdown

    :param session: ClientSession object for aiohttp connection
    :param url: The URL we want
    :return:
    """
    async with session.get(url) as response:
        if response.status >= 400:
            LOGGER.error("Got status %s for GET %s", response.status, url)

        response.raise_for_status()
        return await response.read()
Ejemplo n.º 13
0
async def get_imdb_id(article_title: str, *,
                      session: ClientSession
                      ) -> Optional[int]:
    params = dict(action='expandtemplates',
                  text='{{IMDb title}}',
                  prop='wikitext',
                  title=article_title,
                  format='json')
    async with session.get(WIKIPEDIA_API_URL,
                           params=params) as response:
        response_json = await response.json()
        templates = response_json['expandtemplates']
        imdb_link = templates.get('wikitext', '')
        search_res = IMDB_ID_RE.search(imdb_link)
        if search_res is None:
            return None
        return int(search_res.group(0))
Ejemplo n.º 14
0
class Downloader(Actor):
    async def startup(self):
        self.session = ClientSession(loop=self.loop)

    @concurrent
    async def download_content(self, url):
        async with self.session.get(url) as response:
            content = await response.read()
            print('{}: {:.80}...'.format(url, content.decode()))
        return len(content)

    async def shutdown(self):
        self.session.close()

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc, tb):
        await self.close()
Ejemplo n.º 15
0
    async def create_line_to_position_map(
        self, client_session: aiohttp.ClientSession
    ) -> MutableMapping[str, Dict[int, int]]:
        result = defaultdict(dict)  # type: MutableMapping[str, Dict[int, int]]
        current_file = ''
        position = -1
        right_line_number = -1

        headers = {
            'Accept': 'application/vnd.github.diff',
        }
        url = ('{api_url}/repos/'
               '{organization}/{repo}/pulls/{pr}'.format(
                   api_url=GITHUB_API_URL,
                   organization=self.organization,
                   repo=self.repo,
                   pr=self.pr))
        async with client_session.get(url, headers=headers) as response:
            async for line in response.content:
                line = line.decode()
                file_match = FILE_START_REGEX.match(line)
                if file_match:
                    current_file = file_match.groups()[0].strip()
                    right_line_number = -1
                    position = -1
                    continue
                elif line.startswith(NEW_FILE_SECTION_START):
                    current_file = ''
                if not current_file:
                    continue

                position += 1
                hunk_match = HUNK_REGEX.match(line)
                if hunk_match:
                    right_line_number = int(hunk_match.groups()[0]) - 1
                elif not line.startswith('-'):
                    right_line_number += 1
                    result[current_file][right_line_number] = position

        return result
Ejemplo n.º 16
0
    def create_line_to_position_map(
        self, client_session: aiohttp.ClientSession
    ) -> MutableMapping[str, Dict[int, int]]:
        result = defaultdict(dict)  # type: MutableMapping[str, Dict[int, int]]
        current_file = ''
        position = -1
        right_line_number = -1

        headers = {
            'Accept': 'application/vnd.github.diff',
        }
        url = ('https://api.github.com/repos/'
               '{organization}/{repo}/pulls/{pr}'.format(
                   organization=self.organization,
                   repo=self.repo,
                   pr=self.pr))
        response = yield from client_session.get(url, headers=headers)
        content = yield from response.text()
        for line in content.split('\n'):
            file_match = FILE_START_REGEX.match(line)
            if file_match:
                current_file = file_match.groups()[0]
                right_line_number = -1
                position = -1
                continue
            elif line.startswith(NEW_FILE_SECTION_START):
                current_file = ''
            if not current_file:
                continue

            position += 1
            hunk_match = HUNK_REGEX.match(line)
            if hunk_match:
                right_line_number = int(hunk_match.groups()[0]) - 1
            elif not line.startswith('-'):
                right_line_number += 1
                result[current_file][right_line_number] = position

        return result
Ejemplo n.º 17
0
class Github:
    _BASE_URL = 'https://api.github.com'

    def __init__(self, username, password, timeout=10):
        self._loop = asyncio.get_event_loop()
        self._session = ClientSession(loop=self._loop, auth=BasicAuth(username, password))
        self._timeout = timeout

    def close(self):
        self._session.close()

    async def fetch(self, url, params):
        with Timeout(self._timeout):
            async with self._session.get('{}{}'.format(self._BASE_URL, url), params=params) as response:
                return await response.json()

    async def search_repositories(self, language, pushed, sort, order):
        q = 'language:{}'.format(language)
        if pushed:
            q = '{} pushed:>={}'.format(q, pushed)

        params = {'q': q, 'sort': sort, 'order': order}
        return await self.fetch('/search/repositories', params=params)
Ejemplo n.º 18
0
async def fetch_page(session: aiohttp.ClientSession, url: str):
    with aiohttp.Timeout(10):
        async with session.get(url) as resp:
            assert resp.status == 200
            return await resp.read()
Ejemplo n.º 19
0
async def get_projects(session: aiohttp.ClientSession, params: Dict = None) -> Dict:
    async with session.get(GITLAB_API_URI + "/projects", params=params) as resp:
        return await resp.json()
Ejemplo n.º 20
0
class OwnerOnly(object):
    def __init__(self, bot):
        self.bot = bot
        self.session = ClientSession(loop=bot.loop)

    def __unload(self):
        self.session.close()

    @commands.command(pass_context=True)
    @permissionChecker(check='is_owner')
    async def editrolecolour(self, ctx, colour, *, name):
        '''
        Lets you change the profile.
        '''

        r = [
            i for i in ctx.message.server.roles
            if name.lower() in i.name.lower()
        ]
        if len(r) > 1:
            await self.bot.say('Too many roles etc')
            return
        elif len(r) < 1:
            await self.bot.say('nop no roles like that')
            return

        if len(colour) == 6:
            colour = Colour(int(colour, 16))
        else:
            await self.bot.say('Idk what colours are, man')
            return

        await self.bot.edit_role(ctx.message.server, r[0], colour=colour)
        await self.bot.say('Done.')

    @commands.command(pass_context=True)
    @permissionChecker(check='is_owner')
    async def givemerole(self, ctx, *, name):
        '''
        Lets you change the profile.
        '''

        r = [
            i for i in ctx.message.server.roles
            if name.lower() in i.name.lower()
        ]
        if len(r) > 1:
            await self.bot.say('Too many roles etc')
            return
        elif len(r) < 1:
            await self.bot.say('nop no roles like that')
            return

        await self.bot.add_roles(ctx.message.author, r[0])
        await self.bot.say('Done.')

    @commands.command(pass_context=True)
    @permissionChecker(check='is_owner')
    async def takemerole(self, ctx, *, name):
        '''
        Lets you change the profile.
        '''

        r = [
            i for i in ctx.message.server.roles
            if name.lower() in i.name.lower()
        ]
        if len(r) > 1:
            await self.bot.say('Too many roles etc')
            return
        elif len(r) < 1:
            await self.bot.say('nop no roles like that')
            return

        await self.bot.remove_roles(ctx.message.author, r[0])
        await self.bot.say('Done.')

    @commands.group()
    @permissionChecker(check='is_owner')
    async def profile(self):
        '''
        Lets you change the profile.
        '''

        pass

    @profile.command()
    @permissionChecker(check='is_owner')
    async def name(self, *, name: str = None):
        '''
        Changes the name of the profile.
        '''

        if name == None:
            await self.bot.say('`!profile name [NAME]`')
            return

        await self.bot.edit_profile(username=name)
        w = await self.bot.say('👌')
        await sleep(2)
        await self.bot.delete_message(w)

    @profile.command()
    @permissionChecker(check='is_owner')
    async def avatar(self, *, avatar: str = None):
        '''
        Changes the profile picture of the bot.
        '''

        if avatar == None:
            await self.bot.say('`!profile avatar [URL]`')
            return

        async with self.session.get(avatar) as r:
            content = r.read()

        await self.bot.edit_profile(avatar=content)
        w = await self.bot.say('👌')
        await sleep(2)
        await self.bot.delete_message(w)

    @commands.command(pass_context=True, hidden=True)
    @permissionChecker(check='is_owner')
    async def ev(self, ctx, *, content: str):
        '''
        Evaluates a given Python expression
        '''

        # Eval and print the answer
        try:
            output = eval(content)
        except Exception:
            type_, value_, traceback_ = exc_info()
            ex = format_exception(type_, value_, traceback_)
            output = ''.join(ex)
        await self.bot.say('```python\n{}```'.format(output))

    @commands.command(pass_context=True, hidden=True)
    @permissionChecker(check='is_owner')
    async def cls(self, ctx):
        '''
        Clears the console
        '''

        print('\n' * 50)
        await self.bot.say('Done.')

    @commands.command(pass_context=True, hidden=True)
    @permissionChecker(check='is_owner')
    async def kill(self, ctx):
        '''
        Kills the bot. Makes it deaded
        '''

        # If it is, tell the user the bot it dying
        await self.bot.say('*Finally*.')
        await self.bot.change_presence(status=Status.invisible, game=None)
        exit()

    @commands.command(pass_context=True, hidden=True, aliases=['rs'])
    @permissionChecker(check='is_owner')
    async def restart(self, ctx):
        '''
        Restarts the bot. Literally everything
        '''

        # If it is, tell the user the bot it dying
        await self.bot.say('Now restarting.')
        await self.bot.change_presence(status=Status.dnd, game=None)
        execl(executable, *([executable] + argv))

    @commands.command(pass_context=True, hidden=True)
    @permissionChecker(check='is_owner')
    async def rld(self, ctx, *, extention: str):
        '''
        Reloads a cog from the bot
        '''

        extention = f'Cogs.{extention}'

        # Unload the extention
        await self.bot.say("Reloading extension **{}**...".format(extention))
        try:
            self.bot.unload_extension(extention)
        except:
            pass

        # Load the new one
        try:
            self.bot.load_extension(extention)
        except Exception:
            type_, value_, traceback_ = exc_info()
            ex = format_exception(type_, value_, traceback_)
            output = ''.join(ex)
            await self.bot.say('```python\n{}```'.format(output))
            return

        # Boop the user
        await self.bot.say("Done!")
Ejemplo n.º 21
0
class AioHttpClient(HttpClient):
    def __init__(self,
                 *,
                 connector=None,
                 loop=None,
                 cookies=None,
                 headers=None,
                 skip_auto_headers=None,
                 auth=None,
                 json_serialize=json.dumps,
                 request_class=ClientRequest,
                 response_class=ClientResponse,
                 ws_response_class=ClientWebSocketResponse,
                 version=http.HttpVersion11,
                 cookie_jar=None,
                 connector_owner=True,
                 raise_for_status=False,
                 read_timeout=sentinel,
                 conn_timeout=None,
                 auto_decompress=True,
                 trust_env=False,
                 **kwargs):
        """
        The class packaging a class ClientSession to perform HTTP request and manager that these HTTP connection.

        For details of the params: http://aiohttp.readthedocs.io/en/stable/client_advanced.html#client-session
        """
        super(AioHttpClient, self).__init__(**kwargs)
        self.client = ClientSession(connector=connector,
                                    loop=loop,
                                    cookies=cookies,
                                    headers=headers,
                                    skip_auto_headers=skip_auto_headers,
                                    auth=auth,
                                    json_serialize=json_serialize,
                                    request_class=request_class,
                                    response_class=response_class,
                                    ws_response_class=ws_response_class,
                                    version=version,
                                    cookie_jar=cookie_jar,
                                    connector_owner=connector_owner,
                                    raise_for_status=raise_for_status,
                                    read_timeout=read_timeout,
                                    conn_timeout=conn_timeout,
                                    auto_decompress=auto_decompress,
                                    trust_env=trust_env)

    def request(self, method, url, *args, **kwargs):
        return self.client.request(method=method, url=url, **kwargs)

    def get(self, url, *args, **kwargs):
        return self.client.get(url=url, **kwargs)

    def post(self, url, *args, data=None, **kwargs):
        return self.client.post(url=url, data=data, **kwargs)

    def put(self, url, *args, data=None, **kwargs):
        return self.client.put(url=url, data=data, **kwargs)

    def delete(self, url, *args, **kwargs):
        return self.client.delete(url=url, **kwargs)

    def options(self, url, *args, **kwargs):
        return self.client.options(url=url, **kwargs)

    def head(self, url, *args, **kwargs):
        return self.client.head(url=url, **kwargs)

    def patch(self, url, *args, data=None, **kwargs):
        return self.client.patch(url=url, data=data, **kwargs)

    async def close(self):
        await self.client.close()

    async def get_response(self, response):
        text = await response.text()
        return Response(url=response.url,
                        status=response.status,
                        charset=response.charset,
                        content_type=response.content_type,
                        content_length=response.content_length,
                        reason=response.reason,
                        headers=response.headers,
                        text=text,
                        selector=etree.HTML(text))

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.close()
Ejemplo n.º 22
0
async def fetch(client: ClientSession, url):
    async with client.get(url=url) as resp:
        assert resp.status == 200
        return await resp.text()
Ejemplo n.º 23
0
async def fetch(url: str, session: ClientSession) -> str:
    async with session.get(url) as response:
        return await response.text()
Ejemplo n.º 24
0
class DaapSession(object):
    """This class makes it easy to perform DAAP requests.

    It automatically adds the required headers and also does DMAP parsing.
    """
    def __init__(self, loop, timeout=DEFAULT_TIMEOUT):
        """Initialize a new DaapSession."""
        self._session = ClientSession(loop=loop)
        self._timeout = timeout

    def close(self):
        """Close the underlying client session."""
        return self._session.close()

    @asyncio.coroutine
    def get_data(self, url, should_parse=True):
        """Perform a GET request. Optionally parse reponse as DMAP data."""
        _LOGGER.debug('GET URL: %s', url)
        resp = yield from self._session.get(url,
                                            headers=_DMAP_HEADERS,
                                            timeout=self._timeout)
        try:
            resp_data = yield from resp.read()
            extracted = self._extract_data(resp_data, should_parse)
            return extracted, resp.status
        except Exception as ex:
            resp.close()
            raise ex
        finally:
            yield from resp.release()

    @asyncio.coroutine
    def post_data(self, url, data=None, parse=True):
        """Perform a POST request. Optionally parse reponse as DMAP data."""
        _LOGGER.debug('POST URL: %s', url)

        headers = copy(_DMAP_HEADERS)
        headers['Content-Type'] = 'application/x-www-form-urlencoded'

        resp = yield from self._session.post(url,
                                             headers=headers,
                                             data=data,
                                             timeout=self._timeout)
        try:
            resp_data = yield from resp.read()
            extracted = self._extract_data(resp_data, parse)
            return extracted, resp.status
        except Exception as ex:
            resp.close()
            raise ex
        finally:
            yield from resp.release()

    @staticmethod
    def _extract_data(data, should_parse):
        if _LOGGER.isEnabledFor(logging.DEBUG):
            output = data[0:128]
            _LOGGER.debug('Data[%d]: %s%s', len(data),
                          binascii.hexlify(output),
                          '...' if len(output) != len(data) else '')
        if should_parse:
            return dmap.parse(data, lookup_tag)
        else:
            return data
async def get_flag(session: ClientSession, cc: str) -> bytes:  # <4>
    cc = cc.lower()
    url = f'{BASE_URL}/{cc}/{cc}.gif'
    async with session.get(url) as resp:  # <5>
        print(resp)
        return await resp.read()  # <6>
Ejemplo n.º 26
0
class SmartThingsTV:
    def __init__(
        self,
        api_key: str,
        device_id: str,
        use_channel_info: bool = True,
        session: Optional[ClientSession] = None,
    ):
        """Initialize SmartThingsTV."""
        self._api_key = api_key
        self._device_id = device_id
        self._use_channel_info = use_channel_info
        if session:
            self._session = session
            self._managed_session = False
        else:
            self._session = ClientSession()
            self._managed_session = True

        self._device_name = None
        self._state = STStatus.STATE_UNKNOWN
        self._prev_state = STStatus.STATE_UNKNOWN
        self._muted = False
        self._volume = 10
        self._source_list = None
        self._source_list_map = None
        self._source = ""
        self._channel = ""
        self._channel_name = ""
        self._sound_mode = None
        self._sound_mode_list = None
        self._picture_mode = None
        self._picture_mode_list = None

        self._is_forced_val = False
        self._forced_count = 0

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        pass

    @property
    def api_key(self) -> str:
        """Return current api_key."""
        return self._api_key

    @property
    def device_id(self) -> str:
        """Return current device_id."""
        return self._device_id

    @property
    def device_name(self) -> str:
        """Return current device_name."""
        return self._device_name

    @property
    def state(self):
        """Return current state."""
        return self._state

    @property
    def prev_state(self):
        """Return current state."""
        return self._prev_state

    @property
    def muted(self) -> bool:
        """Return current muted state."""
        return self._muted

    @property
    def volume(self) -> int:
        """Return current volume."""
        return self._volume

    @property
    def source(self) -> str:
        """Return current source."""
        return self._source

    @property
    def channel(self) -> str:
        """Return current channel."""
        return self._channel

    @property
    def channel_name(self) -> str:
        """Return current channel name."""
        return self._channel_name

    @property
    def source_list(self):
        """Return available source list."""
        return self._source_list

    @property
    def sound_mode(self):
        """Return current sound mode."""
        if self._state != STStatus.STATE_ON:
            return None
        return self._sound_mode

    @property
    def sound_mode_list(self):
        """Return available sound modes."""
        if self._state != STStatus.STATE_ON:
            return None
        return self._sound_mode_list

    @property
    def picture_mode(self):
        """Return current picture mode."""
        if self._state != STStatus.STATE_ON:
            return None
        return self._picture_mode

    @property
    def picture_mode_list(self):
        """Return available picture modes."""
        if self._state != STStatus.STATE_ON:
            return None
        return self._picture_mode_list

    def get_source_name(self, source_id: str) -> str:
        """Get source name based on source id."""
        if not self._source_list_map:
            return ""
        if source_id.upper() == DIGITAL_TV.upper():
            source_id = "dtv"
        for map_value in self._source_list_map:
            map_id = map_value.get("id")
            if map_id and map_id == source_id:
                return map_value.get("name", "")
        return ""

    def set_application(self, app_id):
        """Set running application info."""
        if self._use_channel_info:
            self._channel = ""
            self._channel_name = app_id
            self._is_forced_val = True
            self._forced_count = 0

    def _set_source(self, source):
        """Set current source info."""
        if source != self._source:
            self._source = source
            self._channel = ""
            self._channel_name = ""
            self._is_forced_val = True
            self._forced_count = 0

    @staticmethod
    def _load_json_list(dev_data, list_name):
        """Try load a list from string to json format."""
        load_list = []
        json_list = dev_data.get(list_name, {}).get("value")
        if json_list:
            try:
                load_list = json.loads(json_list)
            except (TypeError, ValueError):
                pass
        return load_list

    @staticmethod
    async def get_devices_list(api_key,
                               session: ClientSession,
                               device_label=""):
        """Get list of available SmartThings devices"""

        result = {}

        async with session.get(
                API_DEVICES,
                headers=_headers(api_key),
                raise_for_status=True,
        ) as resp:
            device_list = await resp.json()

        if device_list:
            _LOGGER.debug("SmartThings available devices: %s",
                          str(device_list))

            for k in device_list.get("items", []):
                device_id = k.get("deviceId", "")
                device_type = k.get("type", "")
                device_type_id = k.get("deviceTypeId", "")
                if device_id and (device_type_id == DEVICE_TYPEID_OCF
                                  or device_type == DEVICE_TYPE_OCF):
                    label = k.get("label", "")
                    if device_label == "" or (label == device_label
                                              and label != ""):
                        result.setdefault(device_id,
                                          {})["name"] = k.get("name", "")
                        result.setdefault(device_id, {})["label"] = label

        _LOGGER.info("SmartThings discovered TV devices: %s", str(result))

        return result

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    async def _device_refresh(self, **kwargs):
        """Refresh device status on SmartThings"""

        device_id = self._device_id
        if not device_id:
            return

        api_device = f"{API_DEVICES}/{device_id}"
        api_command = f"{api_device}/commands"

        if self._use_channel_info:
            async with self._session.post(
                    api_command,
                    headers=_headers(self._api_key),
                    data=_command(COMMAND_REFRESH),
                    raise_for_status=False,
            ) as resp:
                if resp.status == 409:
                    self._state = STStatus.STATE_OFF
                    return
                resp.raise_for_status()
                await resp.json()

        return

    async def _async_send_command(self, data_cmd):
        """Send a command via SmartThings"""
        device_id = self._device_id
        if not device_id:
            return
        if not data_cmd:
            return

        api_device = f"{API_DEVICES}/{device_id}"
        api_command = f"{api_device}/commands"

        async with self._session.post(
                api_command,
                headers=_headers(self._api_key),
                data=data_cmd,
                raise_for_status=True,
        ) as resp:
            await resp.json()

        await self._device_refresh()

    async def async_device_health(self):
        """Check device availability"""

        device_id = self._device_id
        if not device_id:
            return False

        api_device = f"{API_DEVICES}/{device_id}"
        api_device_health = f"{api_device}/health"

        # this get the real status of the device
        async with self._session.get(
            api_device_health,
            headers=_headers(self._api_key),
            raise_for_status=True,
        ) as resp:
            health = await resp.json()

        _LOGGER.debug(health)

        if health["state"] == "ONLINE":
            return True
        return False

    async def async_device_update(self, use_channel_info: bool = None):
        """Query device status on SmartThing"""

        device_id = self._device_id
        if not device_id:
            return

        if use_channel_info is not None:
            self._use_channel_info = use_channel_info

        api_device = f"{API_DEVICES}/{device_id}"
        api_device_status = f"{api_device}/states"
        # not used, just for reference
        api_device_main_status = f"{api_device}/components/main/status"

        self._prev_state = self._state

        try:
            is_online = await self.async_device_health()
        except (
                AsyncTimeoutError,
                ClientConnectionError,
                ClientResponseError,
        ):
            self._state = STStatus.STATE_UNKNOWN
            return

        if is_online:
            self._state = STStatus.STATE_ON
        else:
            self._state = STStatus.STATE_OFF
            return

        await self._device_refresh()
        if self._state == STStatus.STATE_OFF:
            return

        async with self._session.get(
                api_device_status,
                headers=_headers(self._api_key),
                raise_for_status=True,
        ) as resp:
            data = await resp.json()

        _LOGGER.debug(data)

        dev_data = data.get("main", {})
        # device_state = data['main']['switch']['value']

        # Volume
        device_volume = dev_data.get("volume", {}).get("value", 0)
        if device_volume and device_volume.isdigit():
            self._volume = int(device_volume) / 100
        else:
            self._volume = 0

        # Muted state
        device_muted = dev_data.get("mute", {}).get("value", "")
        self._muted = (device_muted == "mute")

        # Sound Mode
        self._sound_mode = dev_data.get("soundMode", {}).get("value")
        self._sound_mode_list = self._load_json_list(dev_data,
                                                     "supportedSoundModes")

        # Picture Mode
        self._picture_mode = dev_data.get("pictureMode", {}).get("value")
        self._picture_mode_list = self._load_json_list(
            dev_data, "supportedPictureModes")

        # Sources and channel
        self._source_list = self._load_json_list(dev_data,
                                                 "supportedInputSources")
        self._source_list_map = self._load_json_list(
            dev_data, "supportedInputSourcesMap")

        if self._is_forced_val and self._forced_count <= 0:
            self._forced_count += 1
            return
        self._is_forced_val = False
        self._forced_count = 0

        device_source = dev_data.get("inputSource", {}).get("value", "")
        device_tv_chan = dev_data.get("tvChannel", {}).get("value", "")
        device_tv_chan_name = dev_data.get("tvChannelName",
                                           {}).get("value", "")

        if device_source:
            if device_source.upper() == DIGITAL_TV.upper():
                device_source = DIGITAL_TV
        self._source = device_source
        # if the status is not refreshed this info may become not reliable
        if self._use_channel_info:
            self._channel = device_tv_chan
            self._channel_name = device_tv_chan_name
        else:
            self._channel = ""
            self._channel_name = ""

    async def async_turn_off(self):
        """Turn off TV via SmartThings"""
        await self._async_send_command(COMMAND_POWER_OFF)

    async def async_turn_on(self):
        """Turn on TV via SmartThings"""
        await self._async_send_command(COMMAND_POWER_ON)

    async def async_send_command(self, cmd_type, command=""):
        """Send a command to the device"""
        data_cmd = None

        if cmd_type == "setvolume":  # sets volume
            data_cmd = _command(COMMAND_SET_VOLUME, [int(command)])
        elif cmd_type == "stepvolume":  # steps volume up or down
            if command == "up":
                data_cmd = _command(COMMAND_VOLUME_UP)
            elif command == "down":
                data_cmd = _command(COMMAND_VOLUME_DOWN)
        elif cmd_type == "audiomute":  # mutes audio
            if command == "on":
                data_cmd = _command(COMMAND_MUTE)
            elif command == "off":
                data_cmd = _command(COMMAND_UNMUTE)
        elif cmd_type == "selectchannel":  # changes channel
            data_cmd = _command(COMMAND_SET_CHANNEL, [command])
        elif cmd_type == "stepchannel":  # steps channel up or down
            if command == "up":
                data_cmd = _command(COMMAND_CHANNEL_UP)
            elif command == "down":
                data_cmd = _command(COMMAND_CHANNEL_DOWN)
        else:
            return

        await self._async_send_command(data_cmd)

    async def async_select_source(self, source):
        """Select source"""
        # if source not in self._source_list:
        #     return
        data_cmd = _command(COMMAND_SET_SOURCE, [source])
        # set property to reflect new changes
        self._set_source(source)
        await self._async_send_command(data_cmd)

    async def async_set_sound_mode(self, mode):
        """Select sound mode"""
        if self._state != STStatus.STATE_ON:
            return
        if mode not in self._sound_mode_list:
            raise InvalidSmartThingsSoundMode()
        data_cmd = _command(COMMAND_SOUND_MODE, [mode])
        await self._async_send_command(data_cmd)
        self._sound_mode = mode

    async def async_set_picture_mode(self, mode):
        """Select picture mode"""
        if self._state != STStatus.STATE_ON:
            return
        if mode not in self._picture_mode_list:
            raise InvalidSmartThingsPictureMode()
        data_cmd = _command(COMMAND_PICTURE_MODE, [mode])
        await self._async_send_command(data_cmd)
        self._picture_mode = mode
Ejemplo n.º 27
0
class Projects(Cog):
    """Cog that reacts appropriately to project urls."""

    _index_channel: int = ConfigValue("default", "projects",
                                      "index_channel_id")

    _default_kwargs = {
        "pattern": r"^(?:webhook!)?https?://($hosts)(?:.{0,200})$$",
        "message_channel_id": _index_channel,
        "message_author_bot": False,
        "formatter": lambda client: {
            "hosts": "|".join(client.config["default"]["projects"]["hosts"])
        },
    }

    _negative_lookahed = {
        **_default_kwargs,
        "filter_": (lambda match: isinstance(match, Match)),
    }

    _category_id: int = ConfigValue("default", "projects", "category_id")
    _member_role_id: int = ConfigValue("default", "guild_member_role")

    session: ClientSession

    def __post_init__(self):
        self.session = ClientSession()

    # Internal

    async def _activate_webhook_channel(
            self,
            channel: TextChannel,
            timeout: int = DEALLOCATION_TIMEOUT) -> None:
        def is_webhook_message(message: Message) -> bool:
            return message.channel == channel and message.webhook_id is not None

        wait_for = partial(self.client.wait_for, "message")

        try:
            await wait_for(check=is_webhook_message, timeout=timeout)
        except TimeoutError:
            await channel.delete()
            return

        self.logger.info("Activating webhook channel %s", repr(channel))

        def is_not_webhook(message: Message) -> bool:
            return message.webhook_id is None

        await channel.purge(limit=None, check=is_not_webhook, bulk=True)
        await channel.edit(sync_permissions=True)

    # Zombie rescheduler

    @Cog.task
    @Cog.wait_until_ready
    async def _reschedule_orphan_channels(self) -> None:
        category = self.client.get_channel(self._category_id)
        assert category is not None

        schedule_task = self.client.schedule_task
        for channel in category.channels:
            if channel.id == self._index_channel:
                continue

            timeout = None
            now = datetime.now()

            async for message in channel.history(limit=None,
                                                 oldest_first=True):
                if message.webhook_id is not None:
                    timeout = None
                    break

                if timeout is None:
                    timeout = DEALLOCATION_TIMEOUT - (
                        now - message.created_at).seconds

                    if timeout <= 0:
                        timeout = DEALLOCATION_TIMEOUT

            if timeout is not None:
                self.logger.warn(
                    "Rescheduling activation task for channel timeout=%s channel=%s",
                    timeout,
                    repr(channel),
                )
                schedule_task(self._activate_webhook_channel(channel, timeout))

    # Listeners

    @Cog.formatted_regex(**_negative_lookahed)
    async def filter_project_message(self, message: Message) -> None:
        """Handle a :class:`discord.Message` sent in the projects channel."""
        await message.channel.send(
            f"{message.author.mention}, That doesn't look like a valid vcs link.",
            delete_after=3.0,
        )
        await sleep(0.5)
        await message.delete()

    @Cog.formatted_regex(**_default_kwargs)
    @Cog.wait_until_ready
    async def webhook_project_repository(self, message: Message) -> None:
        """Generate a channel and webhook for a repository."""
        assert message.content.startswith("webhook!")

        url = message.content[len("webhook!"):]

        async with self.session.get(url) as resp:
            if not resp.status in range(200, 300):
                await message.channel.send(
                    f"{message.author.mention} - I couldn't verify that link, I got a HTTP/{resp.status} back.",
                    delete_after=3.0)
                await sleep(2)
                await message.delete()
                return

        kwargs = {"topic": url, "reason": f"Invoked by {message.author!s}"}

        match = await self.client.loop.run_in_executor(
            None, partial(search, r"([^/][\w-]+)(?:/)([^/].+)$", url))

        if match is not None:
            name = "-".join(match.groups())
        else:
            self.logger.error("Failed to match against %s", repr(url))
            name = url

        if len(name) > 80:
            name = name[:80]

        assert len(name) <= 80

        kwargs["name"] = name

        category = self.client.get_channel(self._category_id)
        assert category is not None

        member_role = message.guild.get_role(self._member_role_id)
        assert member_role is not None

        kwargs["overwrites"] = {
            **category.overwrites,
            member_role:
            PermissionOverwrite(read_messages=False,
                                read_message_history=False),
            message.author:
            PermissionOverwrite(read_messages=True,
                                read_message_history=True,
                                send_messages=True),
        }

        channel = await category.create_text_channel(**kwargs)
        webhook = await channel.create_webhook(name=name)

        await channel.send(
            ALLOCATED_MESSAGE.format(message=message, webhook=webhook))
        self.client.schedule_task(self._activate_webhook_channel(channel))
Ejemplo n.º 28
0
class SeasonalBot(commands.Bot):
    """
    Base bot instance.

    While in debug mode, the asset upload methods (avatar, banner, ...) will not
    perform the upload, and will instead only log the passed download urls and pretend
    that the upload was successful. See the `mock_in_debug` decorator for further details.
    """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.http_session = ClientSession(connector=TCPConnector(
            resolver=AsyncResolver(), family=socket.AF_INET))
        self._guild_available = asyncio.Event()

        self.loop.create_task(self.send_log("SeasonalBot", "Connected!"))

    @property
    def member(self) -> Optional[discord.Member]:
        """Retrieves the guild member object for the bot."""
        guild = self.get_guild(Client.guild)
        if not guild:
            return None
        return guild.me

    def add_cog(self, cog: commands.Cog) -> None:
        """
        Delegate to super to register `cog`.

        This only serves to make the info log, so that extensions don't have to.
        """
        super().add_cog(cog)
        log.info(f"Cog loaded: {cog.qualified_name}")

    async def on_command_error(self, context: commands.Context,
                               exception: DiscordException) -> None:
        """Check command errors for UserInputError and reset the cooldown if thrown."""
        if isinstance(exception, commands.UserInputError):
            context.command.reset_cooldown(context)
        else:
            await super().on_command_error(context, exception)

    async def _fetch_image(self, url: str) -> bytes:
        """Retrieve and read image from `url`."""
        log.debug(f"Getting image from: {url}")
        async with self.http_session.get(url) as resp:
            return await resp.read()

    async def _apply_asset(self, target: Union[Guild, User], asset: AssetType,
                           url: str) -> bool:
        """
        Internal method for applying media assets to the guild or the bot.

        This shouldn't be called directly. The purpose of this method is mainly generic
        error handling to reduce needless code repetition.

        Return True if upload was successful, False otherwise.
        """
        log.info(f"Attempting to set {asset.name}: {url}")

        kwargs = {asset.value: await self._fetch_image(url)}
        try:
            async with async_timeout.timeout(5):
                await target.edit(**kwargs)

        except asyncio.TimeoutError:
            log.info("Asset upload timed out")
            return False

        except discord.HTTPException as discord_error:
            log.exception("Asset upload failed", exc_info=discord_error)
            return False

        else:
            log.info(f"Asset successfully applied")
            return True

    @mock_in_debug(return_value=True)
    async def set_banner(self, url: str) -> bool:
        """Set the guild's banner to image at `url`."""
        guild = self.get_guild(Client.guild)
        if guild is None:
            log.info("Failed to get guild instance, aborting asset upload")
            return False

        return await self._apply_asset(guild, AssetType.BANNER, url)

    @mock_in_debug(return_value=True)
    async def set_icon(self, url: str) -> bool:
        """Sets the guild's icon to image at `url`."""
        guild = self.get_guild(Client.guild)
        if guild is None:
            log.info("Failed to get guild instance, aborting asset upload")
            return False

        return await self._apply_asset(guild, AssetType.SERVER_ICON, url)

    @mock_in_debug(return_value=True)
    async def set_avatar(self, url: str) -> bool:
        """Set the bot's avatar to image at `url`."""
        return await self._apply_asset(self.user, AssetType.AVATAR, url)

    @mock_in_debug(return_value=True)
    async def set_nickname(self, new_name: str) -> bool:
        """Set the bot nickname in the main guild to `new_name`."""
        member = self.member
        if member is None:
            log.info(
                "Failed to get bot member instance, aborting asset upload")
            return False

        log.info(f"Attempting to set nickname to {new_name}")
        try:
            await member.edit(nick=new_name)
        except discord.HTTPException as discord_error:
            log.exception("Setting nickname failed", exc_info=discord_error)
            return False
        else:
            log.info("Nickname set successfully")
            return True

    async def send_log(self,
                       title: str,
                       details: str = None,
                       *,
                       icon: str = None) -> None:
        """Send an embed message to the devlog channel."""
        await self.wait_until_guild_available()
        devlog = self.get_channel(Channels.devlog)

        if not devlog:
            log.info(
                f"Fetching devlog channel as it wasn't found in the cache (ID: {Channels.devlog})"
            )
            try:
                devlog = await self.fetch_channel(Channels.devlog)
            except discord.HTTPException as discord_exc:
                log.exception("Fetch failed", exc_info=discord_exc)
                return

        if not icon:
            icon = self.user.avatar_url_as(format="png")

        embed = Embed(description=details)
        embed.set_author(name=title, icon_url=icon)

        await devlog.send(embed=embed)

    async def on_guild_available(self, guild: discord.Guild) -> None:
        """
        Set the internal `_guild_available` event when PyDis guild becomes available.

        If the cache appears to still be empty (no members, no channels, or no roles), the event
        will not be set.
        """
        if guild.id != Client.guild:
            return

        if not guild.roles or not guild.members or not guild.channels:
            log.warning(
                "Guild available event was dispatched but the cache appears to still be empty!"
            )
            return

        self._guild_available.set()

    async def on_guild_unavailable(self, guild: discord.Guild) -> None:
        """Clear the internal `_guild_available` event when PyDis guild becomes unavailable."""
        if guild.id != Client.guild:
            return

        self._guild_available.clear()

    async def wait_until_guild_available(self) -> None:
        """
        Wait until the PyDis guild becomes available (and the cache is ready).

        The on_ready event is inadequate because it only waits 2 seconds for a GUILD_CREATE
        gateway event before giving up and thus not populating the cache for unavailable guilds.
        """
        await self._guild_available.wait()
Ejemplo n.º 29
0
async def _get_xlsx_url(session: aiohttp.ClientSession) -> str:
    """Получить url для файла с инфляцией."""
    async with session.get(URL) as resp:
        html = await resp.text()
    if match := re.search(FILE_PATTERN, html):
        return match.group(0)
Ejemplo n.º 30
0
class FirebaseHTTP:
    """
    HTTP Client for Firebase.

    Args:
        base_url (str): URL to your data.
        auth (string): Auth key.
        loop (class:`asyncio.BaseEventLoop`): Loop.
    """

    def __init__(self, base_url, auth=None, loop=None):
        """Initialise the class."""
        self._loop = loop or asyncio.get_event_loop()
        self._base_url = base_url
        self._auth = auth
        self._session = ClientSession(loop=self._loop)

    async def close(self):
        """Gracefully close the session."""
        await self._session.close()

    async def get(self, *, path=None, params=None):
        """Perform a GET request."""
        return await self._request(method='GET', path=path, params=params)

    async def put(self, *, value, path=None, params=None):
        """Perform a put request."""
        return await self._request(method='PUT', value=value, path=path, params=params)

    async def post(self, *, value, path=None, params=None):
        """Perform a POST request."""
        return await self._request(method='POST', value=value, path=path, params=params)

    async def patch(self, *, value, path=None, params=None):
        """Perform a PATCH request."""
        return await self._request(method='PATCH', value=value, path=path, params=params)

    async def delete(self, *, path=None, params=None):
        """Perform a DELETE request."""
        return await self._request(method='DELETE', path=path, params=params)

    async def stream(self, *, callback, path=None):
        """Hook up to the EventSource stream."""
        url = posixpath.join(self._base_url, path) if path else self._base_url
        headers = {'accept': 'text/event-stream'}
        async with self._session.get(url, headers=headers) as resp:
            while True:
                await FirebaseHTTP._iterate_over_stream(resp.content.read(), callback)

    @staticmethod
    async def _iterate_over_stream(iterable, callback):
        """Iterate over the EventSource stream and pass the event and data to the callback as and when we receive it."""
        async for msg in iterable:
            msg_str = msg.decode('utf-8').strip()

            if not msg_str:
                continue

            key, value = msg_str.split(':', 1)

            if key == 'event' and value == 'cancel':
                raise StreamCancelled('The requested location is no longer allowed due to security/rules changes.')
            elif key == 'event' and value == 'auth_revoked':
                raise StreamAuthRevoked('The auth credentials has expired.')
            elif key == 'event':
                event = value
            elif key == 'data':
                await callback(event=event, data=json.loads(value))

    async def _request(self, *, method, value=None, path=None, params=None):
        """Perform a request to Firebase."""
        url = posixpath.join(self._base_url, path.strip('/')) if path else self._base_url
        url += '.json'
        data = json.dumps(value) if value else None
        params = params or {}
        headers = {}
        if self._auth:
            params.update({'auth': self._auth})
            headers.update({'typ': 'JWT', 'alg': 'HS256'})
        async with self._session.request(method, url, data=data, params=params, headers=headers) as resp:
            assert resp.status == 200
            return await resp.json()
Ejemplo n.º 31
0
async def make_riot_request(
        cls: AAshe.sqlite.SQLite, aiosession: aiohttp.ClientSession, region: str, url: str, headers: dict, timeout: int=10, count=True) \
  ->(bytes, dict):
    """
	Makes a web request with an aiosession and returns the data.

	Args:
		cls: AAshe.sqlite.MessagePrint
			Used to broadcast status messages.
		aiosession:
			aiosession used to make the request.
		region:
			Region used in the request.
		url:
			URL to call.
		headers:
			Headers used for the call, usually empty.
		timeout:
			Timeout timer.
		count:
			If it should count on the rate limit.

	Returns:
		(bytes, dict)
			Contains the raw data, and the return headers.
	"""
    # Insures there is a Rate Limit object
    if ratelimit.RateLimit.key_limit is None:
        ratelimit.RateLimit.key_limit = ratelimit.RateLimit(
            name="Api Key Limit")

    # Checks the rate limits
    await ratelimit.RateLimit.key_limit.check_cooldown(region=region,
                                                       count=count)

    resp_data = None
    resp_headers = None
    # Makes actual request
    with aiohttp.Timeout(timeout):
        async with aiosession.get(url=url.format(region.lower()),
                                  headers=headers) as resp:
            resp_data = await resp.read()
            resp_headers = resp.headers

    if region.lower() not in ratelimit.RateLimit.key_limit.region_limits:
        cls.info(msg="Region was not within dictionary, adding.")
        ratelimit.RateLimit.key_limit.region_limits[
            region.lower()] = ratelimit.RateLimit.Region(region=region,
                                                         lock=True)

    region_limit = ratelimit.RateLimit.key_limit.region_limits[region.lower()]

    if resp_headers:
        if "X-App-Rate-Limit" in resp_headers and "X-App-Rate-Limit-Count" in resp_headers:
            if time.time(
            ) - region_limit.time > ratelimit.RateLimit.key_refresh_cooldown:
                if ratelimit.RateLimit.key_refresh_cooldown != 0 or not region_limit.limits:
                    # Cleanup old
                    if isinstance(region_limit.limits, list):
                        for i, limit in enumerate(region_limit.limits):
                            del region_limit.limits[i]
                    region_limit.limits = []

                    # Prepare new
                    rate_limits = {}
                    for str_limit in resp_headers["X-App-Rate-Limit"].strip(
                    ).split(","):
                        period, every = str_limit.split(":", 1)

                        rate_limits[int(every)] = int(period)

                    rate_limit_count = {}
                    for str_limit in resp_headers[
                            "X-App-Rate-Limit-Count"].strip().split(","):
                        count, every = str_limit.split(":", 1)

                        rate_limit_count[int(every)] = int(count)

                    # Adds them
                    for every in list(rate_limits.keys()):
                        if ratelimit.RateLimit.key_limit.add_limit(
                                period=rate_limits[every],
                                every=float(every),
                                region=region,
                                count=rate_limit_count[every]):

                            cls.debug(
                                msg=
                                f"Added limit <{rate_limits[every]}/{every}s> with count {rate_limit_count[every]}."
                            )

    if "status" in json.loads(resp_data.decode()):
        exceptions = \
         {
          # You f****d up
          400: errors.BadRequest,
          401: errors.Unauthorized,
          403: errors.Forbidden,
          404: errors.DataNotFound,
          405: errors.MethodNotAllowed,
          415: errors.UnsupportedMediaType,
          429: errors.RateLimitExceeded,

          # Server f****d up
          500: errors.InternalServerError,
          502: errors.BadGateway,
          503: errors.ServiceUnavailable,
          504: errors.GatewayTimeout
         }

        exception = exceptions[json.loads(
            resp_data.decode())["status"]["status_code"]]
        exception.server_message = json.loads(
            resp_data.decode())["status"]["message"]
        raise exception

    return resp_data, resp_headers
Ejemplo n.º 32
0
Archivo: nhl.py Proyecto: aaront/puckdb
async def _get(url: str, session: aiohttp.ClientSession):
    async with session.get(url, headers=_HEADERS) as response:
        assert response.status == 200
        return await response.json(loads=ujson.loads)
Ejemplo n.º 33
0
async def draw_rank(session: ClientSession, user: Member) -> Image:
    name_fnt = ImageFont.truetype(font_heavy_file, 24)
    name_u_fnt = ImageFont.truetype(font_unicode_file, 24)
    label_fnt = ImageFont.truetype(font_bold_file, 16)
    exp_fnt = ImageFont.truetype(font_bold_file, 9)
    large_fnt = ImageFont.truetype(font_thin_file, 24)
    symbol_u_fnt = ImageFont.truetype(font_unicode_file, 15)

    def _write_unicode(text, init_x, y, font, unicode_font, fill):
        write_pos = init_x

        for char in text:
            if char.isalnum() or char in string.punctuation or char in string.whitespace:
                draw.text((write_pos, y), char, font=font, fill=fill)
                write_pos += font.getsize(char)[0]
            else:
                draw.text((write_pos, y), u"{}".format(char), font=unicode_font, fill=fill)
                write_pos += unicode_font.getsize(char)[0]

    user_info = db.user(user)

    bg_url = await user_info.rank_background()
    profile_url = user.avatar_url

    async with session.get(bg_url) as r:
        bg_image = Image.open(BytesIO(await r.content.read())).convert("RGBA")
    async with session.get(profile_url) as r:
        profile_image = Image.open(BytesIO(await r.content.read())).convert("RGBA")

    member_info = db.member(user)
    user_exp = await member_info.current_exp()
    user_level = await member_info.level()
    exp_color = tuple(await user_info.rank_info_color())

    # set canvas
    width = 390
    height = 100
    bg_color = (255, 255, 255, 0)
    bg_width = width - 50
    result = Image.new("RGBA", (width, height), bg_color)
    process = Image.new("RGBA", (width, height), bg_color)
    draw = ImageDraw.Draw(process)

    # info section
    info_section = Image.new("RGBA", (bg_width, height), bg_color)
    info_section_process = Image.new("RGBA", (bg_width, height), bg_color)
    # puts in background
    bg_image = bg_image.resize((width, height), Image.ANTIALIAS)
    bg_image = bg_image.crop((0, 0, width, height))
    info_section.paste(bg_image, (0, 0))

    # draw transparent overlays
    draw_overlay = ImageDraw.Draw(info_section_process)
    draw_overlay.rectangle([(0, 0), (bg_width, 20)], fill=(230, 230, 230, 200))
    draw_overlay.rectangle([(0, 20), (bg_width, 30)], fill=(120, 120, 120, 180))  # Level bar
    exp_width = int(bg_width * (user_exp / _required_exp(user_level)))

    draw_overlay.rectangle([(0, 20), (exp_width, 30)], fill=exp_color)  # Exp bar
    draw_overlay.rectangle([(0, 30), (bg_width, 31)], fill=(0, 0, 0, 255))  # Divider
    for i in range(0, 70):
        draw_overlay.rectangle(
            [(0, height - i), (bg_width, height - i)], fill=(20, 20, 20, 255 - i * 3)
        )  # title overlay

    # draw corners and finalize
    info_section = Image.alpha_composite(info_section, info_section_process)
    info_section = _add_corners(info_section, 25)
    process.paste(info_section, (35, 0))

    # draw level circle
    multiplier = 6
    lvl_circle_dia = 100
    circle_left = 0
    circle_top = int((height - lvl_circle_dia) / 2)
    raw_length = lvl_circle_dia * multiplier

    # create mask
    mask = Image.new("L", (raw_length, raw_length), 0)
    draw_thumb = ImageDraw.Draw(mask)
    draw_thumb.ellipse((0, 0) + (raw_length, raw_length), fill=255, outline=0)

    # drawing level border
    lvl_circle = Image.new("RGBA", (raw_length, raw_length))
    draw_lvl_circle = ImageDraw.Draw(lvl_circle)
    draw_lvl_circle.ellipse([0, 0, raw_length, raw_length], fill=(250, 250, 250, 250))

    # put on profile circle background
    lvl_circle = lvl_circle.resize((lvl_circle_dia, lvl_circle_dia), Image.ANTIALIAS)
    lvl_bar_mask = mask.resize((lvl_circle_dia, lvl_circle_dia), Image.ANTIALIAS)
    process.paste(lvl_circle, (circle_left, circle_top), lvl_bar_mask)

    # draws mask
    total_gap = 6
    border = int(total_gap / 2)
    profile_size = lvl_circle_dia - total_gap
    # put in profile picture
    mask = mask.resize((profile_size, profile_size), Image.ANTIALIAS)
    profile_image = profile_image.resize((profile_size, profile_size), Image.ANTIALIAS)
    process.paste(profile_image, (circle_left + border, circle_top + border), mask)

    # draw text
    grey_color = (100, 100, 100, 255)
    white_color = (220, 220, 220, 255)

    # name
    _write_unicode(
        _truncate_text(get_user_display_name(user, 20), 20), 100, 0, name_fnt, name_u_fnt, grey_color
    )  # Name

    # labels
    v_label_align = 75
    info_text_color = white_color
    draw.text(
        (_center(100, 200, "  RANK", label_fnt), v_label_align),
        "  RANK",
        font=label_fnt,
        fill=info_text_color,
    )  # Rank
    draw.text(
        (_center(100, 360, "  LEVEL", label_fnt), v_label_align),
        "  LEVEL",
        font=label_fnt,
        fill=info_text_color,
    )  # Rank
    draw.text(
        (_center(260, 360, "BALANCE", label_fnt), v_label_align),
        "BALANCE",
        font=label_fnt,
        fill=info_text_color,
    )  # Rank
    if "linux" in platform.system().lower():
        local_symbol = u"\U0001F3E0 "
        _write_unicode(
            local_symbol, 117, v_label_align + 4, label_fnt, symbol_u_fnt, info_text_color
        )  # Symbol
        _write_unicode(
            local_symbol, 195, v_label_align + 4, label_fnt, symbol_u_fnt, info_text_color
        )  # Symbol

    # userinfo
    guild_rank = f"#{await _find_guild_rank(user)}"
    draw.text(
        (_center(100, 200, guild_rank, large_fnt), v_label_align - 30),
        guild_rank,
        font=large_fnt,
        fill=info_text_color,
    )  # Rank
    level_text = str(user_level)
    draw.text(
        (_center(95, 360, level_text, large_fnt), v_label_align - 30),
        level_text,
        font=large_fnt,
        fill=info_text_color,
    )  # Level
    credit_txt = f"${await bank.get_balance(user)}"
    draw.text(
        (_center(260, 360, credit_txt, large_fnt), v_label_align - 30),
        credit_txt,
        font=large_fnt,
        fill=info_text_color,
    )  # Balance
    exp_text = f"{user_exp}/{_required_exp(user_level)}"
    draw.text(
        (_center(80, 360, exp_text, exp_fnt), 19),
        exp_text,
        font=exp_fnt,
        fill=info_text_color,
    )  # Rank

    return Image.alpha_composite(result, process)
Ejemplo n.º 34
0
 async def one_request(cls, session: aiohttp.ClientSession, url, params):
     async with session.get(url=url, params=params) as res:
         rs = await res.read()
         return rs
async def worker(queue: asyncio.Queue, session: aiohttp.ClientSession):
    global done, wait_a_little
    while True:
        if done:
            return
        else:
            try:
                info = await asyncio.wait_for(queue.get(), 100)
            except asyncio.exceptions.TimeoutError:
                print("等待超过了100秒, 如果在接下来120秒内没有响应将退出.")
                try:
                    info = await asyncio.wait_for(queue.get(), 120)
                except asyncio.exceptions.TimeoutError:
                    print("已经等待了120秒, 生成器没有输出, 该协程退出.")
                    break
        """
        if Path(f"./mods/{info['name']}").exists():
            # 校验其长度
            size = os.path.getsize(Path(f"./mods/{info['name']}").absolute())
            if size == info['file-length']:
                print(f"warn: {info['name']} 已存在, 跳过.")
                continue
            else:
                print(f"warn: {info['name']} 不完整, 重新爬取")
        """

        print(f"开始获取 [{info['name']}][{info['url']}] ")
        try:
            async with session.get(info['url']) as response:
                file_content = await response.read()
                with tempfile.TemporaryFile("r+b") as f:
                    f.write(file_content)
                    f.seek(0)
                    zipFile = zipfile.ZipFile(f)
                    with tempfile.TemporaryDirectory() as td_name:
                        # td = TemporaryDirectory
                        zipFile.extractall(td_name)

                        td_path = Path(td_name)
                        paths = glob.glob(
                            str(td_path.absolute()) + "/assets/*/lang")
                        domains = [i.string[i.start():i.end()] for i in [
                            re.search(r"(?<=(assets\/))[a-zA-Z0-9]*(?=(\/lang))", i.replace("\\", "/"))\
                            for i in paths
                        ] if i]
                        for domain in domains:
                            if not domain:
                                continue

                            if f"{info['name']}::{domain}" in config.namespace_domain_blacklist:
                                print(
                                    f"检测到模组 {info['name']} 正在尝试修改被列入命名空间黑名单的资源域 {domain}, 已阻止."
                                )
                                continue

                            domain_dir = Path(f"./project/assets/{domain}")
                            if not domain_dir.exists():
                                domain_dir.absolute().mkdir()

                            domain_lang = domain_dir / "lang"
                            if not domain_lang.exists():
                                domain_lang.absolute().mkdir()

                            # touch 各个文件
                            touch_list: List[Path] = [
                                (td_path / "assets" / domain / "lang" /
                                 filename) for filename in [
                                     "en_us.lang", "zh_cn.lang",
                                     "en_us_old.lang", "zh_cn_old.lang"
                                 ]
                            ]
                            for filename in touch_list:
                                if not filename.exists():
                                    filename.touch()

                            # 复制文件到{tmp}/assets/{domain}/lang下
                            domain_root = Path(f"./project/assets/{domain}")
                            project_en_us: Path = domain_root / "lang" / "en_us.lang"
                            project_zh_cn: Path = domain_root / "lang" / "zh_cn.lang"
                            if project_en_us.exists(
                            ) and project_en_us.is_file():
                                shutil.copy(
                                    str(project_en_us.absolute()),
                                    str(td_path / "assets" / domain / "lang" /
                                        "en_us_old.lang"))
                            if project_zh_cn.exists(
                            ) and project_zh_cn.is_file():
                                shutil.copy(
                                    str(project_zh_cn.absolute()),
                                    str(td_path / "assets" / domain / "lang" /
                                        "zh_cn.lang"))

                            # 复制重构完毕.
                            # 开始预处理....
                            # ph = pre handle
                            ph_en_us: Path = td_path / "assets" / domain / "lang" / "en_us.lang"
                            if ph_en_us.exists() and ph_en_us.is_file():
                                ph_en_us.write_text(ph_en_us.read_text(
                                    encoding="utf-8", errors="replace"),
                                                    encoding="utf-8",
                                                    errors="replace")
                                # 自动转换编码

                                if not utils.is_properties_language_file(
                                        str(ph_en_us.absolute())):
                                    utils.language_file_delete_and_fix(
                                        str(ph_en_us.absolute()))

                        # 开始删除..
                        for item in config.delete_list:
                            if os.path.exists(td_name + "/assets/" + item):
                                shutil.rmtree(td_name + "/assets/" + item)
                            if Path(f"./project/assets/{item}").exists():
                                print(f"删除项 [{item}]")
                                shutil.rmtree(f"./project/assets/{item}")
                            if item in domains:
                                domains.remove(item)

                        # 开始复制
                        for i in domains:
                            local_lang = Path(
                                f"./project/assets/{i}/lang/en_us.lang")

                            if not local_lang.exists():
                                with open(str(local_lang.absolute()),
                                          "a") as f:
                                    f.write("")
                            else:
                                # 不需要处理 en_us_old.lang 了
                                pass

                            shutil.copyfile(
                                f"{td_name}/assets/{i}/lang/en_US.lang",
                                str(local_lang.absolute()))
                            # 处理date文件
                        print(f"处理 [{info['name']}] 完毕.")
        except Exception as e:
            print(f"在爬取 [{info['name']}] 时发生了错误, 尝试重新排入队列", type(e))
            traceback.print_exc()
            wait_a_little = True
            await queue.put(info)
Ejemplo n.º 36
0
class Client:
    """MELCloud client.

    Please do not use this class directly. It is better to use the get_devices
    method exposed by the __init__.py.
    """
    def __init__(
            self,
            token: str,
            session: Optional[ClientSession] = None,
            *,
            conf_update_interval=timedelta(minutes=5),
            device_set_debounce=timedelta(seconds=1),
    ):
        """Initialize MELCloud client."""
        self._token = token
        if session:
            self._session = session
            self._managed_session = False
        else:
            self._session = ClientSession()
            self._managed_session = True
        self._conf_update_interval = conf_update_interval
        self._device_set_debounce = device_set_debounce

        self._last_conf_update = None
        self._device_confs: List[Dict[str, Any]] = []
        self._account: Optional[Dict[str, Any]] = None

    @property
    def token(self) -> str:
        """Return currently used token."""
        return self._token

    @property
    def device_confs(self) -> List[Dict[Any, Any]]:
        """Return device configurations."""
        return self._device_confs

    @property
    def account(self) -> Optional[Dict[Any, Any]]:
        """Return account."""
        return self._account

    async def _fetch_user_details(self):
        """Fetch user details."""
        async with self._session.get(
                f"{BASE_URL}/User/GetUserDetails",
                headers=_headers(self._token),
                raise_for_status=True,
        ) as resp:
            self._account = await resp.json()

    async def _fetch_device_confs(self):
        """Fetch all configured devices."""
        url = f"{BASE_URL}/User/ListDevices"
        async with self._session.get(url,
                                     headers=_headers(self._token),
                                     raise_for_status=True) as resp:
            entries = await resp.json()
            new_devices = []
            for entry in entries:
                new_devices = new_devices + entry["Structure"]["Devices"]

                for area in entry["Structure"]["Areas"]:
                    new_devices = new_devices + area["Devices"]

                for floor in entry["Structure"]["Floors"]:
                    new_devices = new_devices + floor["Devices"]

                    for area in floor["Areas"]:
                        new_devices = new_devices + area["Devices"]

            visited = set()
            self._device_confs = [
                d for d in new_devices if d["DeviceID"] not in visited
                and not visited.add(d["DeviceID"])
            ]

    async def update_confs(self):
        """Update device_confs and account.

        Calls are rate limited to allow Device instances to freely poll their own
        state while refreshing the device_confs list and account.
        """
        now = datetime.now()
        if (self._last_conf_update is not None
                and now - self._last_conf_update < self._conf_update_interval):
            return None

        self._last_conf_update = now
        await self._fetch_user_details()
        await self._fetch_device_confs()

    async def fetch_device_units(self, device) -> Optional[Dict[Any, Any]]:
        """Fetch unit information for a device.

        User provided info such as indoor/outdoor unit model names and
        serial numbers.
        """
        async with self._session.post(
                f"{BASE_URL}/Device/ListDeviceUnits",
                headers=_headers(self._token),
                json={"deviceId": device.device_id},
                raise_for_status=True,
        ) as resp:
            return await resp.json()

    async def fetch_device_state(self, device) -> Optional[Dict[Any, Any]]:
        """Fetch state information of a device.

        This method should not be called more than once a minute. Rate
        limiting is left to the caller.
        """
        device_id = device.device_id
        building_id = device.building_id
        async with self._session.get(
                f"{BASE_URL}/Device/Get?id={device_id}&buildingID={building_id}",
                headers=_headers(self._token),
                raise_for_status=True,
        ) as resp:
            return await resp.json()

    async def set_device_state(self, device):
        """Update device state.

        This method is as dumb as it gets. Device is responsible for updating
        the state and managing EffectiveFlags.
        """
        device_type = device.get("DeviceType")
        if device_type == 0:
            setter = "SetAta"
        elif device_type == 1:
            setter = "SetAtw"
        elif device_type == 3:
            setter = "SetErv"
        else:
            raise ValueError(f"Unsupported device type [{device_type}]")

        async with self._session.post(
                f"{BASE_URL}/Device/{setter}",
                headers=_headers(self._token),
                json=device,
                raise_for_status=True,
        ) as resp:
            return await resp.json()
Ejemplo n.º 37
0
async def update_index(
    http_client: aiohttp.ClientSession, token: str, uploader: Uploader
) -> bool:
    try:
        logger.info("finding shared folder link")
        headers = {"Authorization": "Bearer " + token}
        params = {
            "path": "/Public",
            "direct_only": True,
        }
        async with http_client.post(
            DROPBOX_API_URL + "/2/sharing/list_shared_links",
            headers=headers,
            json=params,
        ) as resp:
            await raise_for_status_body(resp)
            for link in (await resp.json())["links"]:
                if link[".tag"] != "folder":
                    continue
                try:
                    visibility = link["link_permissions"]["resolved_visibility"][".tag"]
                except KeyError:
                    continue
                if visibility == "public":
                    break
            else:
                raise Exception("shared folder link not found")

        logger.info("walking shared folder")
        async for path, files, dirs in walk_shared_folder(http_client, link["url"]):
            lines = []
            old_lines = []
            for name, href in files:
                href = make_download_url(href)
                lines.append(name + "\t" + href + "\n")
                if name == "INDEX":
                    async with http_client.get(href, raise_for_status=True) as resp:
                        old_lines = (await resp.text()).splitlines(keepends=True)
            lines.extend(name + "/\t" + href + "\n" for name, href in dirs)
            lines.sort()

            index_path = (path + "/" if path else "") + "INDEX"
            if lines == old_lines:
                logger.info("%s is up to date", index_path)
                continue
            diff = difflib.unified_diff(
                old_lines, lines, fromfile="a/" + index_path, tofile="b/" + index_path
            )
            logger.info("updating %s:\n%s", index_path, "".join(diff).rstrip("\n"))
            uploader.queue_file_obj(
                io.BytesIO("".join(lines).encode()),
                "/Public/" + index_path,
                mode="overwrite",
            )
        succeeded, failed = await uploader.wait()
        if failed:
            logger.info("updates failed: %s", ", ".join(failed))
            return False
        return True
    except Exception:
        logger.exception("updating INDEX files failed")
        return False
Ejemplo n.º 38
0
async def _load_from_url(session: ClientSession, url: URL) -> Tuple[Dict, str]:
    async with session.get(url) as resp:
        text = await resp.text()
        spec_dict = yaml.safe_load(text)
        return spec_dict, str(url)
Ejemplo n.º 39
0
async def get_full_image_data(session: ClientSession, token: str,
                              image_id: str) -> dict:
    async with session.get(f"{API_BASE_URL}{API_IMAGES_URI}/{image_id}",
                           headers={"Authorization":
                                    f"Bearer {token}"}) as response:
        return await response.json()
Ejemplo n.º 40
0
class HttpTrackerSession(TrackerSession):
    def __init__(self, tracker_url, tracker_address, announce_page, timeout,
                 proxy):
        super().__init__('http', tracker_url, tracker_address, announce_page,
                         timeout)
        self._session = ClientSession(
            connector=Socks5Connector(proxy) if proxy else None,
            raise_for_status=True,
            timeout=ClientTimeout(total=self.timeout))

    async def connect_to_tracker(self):
        # create the HTTP GET message
        # Note: some trackers have strange URLs, e.g.,
        #       http://moviezone.ws/announce.php?passkey=8ae51c4b47d3e7d0774a720fa511cc2a
        #       which has some sort of 'key' as parameter, so we need to use the add_url_params
        #       utility function to handle such cases.

        url = add_url_params(
            "http://%s:%s%s" %
            (self.tracker_address[0], self.tracker_address[1],
             self.announce_page.replace('announce', 'scrape')),
            {"info_hash": self.infohash_list})

        # no more requests can be appended to this session
        self.is_initiated = True
        self.last_contact = int(time.time())

        try:
            self._logger.debug("%s HTTP SCRAPE message sent: %s", self, url)
            async with self._session:
                async with self._session.get(
                        url.encode('ascii').decode('utf-8')) as response:
                    body = await response.read()
        except UnicodeEncodeError as e:
            raise e
        except ClientResponseError as e:
            self._logger.warning("%s HTTP SCRAPE error response code %s", self,
                                 e.status)
            self.failed(msg=f"error code {e.status}")
        except Exception as e:
            self.failed(msg=str(e))

        return self._process_scrape_response(body)

    def _process_scrape_response(self, body):
        """
        This function handles the response body of a HTTP tracker,
        parsing the results.
        """
        # parse the retrieved results
        if body is None:
            self.failed(msg="no response body")

        response_dict = bdecode_compat(body)
        if not response_dict:
            self.failed(msg="no valid response")

        response_list = []

        unprocessed_infohash_list = self.infohash_list[:]
        if b'files' in response_dict and isinstance(response_dict[b'files'],
                                                    dict):
            for infohash in response_dict[b'files']:
                complete = 0
                incomplete = 0
                if isinstance(response_dict[b'files'][infohash], dict):
                    complete = response_dict[b'files'][infohash].get(
                        b'complete', 0)
                    incomplete = response_dict[b'files'][infohash].get(
                        b'incomplete', 0)

                # Sow complete as seeders. "complete: number of peers with the entire file, i.e. seeders (integer)"
                #  - https://wiki.theory.org/BitTorrentSpecification#Tracker_.27scrape.27_Convention
                seeders = complete
                leechers = incomplete

                # Store the information in the dictionary
                response_list.append({
                    'infohash': hexlify(infohash),
                    'seeders': seeders,
                    'leechers': leechers
                })

                # remove this infohash in the infohash list of this session
                if infohash in unprocessed_infohash_list:
                    unprocessed_infohash_list.remove(infohash)

        elif b'failure reason' in response_dict:
            self._logger.info("%s Failure as reported by tracker [%s]", self,
                              repr(response_dict[b'failure reason']))
            self.failed(msg=repr(response_dict[b'failure reason']))

        # handle the infohashes with no result (seeders/leechers = 0/0)
        for infohash in unprocessed_infohash_list:
            response_list.append({
                'infohash': hexlify(infohash),
                'seeders': 0,
                'leechers': 0
            })

        self.is_finished = True
        return {self.tracker_url: response_list}

    async def cleanup(self):
        """
        Cleans the session by cancelling all deferreds and closing sockets.
        :return: A deferred that fires once the cleanup is done.
        """
        await self._session.close()
        await super().cleanup()
Ejemplo n.º 41
0
class SmartThingsTV:
    def __init__(
        self,
        api_key: str,
        device_id: str,
        use_channel_info: bool = True,
        session: Optional[ClientSession] = None,
    ):
        """Initialize SmartThingsTV."""
        self._api_key = api_key
        self._device_id = device_id
        self._use_channel_info = use_channel_info
        if session:
            self._session = session
            self._managed_session = False
        else:
            self._session = ClientSession()
            self._managed_session = True

        self._device_name = None
        self._state = STStatus.STATE_UNKNOWN
        self._prev_state = STStatus.STATE_UNKNOWN
        self._muted = False
        self._volume = 10
        self._source_list = None
        self._source = ""
        self._channel = ""
        self._channel_name = ""

        self._is_forced_val = False
        self._forced_count = 0

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        pass

    @property
    def api_key(self) -> str:
        """Return currently api_key."""
        return self._api_key

    @property
    def device_id(self) -> str:
        """Return currently device_id."""
        return self._device_id

    @property
    def device_name(self) -> str:
        """Return currently device_name."""
        return self._device_name

    @property
    def state(self):
        """Return currently state."""
        return self._state

    @property
    def prev_state(self):
        """Return currently state."""
        return self._prev_state

    @property
    def muted(self) -> bool:
        """Return currently muted state."""
        return self._muted

    @property
    def volume(self) -> int:
        """Return currently volume."""
        return self._volume

    @property
    def source(self) -> str:
        """Return currently source."""
        return self._source

    @property
    def channel(self) -> str:
        """Return currently channel."""
        return self._channel

    @property
    def channel_name(self) -> str:
        """Return currently channel name."""
        return self._channel_name

    @property
    def source_list(self):
        """Return currently source list."""
        return self._source_list

    def set_application(self, app_id):
        if self._use_channel_info:
            self._channel = ""
            self._channel_name = app_id
            self._is_forced_val = True
            self._forced_count = 0

    def _set_source(self, source):
        if source != self._source:
            self._source = source
            self._channel = ""
            self._channel_name = ""
            self._is_forced_val = True
            self._forced_count = 0

    @staticmethod
    async def get_devices_list(api_key,
                               session: ClientSession,
                               device_label=""):
        """Get list of available devices"""

        result = {}

        async with session.get(
                API_DEVICES,
                headers=_headers(api_key),
                raise_for_status=True,
        ) as resp:
            device_list = await resp.json()

        if device_list:
            _LOGGER.debug("SmartThings available devices: %s",
                          str(device_list))

            for k in device_list.get("items", []):
                device_id = k.get("deviceId", "")
                device_type = k.get("type", "")
                device_type_id = k.get("deviceTypeId", "")
                if device_id and (device_type_id == DEVICE_TYPEID_OCF
                                  or device_type == DEVICE_TYPE_OCF):
                    label = k.get("label", "")
                    if device_label == "" or (label == device_label
                                              and label != ""):
                        result.setdefault(device_id,
                                          {})["name"] = k.get("name", "")
                        result.setdefault(device_id, {})["label"] = label

        _LOGGER.info("SmartThings discovered TV devices: %s", str(result))

        return result

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    async def _device_refresh(self, **kwargs):
        """Refresh device status on SmartThings"""

        device_id = self._device_id
        if not device_id:
            return

        api_device = f"{API_DEVICES}/{device_id}"
        api_command = f"{api_device}/commands"

        if self._use_channel_info:
            async with self._session.post(
                    api_command,
                    headers=_headers(self._api_key),
                    data=COMMAND_REFRESH,
                    raise_for_status=False,
            ) as resp:
                if resp.status == 409:
                    self._state = STStatus.STATE_OFF
                    return
                resp.raise_for_status()
                await resp.json()

        return

    async def async_device_health(self):
        """Check device availability"""

        device_id = self._device_id
        if not device_id:
            return False

        api_device = f"{API_DEVICES}/{device_id}"
        api_device_health = f"{api_device}/health"

        # this get the real status of the device
        async with self._session.get(
            api_device_health,
            headers=_headers(self._api_key),
            raise_for_status=True,
        ) as resp:
            health = await resp.json()

        _LOGGER.debug(health)

        if health["state"] == "ONLINE":
            return True
        return False

    async def async_device_update(self, use_channel_info: bool = None):
        """Query device status on SmartThing"""

        device_id = self._device_id
        if not device_id:
            return

        if use_channel_info is not None:
            self._use_channel_info = use_channel_info

        api_device = f"{API_DEVICES}/{device_id}"
        api_device_status = f"{api_device}/states"
        # not used, just for reference
        api_device_main_status = f"{api_device}/components/main/status"

        self._prev_state = self._state

        try:
            is_online = await self.async_device_health()
        except (
                AsyncTimeoutError,
                ClientConnectionError,
                ClientResponseError,
        ):
            self._state = STStatus.STATE_UNKNOWN
            return

        if is_online:
            self._state = STStatus.STATE_ON
        else:
            self._state = STStatus.STATE_OFF
            return

        await self._device_refresh()
        if self._state == STStatus.STATE_OFF:
            return

        async with self._session.get(
                api_device_status,
                headers=_headers(self._api_key),
                raise_for_status=True,
        ) as resp:
            data = await resp.json()

        _LOGGER.debug(data)

        dev_data = data.get("main", {})
        # device_state = data['main']['switch']['value']
        device_volume = dev_data.get("volume", {}).get("value", 0)
        device_muted = dev_data.get("mute", {}).get("value", "")
        device_source = dev_data.get("inputSource", {}).get("value", "")
        device_tv_chan = dev_data.get("tvChannel", {}).get("value", "")
        device_tv_chan_name = dev_data.get("tvChannelName",
                                           {}).get("value", "")
        device_all_sources = {}

        json_sources = dev_data.get("supportedInputSources", {}).get("value")
        if json_sources:
            try:
                device_all_sources = json.loads(json_sources)
            except (TypeError, ValueError):
                pass

        if device_volume and device_volume.isdigit():
            self._volume = int(device_volume) / 100
        else:
            self._volume = 0
        self._source_list = device_all_sources
        if device_muted == "mute":
            self._muted = True
        else:
            self._muted = False

        if self._is_forced_val and self._forced_count <= 0:
            self._forced_count += 1
            return

        self._is_forced_val = False
        self._forced_count = 0
        self._source = device_source
        # if the status is not refreshed this info may become not reliable
        if self._use_channel_info:
            self._channel = device_tv_chan
            self._channel_name = device_tv_chan_name
        else:
            self._channel = ""
            self._channel_name = ""

    async def async_send_command(self, cmdtype, command=""):
        """Send a command too the device"""

        device_id = self._device_id
        if not device_id:
            return

        api_device = f"{API_DEVICES}/{device_id}"
        api_command = f"{api_device}/commands"
        datacmd = None

        if cmdtype == "turn_off":  # turns off
            datacmd = COMMAND_POWER_OFF
        elif cmdtype == "turn_on":  # turns on
            datacmd = COMMAND_POWER_ON
        elif cmdtype == "setvolume":  # sets volume
            cmdargs = ARGS_SET_VOLUME.format(command)
            datacmd = COMMAND_SET_VOLUME + cmdargs
        elif cmdtype == "stepvolume":  # steps volume up or down
            if command == "up":
                datacmd = COMMAND_VOLUME_UP
            elif command == "down":
                datacmd = COMMAND_VOLUME_DOWN
        elif cmdtype == "audiomute":  # mutes audio
            if command == "on":
                datacmd = COMMAND_MUTE
            elif command == "off":
                datacmd = COMMAND_UNMUTE
        elif cmdtype == "selectchannel":  # changes channel
            cmdargs = ARGS_SET_CHANNEL.format(command)
            datacmd = COMMAND_SET_CHANNEL + cmdargs
        elif cmdtype == "stepchannel":  # steps channel up or down
            if command == "up":
                datacmd = COMMAND_CHANNEL_UP
            elif command == "down":
                datacmd = COMMAND_CHANNEL_DOWN
        elif cmdtype == "selectsource":  # changes source
            cmdargs = ARGS_SET_SOURCE.format(command)
            datacmd = COMMAND_SET_SOURCE + cmdargs
            # set property to reflect new changes
            self._set_source(command)

        if datacmd:
            async with self._session.post(
                    api_command,
                    headers=_headers(self._api_key),
                    data=datacmd,
                    raise_for_status=True,
            ) as resp:
                await resp.json()

            await self._device_refresh()
Ejemplo n.º 42
0
async def fetch(session: aiohttp.ClientSession):
    print("Query http://httpbin.org/get")
    async with session.get("http://httpbin.org/get") as resp:
        print(resp.status)
        data = await resp.json()
        print(data)
Ejemplo n.º 43
0
class OwnerCommands(object):
    def __init__(self, bot: CustomBot):
        self.bot = bot
        self.session = ClientSession(loop=bot.loop)

    def __unload(self):
        self.session.close()

    async def __local_check(self, ctx: Context):
        x = await is_owner(ctx)
        if x:
            return True
        raise NotOwner()

    @command()
    async def runsql(self, ctx: Context, *, content: str):
        '''
        Runs a line of SQL into the sparcli database
        '''

        async with self.bot.database() as db:
            x = await db(content) or 'No content.'
        if type(x) in [str, type(None)]:
            await ctx.send(x)
            return

        # Get the results into groups
        column_headers = list(x[0].keys())
        grouped_outputs = {}
        for i in column_headers:
            grouped_outputs[i] = []
        for guild_data in x:
            for i, o in guild_data.items():
                grouped_outputs[i].append(str(o))

        # Everything is now grouped super nicely
        # Now to get the maximum length of each column and add it as the last item
        for key, item_list in grouped_outputs.items():
            max_len = max([len(i) for i in item_list + [key]])
            grouped_outputs[key].append(max_len)

        # Format the outputs and add to a list
        key_headers = []
        temp_output = []
        for key, value in grouped_outputs.items():
            # value is a list of unformatted strings
            key_headers.append(format(key, '<' + str(value[-1])))
            formatted_values = [
                format(i, '<' + str(value[-1])) for i in value[:-1]
            ]
            # string_value = '|'.join(formatted_values)
            temp_output.append(formatted_values)
        key_string = '|'.join(key_headers)

        # Rotate the list because apparently I need to
        output = []
        for i in range(len(temp_output[0])):
            temp = []
            for o in temp_output:
                temp.append(o[i])
            output.append('|'.join(temp))

        # Add some final values before returning to the user
        line = '-' * len(key_string)
        output = [key_string, line] + output
        string_output = '\n'.join(output)
        await ctx.send('```\n{}```'.format(string_output))

    @group()
    async def profile(self, ctx: Context):
        '''
        A parent group for the different profile commands
        '''

        pass

    @profile.command(aliases=['username'])
    async def name(self, ctx: Context, *, username: str):
        '''
        Lets you change the username of the bot
        '''

        if len(username) > 32:
            await ctx.send(
                'That username is too long to be compatible with Discord.')
            return

        await self.bot.user.edit(username=username)
        await ctx.send('Done.')

    @profile.command(aliases=['picture'])
    async def avatar(self, ctx: Context, *, url: str = None):
        '''
        Allows you to change the avatar of the bot to a URL or attached picture
        '''

        # Make sure a URL is passed
        if url == None:
            try:
                url = ctx.message.attachments[0].url
            except IndexError:
                raise MissingRequiredArgument(self.avatar.params['url'])

        # Get the image
        async with self.session.get(url) as r:
            content = await r.read()

        # Edit the profile
        await self.bot.user.edit(avatar=content)
        await ctx.send('Done.')

    @profile.command()
    async def game(self,
                   ctx: Context,
                   game_type: int = None,
                   *,
                   name: str = None):
        '''
        Change the game that the bot is playing
        '''

        if not name:
            name = self.bot.config['Game']['name']
        if not game_type:
            game_type = self.bot.config['Game']['type']
        game = Game(name=name, type=game_type)
        await self.bot.change_presence(activity=game)
        await ctx.send('Done.')

    @command()
    async def embed(self, ctx: Context, *, content: str):
        '''
        Creates an embed from raw JSON data
        '''

        e = Embed.from_data(eval(content))
        await ctx.send(embed=e)

    @command()
    async def kill(self, ctx: Context):
        '''
        Turns off the bot and anything related to it
        '''

        async with self.bot.database() as db:
            for i in self.bot._die.values():
                await db.store_die(i)
        await ctx.send('Turning off now.')
        await self.bot.logout()

    @command()
    async def ev(self, ctx: Context, *, content: str):
        '''
        Runs some text through Python's eval function
        '''

        try:
            ans = eval(content)
        except Exception as e:
            await ctx.send('```py\n' + format_exc() + '```')
            return
        if iscoroutine(ans):
            ans = await ans
        await ctx.send('```py\n' + str(ans) + '```')

    @command(aliases=['uld'])
    async def unload(self, ctx: Context, *cog_name: str):
        '''
        Unloads a cog from the bot
        '''

        self.bot.unload_extension('cogs.' +
                                  '_'.join([i.lower() for i in cog_name]))
        await ctx.send('Cog unloaded.')

    @command()
    async def load(self, ctx: Context, *cog_name: str):
        '''
        Unloads a cog from the bot
        '''

        self.bot.load_extension('cogs.' +
                                '_'.join([i.lower() for i in cog_name]))
        await ctx.send('Cog loaded.')

    @command(aliases=['rld'])
    async def reload(self, ctx: Context, *, cog_name: str):
        '''
        Unloads a cog from the bot
        '''

        self.bot.unload_extension('cogs.' + cog_name.lower())
        try:
            self.bot.load_extension('cogs.' + cog_name.lower())
        except Exception as e:
            await ctx.send('```py\n' + format_exc() + '```')
            return
        await ctx.send('Cog reloaded.')

    @command()
    async def leaveguild(self, ctx: Context, guild_id: int):
        '''
        Leaves a given guild
        '''

        guild = self.bot.get_guild(guild_id)
        await guild.leave()
        await ctx.send('Done.')
Ejemplo n.º 44
0
async def get_feed(session: aiohttp.ClientSession, url: str) -> str:
    async with async_timeout.timeout(10):
        async with session.get(url) as response:
            raw_data = await response.text()
            return feedparser.parse(raw_data)
Ejemplo n.º 45
0
 async def get_response(self, url: URL, session: aiohttp.ClientSession) -> str:
     async with session.get(url, timeout=self.timeout) as response:
         if response.status != 200:
             return ''
         html = await response.text()  # response.read() bytes
         return html
Ejemplo n.º 46
0
async def notify_mattermost_header(mattermost_config: Dict,
                                   app_session: ClientSession, state: State,
                                   status_message: str):
    if mattermost_config["enabled"]:
        status_emoji = ":+1: "
        if state is State.FAILED:
            status_emoji = ":x:"
        elif state is State.PAUSED:
            status_emoji = ":x:"

        header_unique_name = mattermost_config["header_unique_name"]
        date = datetime.datetime.utcnow().isoformat(timespec='seconds')
        message = f"{header_unique_name} {status_emoji} {status_message} - {date} |"

        personal_token = mattermost_config["personal_token"]
        channel_id = mattermost_config["channel_id"]
        headers = {"Authorization": f"Bearer {personal_token}"}

        # get the current header to update it
        url = URL(mattermost_config["url"]).with_path(
            f"api/v4/channels/{channel_id}")
        current_header = ""
        async with app_session.get(url, headers=headers) as resp:
            log.debug("requested channel description: received with code %s",
                      resp.status)
            if resp.status == 404:
                log.error("could not find route in %s", url)
                raise ConfigurationError(
                    "Could not find channel within Mattermost app in {}:\n {}".
                    format(url, await resp.text()))
            if not resp.status == 200:
                log.error("Unknown error")
                raise AutoDeployAgentException(
                    "Unknown error while accessing Mattermost app in {}:\n {}".
                    format(url, await resp.text()))
            data = await resp.json()
            log.debug("received data: %s", data)
            current_header = data["header"]

        new_header = message
        start_index = current_header.find(header_unique_name)
        if start_index != -1:
            # update the message instead
            lastindex = current_header.find("|", start_index)
            new_header = "{}{}{}".format(current_header[0:start_index],
                                         message,
                                         current_header[lastindex + 1:])

        url = URL(mattermost_config["url"]).with_path(
            f"api/v4/channels/{channel_id}/patch")
        async with app_session.put(url,
                                   headers=headers,
                                   data=json.dumps({"header":
                                                    new_header})) as resp:
            log.debug(
                "requested patch channel description: response received with code %s",
                resp.status)
            if resp.status == 200:
                data = await resp.json()
                return data
            if resp.status == 404:
                log.error("could not find route in %s", url)
                raise ConfigurationError(
                    "Could not find channel within Mattermost app in {}:\n {}".
                    format(url, await resp.text()))
            log.error("Unknown error")
            raise AutoDeployAgentException(
                "Unknown error while accessing Mattermost app in {}:\n {}".
                format(url, await resp.text()))
Ejemplo n.º 47
0
class YoutubeProvider(Provider):
    name = 'youtube'
    can_search = True

    endpoint = 'https://www.googleapis.com/youtube/v3/search'
    default_params = {
        'part': 'id,snippet',
        'maxResults': 15,
        'type': 'video',
    }

    def __init__(self, *, api_key: str = None):
        self.loop = asyncio.get_event_loop()
        self.session = ClientSession()
        self.api_key = api_key

        if not self.api_key:
            log.critical('API KEY is missing!')
            raise ProviderNotReady()

        self.default_params = {**self.default_params, 'key': self.api_key}

    async def search(self, keyword: str) -> Sequence[EntryOverview]:
        ret = []
        res = await self.youtube_api(params={'q': keyword})

        # should we validate with lib?
        if 'items' in res:
            for item in res['items']:
                try:
                    video_id = item['id']['videoId']
                    title = item['snippet']['title']
                    thumbnail = item['snippet']['thumbnails']['high']['url']
                    thumbnail_small = item['snippet']['thumbnails']['default'][
                        'url']
                except:
                    log.error('missing key: ', exc_info=True)

                ret.append(
                    EntryOverview(
                        self.name, title,
                        f'https://www.youtube.com/watch?v={video_id}',
                        thumbnail, thumbnail_small))

        return ret

    async def resolve_playable(self, uri, cache_dir):
        # search-only provider
        return

    async def resolve(self, uri: str) -> Optional[EntryOverview]:
        # search-only provider
        return

    async def youtube_api(self, params={}) -> Optional[dict]:
        ret = None
        try:
            async with self.session.get(self.endpoint,
                                        params={
                                            **self.default_params,
                                            **params
                                        }) as res:
                ret = await res.json()
                log.debug(ret)
        except:
            log.error(f'Failed to communicate with YouTube API ({params}): ',
                      exc_info=True)

        return ret
Ejemplo n.º 48
0
async def draw_profile(user: Member, session: ClientSession) -> Image:
    name_fnt = ImageFont.truetype(font_heavy_file, 30)
    name_u_fnt = ImageFont.truetype(font_unicode_file, 30)
    title_fnt = ImageFont.truetype(font_heavy_file, 22)
    title_u_fnt = ImageFont.truetype(font_unicode_file, 23)
    label_fnt = ImageFont.truetype(font_bold_file, 18)
    exp_fnt = ImageFont.truetype(font_bold_file, 13)
    large_fnt = ImageFont.truetype(font_thin_file, 33)
    rep_fnt = ImageFont.truetype(font_heavy_file, 26)
    rep_u_fnt = ImageFont.truetype(font_unicode_file, 30)
    text_fnt = ImageFont.truetype(font_file, 14)
    text_u_fnt = ImageFont.truetype(font_unicode_file, 14)
    symbol_u_fnt = ImageFont.truetype(font_unicode_file, 15)

    def _write_unicode(text, init_x, y, font, unicode_font, fill):
        write_pos = init_x

        for char in text:
            if char.isalnum() or char in string.punctuation or char in string.whitespace:
                draw.text((write_pos, y), char, font=font, fill=fill)
                write_pos += font.getsize(char)[0]
            else:
                draw.text((write_pos, y), u"{}".format(char), font=unicode_font, fill=fill)
                write_pos += unicode_font.getsize(char)[0]

    user_info = db.user(user)

    # get urls
    bg_url = await user_info.profile_background()
    profile_url = user.avatar_url

    async with session.get(bg_url) as r:
        bg_image = Image.open(BytesIO(await r.content.read())).convert("RGBA")
    async with session.get(profile_url) as r:
        profile_image = Image.open(BytesIO(await r.content.read())).convert("RGBA")

    # COLORS
    white_color = (240, 240, 240, 255)
    rep_fill = await user_info.rep_color()
    badge_fill = await user_info.badge_col_color()
    info_fill = await user_info.profile_info_color()
    info_fill_tx = (*info_fill[:3], 150)
    exp_fill = await user_info.profile_exp_color()

    title = await user_info.title()
    info = await user_info.info()
    total_exp = await user_info.total_exp()
    badges = await user_info.badges()
    rep = await user_info.rep()

    if badge_fill == (128, 151, 165, 230):
        level_fill = white_color
    else:
        level_fill = _contrast(exp_fill, rep_fill, badge_fill)

    # set canvas
    bg_color = (255, 255, 255, 0)
    result = Image.new("RGBA", (340, 390), bg_color)
    process = Image.new("RGBA", (340, 390), bg_color)

    # draw
    draw = ImageDraw.Draw(process)

    # puts in background
    bg_image = bg_image.resize((340, 340), Image.ANTIALIAS)
    bg_image = bg_image.crop((0, 0, 340, 305))
    result.paste(bg_image, (0, 0))

    # draw filter
    draw.rectangle([(0, 0), (340, 340)], fill=(0, 0, 0, 10))

    draw.rectangle([(0, 134), (340, 325)], fill=info_fill_tx)  # general content
    # draw profile circle
    multiplier = 8
    lvl_circle_dia = 116
    circle_left = 14
    circle_top = 48
    raw_length = lvl_circle_dia * multiplier

    # create mask
    mask = Image.new("L", (raw_length, raw_length), 0)
    draw_thumb = ImageDraw.Draw(mask)
    draw_thumb.ellipse((0, 0) + (raw_length, raw_length), fill=255, outline=0)

    # border
    lvl_circle = Image.new("RGBA", (raw_length, raw_length))
    draw_lvl_circle = ImageDraw.Draw(lvl_circle)
    draw_lvl_circle.ellipse(
        [0, 0, raw_length, raw_length], fill=(255, 255, 255, 255), outline=(255, 255, 255, 250)
    )
    # put border
    lvl_circle = lvl_circle.resize((lvl_circle_dia, lvl_circle_dia), Image.ANTIALIAS)
    lvl_bar_mask = mask.resize((lvl_circle_dia, lvl_circle_dia), Image.ANTIALIAS)
    process.paste(lvl_circle, (circle_left, circle_top), lvl_bar_mask)

    # put in profile picture
    total_gap = 6
    border = int(total_gap / 2)
    profile_size = lvl_circle_dia - total_gap
    mask = mask.resize((profile_size, profile_size), Image.ANTIALIAS)
    profile_image = profile_image.resize((profile_size, profile_size), Image.ANTIALIAS)
    process.paste(profile_image, (circle_left + border, circle_top + border), mask)

    # write label text
    white_color = (240, 240, 240, 255)
    light_color = (160, 160, 160, 255)
    dark_color = (35, 35, 35, 255)

    head_align = 140
    # determine info text color
    info_text_color = _contrast(info_fill, white_color, dark_color)
    _write_unicode(
        _truncate_text(user.name, 22).upper(),
        head_align,
        142,
        name_fnt,
        name_u_fnt,
        info_text_color,
    )  # NAME
    _write_unicode(
        title.upper(), head_align, 170, title_fnt, title_u_fnt, info_text_color
    )

    # draw divider
    draw.rectangle([(0, 323), (340, 324)], fill=(0, 0, 0, 255))  # box
    # draw text box
    draw.rectangle(
        [(0, 324), (340, 390)], fill=(info_fill[0], info_fill[1], info_fill[2], 255)
    )  # box

    _write_unicode("❤", 257, 9, rep_fnt, rep_u_fnt, info_text_color)
    draw.text(
        (_center(278, 340, str(rep), rep_fnt), 10),
        str(rep),
        font=rep_fnt,
        fill=info_text_color,
    )  # Exp Text

    label_align = 362  # vertical
    draw.text(
        (_center(0, 140, "    RANK", label_fnt), label_align),
        "    RANK",
        font=label_fnt,
        fill=info_text_color,
    )  # Rank
    draw.text(
        (_center(0, 340, "    LEVEL", label_fnt), label_align),
        "    LEVEL",
        font=label_fnt,
        fill=info_text_color,
    )  # Exp
    draw.text(
        (_center(200, 340, "BALANCE", label_fnt), label_align),
        "BALANCE",
        font=label_fnt,
        fill=info_text_color,
    )  # Credits

    if "linux" in platform.system().lower():
        global_symbol = u"\U0001F30E "
        _write_unicode(
            global_symbol, 36, label_align + 5, label_fnt, symbol_u_fnt, info_text_color
        )  # Symbol
        _write_unicode(
            global_symbol, 134, label_align + 5, label_fnt, symbol_u_fnt, info_text_color
        )  # Symbol

    # userinfo
    global_rank = f"#{await _find_global_rank(user)}"
    global_level = str(_find_level(total_exp))
    draw.text(
        (_center(0, 140, global_rank, large_fnt), label_align - 27),
        global_rank,
        font=large_fnt,
        fill=info_text_color,
    )  # Rank
    draw.text(
        (_center(0, 340, global_level, large_fnt), label_align - 27),
        global_level,
        font=large_fnt,
        fill=info_text_color,
    )  # Exp
    # draw level bar
    exp_font_color = _contrast(exp_fill, light_color, dark_color)
    exp_frac = int(total_exp - _level_exp(int(global_level)))
    exp_total = _required_exp(int(global_level) + 1)
    bar_length = int(exp_frac / exp_total * 340)
    draw.rectangle(
        [(0, 305), (340, 323)], fill=(level_fill[0], level_fill[1], level_fill[2], 245)
    )  # level box
    draw.rectangle(
        [(0, 305), (bar_length, 323)], fill=(exp_fill[0], exp_fill[1], exp_fill[2], 255)
    )  # box
    exp_text = "{}/{}".format(exp_frac, exp_total)  # Exp
    draw.text(
        (_center(0, 340, exp_text, exp_fnt), 305),
        exp_text,
        font=exp_fnt,
        fill=exp_font_color,
    )  # Exp Text

    credit_txt = f"${await bank.get_balance(user)}"
    draw.text(
        (_center(200, 340, credit_txt, large_fnt), label_align - 27),
        _truncate_text(credit_txt, 18),
        font=large_fnt,
        fill=info_text_color,
    )  # Credits

    if title == "":
        offset = 170
    else:
        offset = 195
    margin = 140
    txt_color = _contrast(info_fill, white_color, dark_color)
    for line in textwrap.wrap(info, width=32):
        _write_unicode(line, margin, offset, text_fnt, text_u_fnt, txt_color)
        offset += text_fnt.getsize(line)[1] + 2

    # sort badges
    priority_badges = []

    for badgename in badges.keys():
        badge = badges[badgename]
        priority_num = badge["priority_num"]
        if priority_num != 0 and priority_num != -1:
            priority_badges.append((badge, priority_num))
    sorted_badges = sorted(priority_badges, key=operator.itemgetter(1), reverse=True)

    # TODO: simplify this. it shouldn't be this complicated... sacrifices conciseness for customizability
    if (await db.badge_type()) == "circles":
        # circles require antialiasing
        vert_pos = 172
        right_shift = 0
        left = 9 + right_shift
        size = 38
        total_gap = 4  # /2
        hor_gap = 6
        vert_gap = 6
        border_width = int(total_gap / 2)
        multiplier = 6  # for antialiasing
        raw_length = size * multiplier
        mult = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)]
        for num in range(9):
            coord = (
                left + int(mult[num][0]) * int(hor_gap + size),
                vert_pos + int(mult[num][1]) * int(vert_gap + size),
            )
            if num < len(sorted_badges[:9]):
                pair = sorted_badges[num]
                badge = pair[0]
                bg_color = badge["bg_img"]
                border_color = badge["border_color"]
                # draw mask circle
                mask = Image.new("L", (raw_length, raw_length), 0)
                draw_thumb = ImageDraw.Draw(mask)
                draw_thumb.ellipse((0, 0) + (raw_length, raw_length), fill=255, outline=0)

                # determine image or color for badge bg
                if await self._valid_image_url(bg_color):
                    # get image
                    async with session.get(bg_color) as r:
                        badge_image = Image.open(BytesIO(await r.content.read())).convert("RGBA")
                    badge_image = badge_image.resize((raw_length, raw_length), Image.ANTIALIAS)

                    # structured like this because if border = 0, still leaves outline.
                    if border_color:
                        square = Image.new("RGBA", (raw_length, raw_length), border_color)
                        # put border on ellipse/circle
                        output = ImageOps.fit(
                            square, (raw_length, raw_length), centering=(0.5, 0.5)
                        )
                        output = output.resize((size, size), Image.ANTIALIAS)
                        outer_mask = mask.resize((size, size), Image.ANTIALIAS)
                        process.paste(output, coord, outer_mask)

                        # put on ellipse/circle
                        output = ImageOps.fit(
                            badge_image, (raw_length, raw_length), centering=(0.5, 0.5)
                        )
                        output = output.resize(
                            (size - total_gap, size - total_gap), Image.ANTIALIAS
                        )
                        inner_mask = mask.resize(
                            (size - total_gap, size - total_gap), Image.ANTIALIAS
                        )
                        process.paste(
                            output,
                            (coord[0] + border_width, coord[1] + border_width),
                            inner_mask,
                        )
                    else:
                        # put on ellipse/circle
                        output = ImageOps.fit(
                            badge_image, (raw_length, raw_length), centering=(0.5, 0.5)
                        )
                        output = output.resize((size, size), Image.ANTIALIAS)
                        outer_mask = mask.resize((size, size), Image.ANTIALIAS)
                        process.paste(output, coord, outer_mask)
            else:
                plus_fill = exp_fill
                # put on ellipse/circle
                plus_square = Image.new("RGBA", (raw_length, raw_length))
                plus_draw = ImageDraw.Draw(plus_square)
                plus_draw.rectangle(
                    [(0, 0), (raw_length, raw_length)],
                    fill=(info_fill[0], info_fill[1], info_fill[2], 245),
                )
                # draw plus signs
                margin = 60
                thickness = 40
                v_left = int(raw_length / 2 - thickness / 2)
                v_right = v_left + thickness
                v_top = margin
                v_bottom = raw_length - margin
                plus_draw.rectangle(
                    [(v_left, v_top), (v_right, v_bottom)],
                    fill=(plus_fill[0], plus_fill[1], plus_fill[2], 245),
                )
                h_left = margin
                h_right = raw_length - margin
                h_top = int(raw_length / 2 - thickness / 2)
                h_bottom = h_top + thickness
                plus_draw.rectangle(
                    [(h_left, h_top), (h_right, h_bottom)],
                    fill=(plus_fill[0], plus_fill[1], plus_fill[2], 245),
                )
                # put border on ellipse/circle
                output = ImageOps.fit(
                    plus_square, (raw_length, raw_length), centering=(0.5, 0.5)
                )
                output = output.resize((size, size), Image.ANTIALIAS)
                outer_mask = mask.resize((size, size), Image.ANTIALIAS)
                process.paste(output, coord, outer_mask)

    result = Image.alpha_composite(result, process)
    result = _add_corners(result, 25)
    return result
Ejemplo n.º 49
0
class EdgeOSWebAPI:
    def __init__(self, hass, config_manager: ConfigManager, disconnection_handler=None):
        self._config_manager = config_manager
        self._last_update = datetime.now()
        self._session: Optional[ClientSession] = None

        self._last_valid = EMPTY_LAST_VALID
        self._hass = hass
        self._is_connected = False
        self._cookies = {}

        self._product = PRODUCT_NAME
        self._disconnection_handler = disconnection_handler

        self._disconnections = 0

    async def initialize(self):
        cookie_jar = CookieJar(unsafe=True)

        if self._hass is None:
            if self._session is not None:
                await self._session.close()

            self._session = ClientSession(cookie_jar=cookie_jar)
        else:
            self._session = async_create_clientsession(
                hass=self._hass, cookies=self._cookies, cookie_jar=cookie_jar,
            )

    @property
    def is_initialized(self):
        return self._session is not None and not self._session.closed

    @property
    def is_connected(self):
        return self._is_connected

    @property
    def product(self):
        return self._product

    @property
    def session_id(self):
        session_id = self.get_cookie_data(COOKIE_PHPSESSID)

        return session_id

    @property
    def beaker_session_id(self):
        beaker_session_id = self.get_cookie_data(COOKIE_BEAKER_SESSION_ID)

        return beaker_session_id

    @property
    def cookies_data(self):
        return self._cookies

    def get_cookie_data(self, cookie_key):
        cookie_data = None

        if self._cookies is not None:
            cookie_data = self._cookies.get(cookie_key)

        return cookie_data

    async def login(self, throw_exception=False):
        logged_in = False

        try:
            username = self._config_manager.data.username
            password = self._config_manager.data.password_clear_text

            credentials = {CONF_USERNAME: username, CONF_PASSWORD: password}

            url = self._config_manager.data.url.get_url()

            async with self._session.post(url, data=credentials) as response:
                all_cookies = self._session.cookie_jar.filter_cookies(response.url)

                for key, cookie in all_cookies.items():
                    self._cookies[cookie.key] = cookie.value

                status_code = response.status

                response.raise_for_status()

                logged_in = (
                    self.beaker_session_id is not None
                    and self.beaker_session_id == self.session_id
                )

                if logged_in:
                    html = await response.text()
                    html_lines = html.splitlines()
                    for line in html_lines:
                        if "EDGE.DeviceModel" in line:
                            line_parts = line.split(" = ")
                            value = line_parts[len(line_parts) - 1]
                            self._product = value.replace("'", "")
                else:
                    _LOGGER.error(f"Failed to login, Invalid credentials")

                    if self.beaker_session_id is None and self.session_id is not None:
                        status_code = 500
                    else:
                        status_code = 403

        except Exception as ex:
            exc_type, exc_obj, tb = sys.exc_info()
            line_number = tb.tb_lineno

            _LOGGER.error(f"Failed to login, Error: {ex}, Line: {line_number}")

            status_code = 404

        if throw_exception and status_code is not None and status_code >= 400:
            raise LoginException(status_code)

        return logged_in

    async def async_get(self, url):
        result = None

        try:
            async with self._session.get(url) as response:
                _LOGGER.debug(f"Status of {url}: {response.status}")

                self._is_connected = response.status < 400

                if response.status == 403:
                    if self._disconnections + 1 < MAXIMUM_RECONNECT:
                        self._disconnections = self._disconnections + 1

                        if self._disconnection_handler is not None:
                            await self._disconnection_handler()
                    else:
                        _LOGGER.error(
                            f"Failed to make authenticated request to {url} {self._disconnections} times"
                        )
                else:
                    response.raise_for_status()

                    result = await response.json()

                    self._last_update = datetime.now()

        except Exception as ex:
            self._is_connected = False

            exc_type, exc_obj, tb = sys.exc_info()
            line_number = tb.tb_lineno

            _LOGGER.error(f"Failed to connect {url}, Error: {ex}, Line: {line_number}")

        return result

    @property
    def last_update(self):
        result = self._last_update

        return result

    async def heartbeat(self, max_age=HEARTBEAT_MAX_AGE):
        try:
            if self.is_initialized:
                ts = datetime.now()
                current_invocation = datetime.now() - self._last_valid
                if current_invocation > timedelta(seconds=max_age):
                    current_ts = str(int(ts.timestamp()))

                    heartbeat_req_url = self.get_edgeos_api_endpoint(
                        EDGEOS_API_HEARTBREAT
                    )
                    heartbeat_req_full_url = API_URL_HEARTBEAT_TEMPLATE.format(
                        heartbeat_req_url, current_ts
                    )

                    response = await self.async_get(heartbeat_req_full_url)

                    _LOGGER.debug(f"Heartbeat response: {response}")

                    self._last_valid = ts
            else:
                _LOGGER.warning(f"Heartbeat not ran due to closed session")
        except Exception as ex:
            exc_type, exc_obj, tb = sys.exc_info()
            line_number = tb.tb_lineno

            _LOGGER.error(
                f"Failed to perform heartbeat, Error: {ex}, Line: {line_number}"
            )

    async def get_devices_data(self):
        result = None

        try:
            if self.is_initialized:
                get_req_url = self.get_edgeos_api_endpoint(EDGEOS_API_GET)

                result_json = await self.async_get(get_req_url)

                if result_json is not None and RESPONSE_SUCCESS_KEY in result_json:
                    success_key = str(result_json.get(RESPONSE_SUCCESS_KEY, "")).lower()

                    if success_key == TRUE_STR:
                        if EDGEOS_API_GET.upper() in result_json:
                            result = result_json.get(EDGEOS_API_GET.upper(), {})
                    else:
                        error_message = result_json[RESPONSE_ERROR_KEY]
                        _LOGGER.error(f"Failed, Error: {error_message}")
                else:
                    _LOGGER.error("Invalid response, not contain success status")
            else:
                _LOGGER.warning(f"Get devices data not ran due to closed session")
        except Exception as ex:
            exc_type, exc_obj, tb = sys.exc_info()
            line_number = tb.tb_lineno

            _LOGGER.error(
                f"Failed to get devices data, Error: {ex}, Line: {line_number}"
            )

        return result

    async def get_general_data(self, item):
        result = None

        try:
            if self.is_initialized:
                clean_item = item.replace(STRING_DASH, STRING_UNDERSCORE)
                data_req_url = self.get_edgeos_api_endpoint(EDGEOS_API_DATA)
                data_req_full_url = API_URL_DATA_TEMPLATE.format(
                    data_req_url, clean_item
                )

                data = await self.async_get(data_req_full_url)

                if data is not None and RESPONSE_SUCCESS_KEY in data:
                    if str(data.get(RESPONSE_SUCCESS_KEY)) == RESPONSE_FAILURE_CODE:
                        error = data.get(RESPONSE_ERROR_KEY, EMPTY_STRING)

                        _LOGGER.error(f"Failed to load {item}, Reason: {error}")
                        result = None
                    else:
                        result = data.get(RESPONSE_OUTPUT)
            else:
                _LOGGER.warning(f"Get data of {item} not ran due to closed session")

        except Exception as ex:
            exc_type, exc_obj, tb = sys.exc_info()
            line_number = tb.tb_lineno

            _LOGGER.error(f"Failed to load {item}, Error: {ex}, Line: {line_number}")
            result = None

        return result

    def get_edgeos_api_endpoint(self, controller):
        url = EDGEOS_API_URL.format(self._config_manager.data.url, controller)

        return url
async def get_response(session: aiohttp.ClientSession, url: str):
    async with session.get(url=url, headers=headers) as response:
        return await response.text()
Ejemplo n.º 51
0
Archivo: nhl.py Proyecto: aaront/puckdb
async def _get(url: str, session: aiohttp.ClientSession):
    async with session.get(url, headers=_HEADERS) as response:
        assert response.status == 200
        return await response.json(loads=ujson.loads)
async def proer(queue: asyncio.Queue, session: aiohttp.ClientSession):
    global done, wait_a_little
    for page in infos:
        for mod in page:
            # 寻找可用版本:
            FileInfo = None
            deep = False

            if mod['slug'] in config.mod_blacklist_slug:
                print(f"模组 [{mod['name']}] 被列入黑名单, 已跳过")
                continue
            """
            date_cache = Path(f"./cache/{mod['id']}.json")
            if date_cache.exists():
                # 一次检查.
                date = maya.parse(orjson.loads(date_cache.read_text("utf-8"))['date'])
                if date:
                    timediff = maya.now() - date
                    if datetime.timedelta(**config.update_setting) > timediff:
                        print(f"模组 [{mod['name']}] 未到更新时间({date.add(**config.update_setting)}), 已跳过")
                        continue
            """
            update_date = date.get(str(mod['id']))
            if update_date:
                # 一次检查.
                date_ = maya.parse(update_date)
                if date_:
                    timediff = maya.now() - date_
                    if datetime.timedelta(**config.update_setting) > timediff:
                        print(
                            f"模组 [{mod['name']}] 未到更新时间({date_.add(**config.update_setting)}), 已跳过"
                        )
                        continue

            print(f"开始找寻模组 [{mod['name']}] 可用于版本 [{version}] 的jar文件")
            for i in mod['latestFiles']:
                if version in i['gameVersion']:
                    print(f"已找到模组 [{mod['name']}] 可用于版本 [{version}] 的jar文件")
                    FileInfo = i
                    break
            else:
                print(
                    f"未找到模组 [{mod['name']}] 可用于版本 [{version}] 的jar文件, 开始请求远端数据库以寻找可用的版本"
                )
                deep = True

            if deep:
                for versionInfo in mod['gameVersionLatestFiles']:
                    if versionInfo['gameVersion'] == version:
                        print(
                            f"已找到远端数据库中模组 [{mod['name']}] 可用于版本 [{version}] 的jar文件, 开始深层数据取出"
                        )
                        info_url = f'https://addons-ecs.forgesvc.net/api/v2/addon/{mod["id"]}/file/{versionInfo["projectFileId"]}'
                        async with session.get(info_url) as response:
                            FileInfo = await response.json()
                else:
                    print(
                        f"未找到模组 [{mod['name']}] 可用于版本 [{version}] 的jar文件, 跳过.")
                    continue

            if not FileInfo:
                print(f"warn: {mod['name']} 没有版本 {version} 可用的文件, 跳过")
                continue

            # 存储更新日期
            ## 可能会找不到文件, touch it
            """
            if not date_cache.exists():
                date_cache.touch()

            date_cache.write_text(orjson.dumps({
                "date": maya.now().rfc2822()
            }).decode('utf-8'), encoding="utf-8")
            """
            date[str(mod['id'])] = maya.now().rfc2822()

            url = FileInfo["downloadUrl"]
            name = FileInfo["fileName"]
            length = FileInfo["fileLength"]
            if wait_a_little:
                await asyncio.sleep(3)
                wait_a_little = False

            await queue.put({"url": url, "name": name, "file-length": length})
    done = True
Ejemplo n.º 53
0
async def fetch(session: aiohttp.ClientSession, url: str) -> Response:
    async with session.get(url) as response:
        print(f"request {url}")
        return response