diff --git a/example.py b/example.py index 3381ffc..33cfd81 100644 --- a/example.py +++ b/example.py @@ -18,12 +18,13 @@ import asyncio -from yatgl import Client, NationGroup, Template +from yatgl import Client, NationGroup, Template, UserAgent async def main(): # Lazy initialization with singleton - Client(client_key='client key here', user_agent='nation here') + user_agent = UserAgent('nation here', 'yatgl example script', '0.0.1') + Client(client_key='client key here', user_agent=user_agent) # If you want, you can change the delay, like so: # Client(delay=200) diff --git a/setup.py b/setup.py index 5f67c08..42319b5 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup(name='yatgl', - version='1.0.1', + version='1.0.2', description='An asynchronous NationStates Telegram API library.', long_description=long_description, long_description_content_type='text/markdown', diff --git a/yatgl/__init__.py b/yatgl/__init__.py index 4f319f5..d320e84 100644 --- a/yatgl/__init__.py +++ b/yatgl/__init__.py @@ -16,4 +16,4 @@ along with this program. If not, see . """ -from .client import Client, NationGroup, Template +from .client import Client, NationGroup, Template, UserAgent diff --git a/yatgl/client.py b/yatgl/client.py index fc4aa8c..34ba6a4 100644 --- a/yatgl/client.py +++ b/yatgl/client.py @@ -27,7 +27,7 @@ from bs4 import BeautifulSoup API_URL = 'https://www.nationstates.net/cgi-bin/api.cgi' -VERSION = '1.0.1' +VERSION = '1.0.2' logger = getLogger(__name__) @@ -43,6 +43,12 @@ class TelegramRequest(NamedTuple): recipient: str +class UserAgent(NamedTuple): + nation_name: str + script_name: str + script_version: str + + class NationGroup(Enum): NEW_WA_MEMBERS = 0 ALL_WA_MEMBERS = 1 @@ -84,7 +90,7 @@ class Client(metaclass=_ClientMeta): >>>asyncio.run(Client().start()) """ client_key: str = None - user_agent: str = None + user_agent: UserAgent = None delay: int = 185 sent = set() queue: deque[TelegramRequest] = deque() @@ -106,7 +112,7 @@ def __init__(self, **kwargs): if 'delay' in kwargs: delay = kwargs.pop('delay') if delay < 30: - raise ValueError('Delay can\'t be less than 180.') + raise ValueError('Delay can\'t be less than 30.') self.delay = delay def queue_tg(self, template: Template, recipient: str): @@ -116,6 +122,7 @@ def queue_tg(self, template: Template, recipient: str): :param recipient: The nation you want to recieve the telegram. """ self.queue.appendleft(TelegramRequest(template, recipient)) + logger.debug(f'queued {template.tgid} to {recipient}') async def start(self): """ @@ -158,7 +165,12 @@ async def mass_telegram(self, template: Template, group: NationGroup, region: It :param region: A list of regions. """ if not self._session or self._session.closed: - self._session = aiohttp.ClientSession() + headers = { + 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, ' + f'used by nation={self.user_agent.nation_name} in script={self.user_agent.script_name} ' + f'v{self.user_agent.script_version}' + } + self._session = aiohttp.ClientSession(headers=headers) task = asyncio.create_task(self._mass_queue(template, group, region)) self._queueing_tasks.append(task) await asyncio.gather(self.start(), task) @@ -222,11 +234,8 @@ async def _get_region_members(self, region: str) -> list[str]: 'q': 'nations', 'region': region } - headers = { - 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, used by nation={self.user_agent}' - } - async with self._session.post(API_URL, data=data, headers=headers) as resp: + async with self._session.post(API_URL, data=data) as resp: parsed = BeautifulSoup(await resp.text(), 'xml') return parsed.REGION.NATIONS.string.split(':') @@ -235,11 +244,8 @@ async def _get_wa_members(self) -> list[str]: 'q': 'members', 'wa': '1' } - headers = { - 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, used by nation={self.user_agent}' - } - async with self._session.post(API_URL, data=data, headers=headers) as resp: + async with self._session.post(API_URL, data=data) as resp: parsed = BeautifulSoup(await resp.text(), 'xml') return parsed.WA.MEMBERS.string.split(',') @@ -248,11 +254,8 @@ async def _get_wa_delegates(self) -> list[str]: 'q': 'delegates', 'wa': '1' } - headers = { - 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, used by nation={self.user_agent}' - } - async with self._session.post(API_URL, data=data, headers=headers) as resp: + async with self._session.post(API_URL, data=data) as resp: parsed = BeautifulSoup(await resp.text(), 'xml') return parsed.WA.DELEGATES.string.split(',') @@ -260,11 +263,8 @@ async def _get_new_founds(self) -> list[str]: data = { 'q': 'newnations' } - headers = { - 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, used by nation={self.user_agent}' - } - async with self._session.post(API_URL, data=data, headers=headers) as resp: + async with self._session.post(API_URL, data=data) as resp: parsed = BeautifulSoup(await resp.text(), 'xml') return parsed.WORLD.NEWNATIONS.string.split(',') @@ -285,14 +285,19 @@ async def _send_tg(self, telegram: TelegramRequest): 'key': telegram.template.secret_key, 'to': recipient } - headers = { - 'User-Agent': f'yatgl v{VERSION} Developed by nation=Notanam, used by nation={self.user_agent}' - } - async with self._session.post(API_URL, data=data, headers=headers) as resp: - if 'queued' in await resp.text(): - self.sent.add(recipient) - logger.info(f'Sent {telegram.template.tgid} to {telegram.recipient}') - else: - logger.error(f'Telegram errored sending {telegram.template.tgid} to {telegram.recipient}:' - f'{await resp.text()}') + while True: + async with self._session.post(API_URL, data=data) as resp: + if resp.status == 429: + retry_after = int(resp.headers['Retry-After']) + logger.warning(f'Got too many requests error from NationStates sending {telegram.template.tgid} to ' + f'{recipient}! Retrying in {retry_after}s') + await asyncio.sleep(retry_after) + elif 'queued' in await resp.text(): + self.sent.add(recipient) + logger.info(f'Sent {telegram.template.tgid} to {telegram.recipient}') + break + else: + logger.error(f'Telegram errored sending {telegram.template.tgid} to {telegram.recipient}:' + f'{await resp.text()}') + break