diff --git a/README.rst b/README.rst index 17e0ded..2f0e2b2 100644 --- a/README.rst +++ b/README.rst @@ -182,6 +182,10 @@ Supports both variants like API object Long Poll --------- +**UserLongPoll** - for User Long Poll API. See https://vk.com/dev/using_longpoll + +**BotsLongPoll** - for Bots Long Poll API. See https://vk.com/dev/bots_longpoll + Use exist API object .. code-block:: python diff --git a/aiovk/__init__.py b/aiovk/__init__.py index d3a1591..8000647 100644 --- a/aiovk/__init__.py +++ b/aiovk/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.1.1' +__version__ = '2.2.0' from aiovk.sessions import ImplicitSession, TokenSession, AuthorizationCodeSession from aiovk.api import API diff --git a/aiovk/longpoll.py b/aiovk/longpoll.py index 912d1a5..df55a17 100644 --- a/aiovk/longpoll.py +++ b/aiovk/longpoll.py @@ -1,18 +1,32 @@ import json +from abc import ABC, abstractmethod from aiovk import API +from aiovk.api import LazyAPI from aiovk.exceptions import VkLongPollError -class LongPoll: - def __init__(self, session_or_api, mode, wait=25, version=1, timeout=None): - if type(session_or_api) == API: +class BaseLongPoll(ABC): + """Interface for all types of Longpoll API""" + def __init__(self, session_or_api, mode: int or list, wait: int=25, version: int=2, timeout: int=None): + """ + :param session_or_api: session object or data for creating a new session + :type session_or_api: BaseSession or API or LazyAPI + :param mode: additional answer options + :param wait: waiting period + :param version: protocol version + :param timeout: timeout for *.getLongPollServer request in current session + """ + if isinstance(session_or_api, (API, LazyAPI)): self.api = session_or_api else: self.api = API(session_or_api) + self.timeout = timeout or self.api._session.timeout + if type(mode) == list: mode = sum(mode) + self.base_params = { 'version': version, 'wait': wait, @@ -24,48 +38,93 @@ def __init__(self, session_or_api, mode, wait=25, version=1, timeout=None): self.key = None self.base_url = None - async def _get_long_poll_server(self, need_pts=False): - response = await self.api('messages.getLongPollServer', need_pts=int(need_pts), timeout=self.timeout) - self.pts = response.get('pts') - self.ts = response['ts'] - self.key = response['key'] - self.base_url = 'https://{}'.format(response['server']) + @abstractmethod + async def _get_long_poll_server(self, need_pts: bool=False) -> None: + """Send *.getLongPollServer request and update internal data - async def wait(self, need_pts=False): + :param need_pts: need return the pts field + """ + + async def wait(self, need_pts=False) -> dict: + """Send long poll request + + :param need_pts: need return the pts field + """ if not self.base_url: await self._get_long_poll_server(need_pts) + params = { 'ts': self.ts, 'key': self.key, } params.update(self.base_params) - # invalid mymetype from server - code, response = await self.api._session.driver.get_text(self.base_url, params, timeout=2 * self.base_params['wait']) + # invalid mimetype from server + code, response = await self.api._session.driver.get_text( + self.base_url, params, + timeout=2 * self.base_params['wait'] + ) + if code == 403: - raise VkLongPollError(403, - 'smth weth wrong', - self.base_url + '/', - params - ) + raise VkLongPollError(403, 'smth weth wrong', self.base_url + '/', params) + response = json.loads(response) failed = response.get('failed') + if not failed: self.ts = response['ts'] return response + if failed == 1: self.ts = response['ts'] elif failed == 4: - raise VkLongPollError(4, - 'An invalid version number was passed in the version parameter', - self.base_url + '/', - params) + raise VkLongPollError( + 4, + 'An invalid version number was passed in the version parameter', + self.base_url + '/', + params + ) else: self.base_url = None + return await self.wait() async def get_pts(self, need_ts=False): if not self.base_url or not self.pts: await self._get_long_poll_server(need_pts=True) + if need_ts: return self.pts, self.ts return self.pts + + +class UserLongPoll(BaseLongPoll): + """Implements https://vk.com/dev/using_longpoll""" + + async def _get_long_poll_server(self, need_pts=False): + response = await self.api('messages.getLongPollServer', need_pts=int(need_pts), timeout=self.timeout) + self.pts = response.get('pts') + self.ts = response['ts'] + self.key = response['key'] + # fucking differences between long poll methods in vk api! + self.base_url = 'https://{}'.format(response['server']) + + +class LongPoll(UserLongPoll): + """Implements https://vk.com/dev/using_longpoll + + This class for backward compatibility + """ + + +class BotsLongPoll(BaseLongPoll): + """Implements https://vk.com/dev/bots_longpoll""" + def __init__(self, session_or_api, mode, group_id, wait=25, version=1, timeout=None): + super().__init__(session_or_api, mode, wait, version, timeout) + self.group_id = group_id + + async def _get_long_poll_server(self, need_pts=False): + response = await self.api('groups.getLongPollServer', group_id=self.group_id) + self.pts = response.get('pts') + self.ts = response['ts'] + self.key = response['key'] + self.base_url = '{}'.format(response['server']) # Method already returning url with https:// diff --git a/aiovk/sessions.py b/aiovk/sessions.py index fc86735..8187cb0 100644 --- a/aiovk/sessions.py +++ b/aiovk/sessions.py @@ -36,7 +36,7 @@ async def send_api_request(self, method_name: str, params: dict = None, timeout: class TokenSession(BaseSession): - """Implements simple session that ues existed token for work""" + """Implements simple session that uses existed token for work""" API_VERSION = '5.74' REQUEST_URL = 'https://api.vk.com/method/'