Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/bots_longpoll.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Модуль `bots_longpoll` (VkBotLongPoll)
=======================================

Модуль для работы с Bots Long Poll

.. module:: vk_api.bots_longpoll
.. autoclass:: VkBotLongPoll
:members:
.. autoclass:: BotEvent
:members:
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ vk_api – Python модуль для написания скриптов для
vk_api
audio
longpoll
bots_longpoll
execute
requests_pool
tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def main():
return
"""

# Авторизация группы:
# Авторизация группы (для групп рекомендуется использовать VkBotLongPoll):
# при передаче token вызывать vk_session.auth не нужно
"""
vk_session = vk_api.VkApi(token='токен с доступом к сообщениям и фото')
Expand Down
237 changes: 237 additions & 0 deletions vk_api/bot_longpoll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
import requests
from enum import Enum

CHAT_START_ID = int(2E9)


class DotDict(dict):
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__


class VkBotEventType(Enum):
MESSAGE_NEW = 'message_new'
MESSAGE_REPLY = 'message_reply'
MESSAGE_EDIT = 'message_edit'

MESSAGE_TYPING_STATE = 'message_typing_state'

MESSAGE_ALLOW = 'message_allow'

MESSAGE_DENY = 'message_deny'

PHOTO_NEW = 'photo_new'

PHOTO_COMMENT_NEW = 'photo_comment_new'
PHOTO_COMMENT_EDIT = 'photo_comment_edit'
PHOTO_COMMENT_RESTORE = 'photo_comment_restore'

PHOTO_COMMENT_DELETE = 'photo_comment_delete'

AUDIO_NEW = 'audio_new'

VIDEO_NEW = 'video_new'

VIDEO_COMMENT_NEW = 'video_comment_new'
VIDEO_COMMENT_EDIT = 'video_comment_edit'
VIDEO_COMMENT_RESTORE = 'video_comment_restore'

VIDEO_COMMENT_DELETE = 'video_comment_delete'

WALL_POST_NEW = 'wall_post_new'
WALL_REPOST = 'wall_repost'

WALL_REPLY_NEW = 'wall_reply_new'
WALL_REPLY_EDIT = 'wall_reply_edit'
WALL_REPLY_RESTORE = 'wall_reply_restore'

WALL_REPLY_DELETE = 'wall_reply_delete'

BOARD_POST_NEW = 'board_post_new'
BOARD_POST_EDIT = 'board_post_edit'
BOARD_POST_RESTORE = 'board_post_restore'

BOARD_POST_DELETE = 'board_post_delete'

MARKET_COMMENT_NEW = 'market_comment_new'
MARKET_COMMENT_EDIT = 'market_comment_edit'
MARKET_COMMENT_RESTORE = 'market_comment_restore'

MARKET_COMMENT_DELETE = 'market_comment_delete'

GROUP_LEAVE = 'group_leave'

GROUP_JOIN = 'group_join'

USER_BLOCK = 'user_block'

USER_UNBLOCK = 'user_unblock'

POLL_VOTE_NEW = 'poll_vote_new'

GROUP_OFFICERS_EDIT = 'group_officers_edit'

GROUP_CHANGE_SETTINGS = 'group_change_settings'

GROUP_CHANGE_PHOTO = 'group_change_photo'


class VkBotEvent(object):
""" Событие Bots Long Poll

Имеет поля в соответствии с `документацией <https://vk.com/dev/groups_events>`_.
"""

__slots__ = (
'raw',
't', 'type',
'obj', 'object',
'group_id'
)

def __init__(self, raw):
self.raw = raw

try:
self.type = VkBotEventType(raw['type'])
except ValueError:
self.type = raw['type']

self.t = self.type # shortcut

self.object = DotDict(raw['object'])
self.obj = self.object

self.group_id = raw['group_id']

def __repr__(self):
return f'<{type(self)}({self.raw})>'

class VkBotMessageEvent(VkBotEvent):
""" Событие с сообщением Bots Long Poll """

__slots__ = ('from_user', 'from_chat', 'from_group', 'chat_id')

def __init__(self, raw):
super(VkBotMessageEvent, self).__init__(raw)

self.from_user = False
self.from_chat = False
self.from_group = False
self.chat_id = None

if self.obj.peer_id < 0:
self.from_group = True
elif self.obj.peer_id < CHAT_START_ID:
self.from_user = True
else:
self.from_chat = True
self.chat_id = self.obj.peer_id - CHAT_START_ID


class VkBotLongPoll(object):
""" Класс для работы с Bots Long Poll сервером

`Подробнее в документации VK API <https://vk.com/dev/bots_longpoll>`__.

:param vk: объект :class:`VkApi`
:param group_id: id группы
:param wait: время ожидания
"""

__slots__ = (
'vk', 'wait', 'group_id',
'url', 'session',
'key', 'server', 'ts'
)

CLASS_BY_EVENT_TYPE = {
VkBotEventType.MESSAGE_NEW.value: VkBotMessageEvent,
VkBotEventType.MESSAGE_REPLY.value: VkBotMessageEvent,
VkBotEventType.MESSAGE_EDIT.value: VkBotMessageEvent,
}
DEFAULT_EVENT_CLASS = VkBotEvent

def __init__(self, vk, group_id, wait=25):
self.vk = vk
self.group_id = group_id
self.wait = wait

self.url = None
self.key = None
self.server = None
self.ts = None

self.session = requests.Session()

self.update_longpoll_server()

def _parse_event(self, raw_event):
event_class = self.CLASS_BY_EVENT_TYPE.get(
raw_event['type'],
self.DEFAULT_EVENT_CLASS
)
return event_class(raw_event)

def update_longpoll_server(self, update_ts=True):
values = {
'group_id': self.group_id
}
response = self.vk.method('groups.getLongPollServer', values)

self.key = response['key']
self.server = response['server']

self.url = self.server

if update_ts:
self.ts = response['ts']

def check(self):
"""
Получить события от сервера один раз

:returns: `list` of :class:`Event`
"""

values = {
'act': 'a_check',
'key': self.key,
'ts': self.ts,
'wait': self.wait,
}

response = self.session.get(
self.url,
params=values,
timeout=self.wait + 10
).json()

if 'failed' not in response:
self.ts = response['ts']
return [
self._parse_event(raw_event)
for raw_event in response['updates']
]

elif response['failed'] == 1:
self.ts = response['ts']

elif response['failed'] == 2:
self.update_longpoll_server(update_ts=False)

elif response['failed'] == 3:
self.update_longpoll_server()

return []

def listen(self):
"""
Слушать сервер

:yields: :class:`Event`
"""
while True:
for event in self.check():
yield event
2 changes: 1 addition & 1 deletion vk_api/longpoll.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from collections import defaultdict
from datetime import datetime
from enum import Enum, IntEnum
from enum import IntEnum

import requests

Expand Down
2 changes: 1 addition & 1 deletion vk_api/vk_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class VkApi(object):
def __init__(self, login=None, password=None, token=None,
auth_handler=None, captcha_handler=None,
config=jconfig.Config, config_filename='vk_config.v2.json',
api_version='5.74', app_id=6222115, scope=DEFAULT_USER_SCOPE,
api_version='5.80', app_id=6222115, scope=DEFAULT_USER_SCOPE,
client_secret=None):

self.login = login
Expand Down