from __future__ import annotations import asyncio from zvk.util.network import Network from zvk.util.zlogging import logger # BOT_MESSAGE_RANDOM_ID_MIN = 1337000000 # BOT_MESSAGE_RANDOM_ID_MAX = 1338000000 API_VERSION = '5.85' class MagicAccumulatingAttributeCatcher: api: VKApi full_method_name: str def __init__(self, api, full_method_name=None): self.api = api if full_method_name is None: full_method_name = '' self.full_method_name = full_method_name def __getattr__(self, item): return MagicAccumulatingAttributeCatcher(self.api, f'{self.full_method_name}.{item}') async def __call__(self, **kwargs): return await self.api.call_method(self.full_method_name, **kwargs) API_CALL_RETRY_COUNT = 3 class VKApi: """ VK api asynchronous interaction interface. Supports dope syntax like `await api.messages.get()`. """ _access_token: str _net: Network def __init__(self, config, net): self._access_token = config['api']['access_token'] self._net = net def __getattr__(self, name): return MagicAccumulatingAttributeCatcher(self, name) async def call_method(self, full_method_name, **params): url = f'https://api.vk.com/method/{full_method_name}' params['access_token'] = self._access_token params['v'] = API_VERSION # TODO: random_id management # if self.name == 'messages.send' and 'random_id' not in params: # params['random_id'] = random.randint(BOT_MESSAGE_RANDOM_ID_MIN, BOT_MESSAGE_RANDOM_ID_MAX) # if self.name == 'messages.send' and 'message' in params: # params['message'] = params['message'].replace('--', '-​-') # filter empty values params = {k: v for k, v in params.items() if v is not None} for retry in range(API_CALL_RETRY_COUNT): response, result = await self._net.post_json(url, sequential=True, data=params) if 'error' in result: error = result['error'] if error['error_code'] == 6: logger.warning('Too many requests, waiting and retrying...') await asyncio.sleep(1) continue raise RuntimeError(f'A significant VKApi error occurred {full_method_name}({params}) -> {error}') if 'response' not in result: raise RuntimeError(f'Malformed api response {full_method_name}({params}) -> {result}') logger.debug(f'VKApi call {full_method_name}({params}) -> {result}') return result['response'] raise RuntimeError(f'VKApi call unsuccessful after retries: {full_method_name}({params})')