Spaces:
Runtime error
Runtime error
| import logging | |
| import os | |
| from dataclasses import dataclass | |
| from http import HTTPStatus | |
| import aiohttp | |
| from .. import types | |
| from ..utils import exceptions, json | |
| from ..utils.helper import Helper, HelperMode, Item | |
| # Main aiogram logger | |
| log = logging.getLogger('aiogram') | |
| class TelegramAPIServer: | |
| """ | |
| Base config for API Endpoints | |
| """ | |
| base: str | |
| file: str | |
| def api_url(self, token: str, method: str) -> str: | |
| """ | |
| Generate URL for API methods | |
| :param token: Bot token | |
| :param method: API method name (case insensitive) | |
| :return: URL | |
| """ | |
| return self.base.format(token=token, method=method) | |
| def file_url(self, token: str, path: str) -> str: | |
| """ | |
| Generate URL for downloading files | |
| :param token: Bot token | |
| :param path: file path | |
| :return: URL | |
| """ | |
| return self.file.format(token=token, path=path) | |
| def from_base(cls, base: str) -> 'TelegramAPIServer': | |
| base = base.rstrip("/") | |
| return cls( | |
| base=f"{base}/bot{{token}}/{{method}}", | |
| file=f"{base}/file/bot{{token}}/{{path}}", | |
| ) | |
| TELEGRAM_PRODUCTION = TelegramAPIServer.from_base("https://api.telegram.org") | |
| def check_token(token: str) -> bool: | |
| """ | |
| Validate BOT token | |
| :param token: | |
| :return: | |
| """ | |
| if not isinstance(token, str): | |
| message = (f"Token is invalid! " | |
| f"It must be 'str' type instead of {type(token)} type.") | |
| raise exceptions.ValidationError(message) | |
| if any(x.isspace() for x in token): | |
| message = "Token is invalid! It can't contains spaces." | |
| raise exceptions.ValidationError(message) | |
| left, sep, right = token.partition(':') | |
| if (not sep) or (not left.isdigit()) or (not right): | |
| raise exceptions.ValidationError('Token is invalid!') | |
| return True | |
| def check_result(method_name: str, content_type: str, status_code: int, body: str): | |
| """ | |
| Checks whether `result` is a valid API response. | |
| A result is considered invalid if: | |
| - The server returned an HTTP response code other than 200 | |
| - The content of the result is invalid JSON. | |
| - The method call was unsuccessful (The JSON 'ok' field equals False) | |
| :param method_name: The name of the method called | |
| :param status_code: status code | |
| :param content_type: content type of result | |
| :param body: result body | |
| :return: The result parsed to a JSON dictionary | |
| :raises ApiException: if one of the above listed cases is applicable | |
| """ | |
| log.debug('Response for %s: [%d] "%r"', method_name, status_code, body) | |
| if content_type != 'application/json': | |
| raise exceptions.NetworkError(f"Invalid response with content type {content_type}: \"{body}\"") | |
| try: | |
| result_json = json.loads(body) | |
| except ValueError: | |
| result_json = {} | |
| description = result_json.get('description') or body | |
| parameters = types.ResponseParameters(**result_json.get('parameters', {}) or {}) | |
| if HTTPStatus.OK <= status_code <= HTTPStatus.IM_USED: | |
| return result_json.get('result') | |
| elif parameters.retry_after: | |
| raise exceptions.RetryAfter(parameters.retry_after) | |
| elif parameters.migrate_to_chat_id: | |
| raise exceptions.MigrateToChat(parameters.migrate_to_chat_id) | |
| elif status_code == HTTPStatus.BAD_REQUEST: | |
| exceptions.BadRequest.detect(description) | |
| elif status_code == HTTPStatus.NOT_FOUND: | |
| exceptions.NotFound.detect(description) | |
| elif status_code == HTTPStatus.CONFLICT: | |
| exceptions.ConflictError.detect(description) | |
| elif status_code in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): | |
| exceptions.Unauthorized.detect(description) | |
| elif status_code == HTTPStatus.REQUEST_ENTITY_TOO_LARGE: | |
| raise exceptions.NetworkError('File too large for uploading. ' | |
| 'Check telegram api limits https://core.telegram.org/bots/api#senddocument') | |
| elif status_code >= HTTPStatus.INTERNAL_SERVER_ERROR: | |
| if 'restart' in description: | |
| raise exceptions.RestartingTelegram() | |
| raise exceptions.TelegramAPIError(description) | |
| raise exceptions.TelegramAPIError(f"{description} [{status_code}]") | |
| async def make_request(session, server, token, method, data=None, files=None, **kwargs): | |
| log.debug('Make request: "%s" with data: "%r" and files "%r"', method, data, files) | |
| url = server.api_url(token=token, method=method) | |
| req = compose_data(data, files) | |
| try: | |
| async with session.post(url, data=req, **kwargs) as response: | |
| return check_result(method, response.content_type, response.status, await response.text()) | |
| except aiohttp.ClientError as e: | |
| raise exceptions.NetworkError(f"aiohttp client throws an error: {e.__class__.__name__}: {e}") | |
| def guess_filename(obj): | |
| """ | |
| Get file name from object | |
| :param obj: | |
| :return: | |
| """ | |
| name = getattr(obj, 'name', None) | |
| if name and isinstance(name, str) and name[0] != '<' and name[-1] != '>': | |
| return os.path.basename(name) | |
| def compose_data(params=None, files=None): | |
| """ | |
| Prepare request data | |
| :param params: | |
| :param files: | |
| :return: | |
| """ | |
| data = aiohttp.formdata.FormData(quote_fields=False) | |
| if params: | |
| for key, value in params.items(): | |
| data.add_field(key, str(value)) | |
| if files: | |
| for key, f in files.items(): | |
| if isinstance(f, tuple): | |
| if len(f) == 2: | |
| filename, fileobj = f | |
| else: | |
| raise ValueError('Tuple must have exactly 2 elements: filename, fileobj') | |
| elif isinstance(f, types.InputFile): | |
| filename, fileobj = f.filename, f.file | |
| else: | |
| filename, fileobj = guess_filename(f) or key, f | |
| data.add_field(key, fileobj, filename=filename) | |
| return data | |
| class Methods(Helper): | |
| """ | |
| Helper for Telegram API Methods listed on https://core.telegram.org/bots/api | |
| """ | |
| mode = HelperMode.lowerCamelCase | |
| # Getting Updates | |
| GET_UPDATES = Item() # getUpdates | |
| SET_WEBHOOK = Item() # setWebhook | |
| DELETE_WEBHOOK = Item() # deleteWebhook | |
| GET_WEBHOOK_INFO = Item() # getWebhookInfo | |
| # Available methods | |
| GET_ME = Item() # getMe | |
| LOG_OUT = Item() # logOut | |
| CLOSE = Item() # close | |
| SEND_MESSAGE = Item() # sendMessage | |
| FORWARD_MESSAGE = Item() # forwardMessage | |
| COPY_MESSAGE = Item() # copyMessage | |
| SEND_PHOTO = Item() # sendPhoto | |
| SEND_AUDIO = Item() # sendAudio | |
| SEND_DOCUMENT = Item() # sendDocument | |
| SEND_VIDEO = Item() # sendVideo | |
| SEND_ANIMATION = Item() # sendAnimation | |
| SEND_VOICE = Item() # sendVoice | |
| SEND_VIDEO_NOTE = Item() # sendVideoNote | |
| SEND_MEDIA_GROUP = Item() # sendMediaGroup | |
| SEND_LOCATION = Item() # sendLocation | |
| EDIT_MESSAGE_LIVE_LOCATION = Item() # editMessageLiveLocation | |
| STOP_MESSAGE_LIVE_LOCATION = Item() # stopMessageLiveLocation | |
| SEND_VENUE = Item() # sendVenue | |
| SEND_CONTACT = Item() # sendContact | |
| SEND_POLL = Item() # sendPoll | |
| SEND_DICE = Item() # sendDice | |
| SEND_CHAT_ACTION = Item() # sendChatAction | |
| GET_USER_PROFILE_PHOTOS = Item() # getUserProfilePhotos | |
| GET_FILE = Item() # getFile | |
| KICK_CHAT_MEMBER = Item() # kickChatMember | |
| BAN_CHAT_MEMBER = Item() # banChatMember | |
| UNBAN_CHAT_MEMBER = Item() # unbanChatMember | |
| RESTRICT_CHAT_MEMBER = Item() # restrictChatMember | |
| PROMOTE_CHAT_MEMBER = Item() # promoteChatMember | |
| SET_CHAT_ADMINISTRATOR_CUSTOM_TITLE = Item() # setChatAdministratorCustomTitle | |
| BAN_CHAT_SENDER_CHAT = Item() # banChatSenderChat | |
| UNBAN_CHAT_SENDER_CHAT = Item() # unbanChatSenderChat | |
| SET_CHAT_PERMISSIONS = Item() # setChatPermissions | |
| EXPORT_CHAT_INVITE_LINK = Item() # exportChatInviteLink | |
| CREATE_CHAT_INVITE_LINK = Item() # createChatInviteLink | |
| EDIT_CHAT_INVITE_LINK = Item() # editChatInviteLink | |
| REVOKE_CHAT_INVITE_LINK = Item() # revokeChatInviteLink | |
| APPROVE_CHAT_JOIN_REQUEST = Item() # approveChatJoinRequest | |
| DECLINE_CHAT_JOIN_REQUEST = Item() # declineChatJoinRequest | |
| SET_CHAT_PHOTO = Item() # setChatPhoto | |
| DELETE_CHAT_PHOTO = Item() # deleteChatPhoto | |
| SET_CHAT_TITLE = Item() # setChatTitle | |
| SET_CHAT_DESCRIPTION = Item() # setChatDescription | |
| PIN_CHAT_MESSAGE = Item() # pinChatMessage | |
| UNPIN_CHAT_MESSAGE = Item() # unpinChatMessage | |
| UNPIN_ALL_CHAT_MESSAGES = Item() # unpinAllChatMessages | |
| LEAVE_CHAT = Item() # leaveChat | |
| GET_CHAT = Item() # getChat | |
| GET_CHAT_ADMINISTRATORS = Item() # getChatAdministrators | |
| GET_CHAT_MEMBER_COUNT = Item() # getChatMemberCount | |
| GET_CHAT_MEMBERS_COUNT = Item() # getChatMembersCount (renamed to getChatMemberCount) | |
| GET_CHAT_MEMBER = Item() # getChatMember | |
| SET_CHAT_STICKER_SET = Item() # setChatStickerSet | |
| DELETE_CHAT_STICKER_SET = Item() # deleteChatStickerSet | |
| GET_FORUM_TOPIC_ICON_STICKERS = Item() # getForumTopicIconStickers | |
| CREATE_FORUM_TOPIC = Item() # createForumTopic | |
| EDIT_FORUM_TOPIC = Item() # editForumTopic | |
| CLOSE_FORUM_TOPIC = Item() # closeForumTopic | |
| REOPEN_FORUM_TOPIC = Item() # reopenForumTopic | |
| DELETE_FORUM_TOPIC = Item() # deleteForumTopic | |
| UNPIN_ALL_FORUM_TOPIC_MESSAGES = Item() # unpinAllForumTopicMessages | |
| EDIT_GENERAL_FORUM_TOPIC = Item() # editGeneralForumTopic | |
| CLOSE_GENERAL_FORUM_TOPIC = Item() # closeGeneralForumTopic | |
| REOPEN_GENERAL_FORUM_TOPIC = Item() # reopenGeneralForumTopic | |
| HIDE_GENERAL_FORUM_TOPIC = Item() # hideGeneralForumTopic | |
| UNHIDE_GENERAL_FORUM_TOPIC = Item() # unhideGeneralForumTopic | |
| ANSWER_CALLBACK_QUERY = Item() # answerCallbackQuery | |
| SET_MY_COMMANDS = Item() # setMyCommands | |
| DELETE_MY_COMMANDS = Item() # deleteMyCommands | |
| GET_MY_COMMANDS = Item() # getMyCommands | |
| # Updating messages | |
| EDIT_MESSAGE_TEXT = Item() # editMessageText | |
| EDIT_MESSAGE_CAPTION = Item() # editMessageCaption | |
| EDIT_MESSAGE_MEDIA = Item() # editMessageMedia | |
| EDIT_MESSAGE_REPLY_MARKUP = Item() # editMessageReplyMarkup | |
| STOP_POLL = Item() # stopPoll | |
| DELETE_MESSAGE = Item() # deleteMessage | |
| # Stickers | |
| SEND_STICKER = Item() # sendSticker | |
| GET_STICKER_SET = Item() # getStickerSet | |
| UPLOAD_STICKER_FILE = Item() # uploadStickerFile | |
| GET_CUSTOM_EMOJI_STICKERS = Item() # getCustomEmojiStickers | |
| CREATE_NEW_STICKER_SET = Item() # createNewStickerSet | |
| ADD_STICKER_TO_SET = Item() # addStickerToSet | |
| SET_STICKER_POSITION_IN_SET = Item() # setStickerPositionInSet | |
| DELETE_STICKER_FROM_SET = Item() # deleteStickerFromSet | |
| SET_STICKER_SET_THUMB = Item() # setStickerSetThumb | |
| # Inline mode | |
| ANSWER_INLINE_QUERY = Item() # answerInlineQuery | |
| ANSWER_WEB_APP_QUERY = Item() # answerWebAppQuery | |
| SET_CHAT_MENU_BUTTON = Item() # setChatMenuButton | |
| GET_CHAT_MENU_BUTTON = Item() # getChatMenuButton | |
| SET_MY_DEFAULT_ADMINISTRATOR_RIGHTS = Item() # setMyDefaultAdministratorRights | |
| GET_MY_DEFAULT_ADMINISTRATOR_RIGHTS = Item() # getMyDefaultAdministratorRights | |
| # Payments | |
| SEND_INVOICE = Item() # sendInvoice | |
| CREATE_INVOICE_LINK = Item() # createInvoiceLink | |
| ANSWER_SHIPPING_QUERY = Item() # answerShippingQuery | |
| ANSWER_PRE_CHECKOUT_QUERY = Item() # answerPreCheckoutQuery | |
| # Telegram Passport | |
| SET_PASSPORT_DATA_ERRORS = Item() # setPassportDataErrors | |
| # Games | |
| SEND_GAME = Item() # sendGame | |
| SET_GAME_SCORE = Item() # setGameScore | |
| GET_GAME_HIGH_SCORES = Item() # getGameHighScores | |