1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Extended the message_handler decorator.

TeleBot now makes use of the API's getUpdates timeout optional parameter instead of time.sleep. This yields quicker response times.
This commit is contained in:
pieter 2015-07-02 22:32:18 +02:00
parent 144fa64604
commit 111ebf5c16
2 changed files with 78 additions and 39 deletions

View File

@ -41,7 +41,7 @@ class TeleBot:
self.last_update_id = 0
self.commands = []
self.message_handlers = []
def get_update(self):
"""
@ -49,7 +49,7 @@ class TeleBot:
Registered listeners and applicable message handlers will be notified when a new message arrives.
:raises ApiException when a call has failed.
"""
updates = apihelper.get_updates(self.token, offset=(self.last_update_id + 1))
updates = apihelper.get_updates(self.token, offset=(self.last_update_id + 1), timeout=20)
new_messages = []
for update in updates:
if update['update_id'] > self.last_update_id:
@ -66,31 +66,33 @@ class TeleBot:
t = threading.Thread(target=listener, args=new_messages)
t.start()
def polling(self, interval=3):
def polling(self):
"""
This function creates a new Thread that calls an internal __polling function.
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
Do not call this function more than once!
Always get updates.
:param interval: interval secs.
:return:
"""
self.interval = interval
# clear thread.
self.__stop_polling = True
time.sleep(interval + 1)
self.__stop_polling = False
self.polling_thread = threading.Thread(target=self.__polling, args=())
self.polling_thread.daemon = True
self.polling_thread.start()
def __polling(self):
print('telegram bot start polling')
print('TeleBot: Started polling.')
while not self.__stop_polling:
try:
self.get_update()
except Exception as e:
print("TeleBot: Exception occurred. Stopping.")
self.__stop_polling = True
print(e)
time.sleep(self.interval)
print('telegram bot stop polling')
print('TeleBot: Stopped polling.')
def stop_polling(self):
self.__stop_polling = True
@ -109,7 +111,7 @@ class TeleBot:
:param user_id:
:param offset:
:param limit:
:return:
:return: API reply.
"""
result = apihelper.get_user_profile_photos(self.token, user_id, offset, limit)
return types.UserProfilePhotos.de_json(result)
@ -122,7 +124,7 @@ class TeleBot:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_message(self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
reply_markup)
@ -133,7 +135,7 @@ class TeleBot:
:param chat_id: which chat to forward
:param from_chat_id: which chat message from
:param message_id: message id
:return:
:return: API reply.
"""
return apihelper.forward_message(self.token, chat_id, from_chat_id, message_id)
@ -145,7 +147,7 @@ class TeleBot:
:param caption:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_photo(self.token, chat_id, photo, caption, reply_to_message_id, reply_markup)
@ -157,7 +159,7 @@ class TeleBot:
:param data:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_data(self.token, chat_id, data, 'audio', reply_to_message_id, reply_markup)
@ -168,7 +170,7 @@ class TeleBot:
:param data:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_data(self.token, chat_id, data, 'document', reply_to_message_id, reply_markup)
@ -179,7 +181,7 @@ class TeleBot:
:param data:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_data(self.token, chat_id, data, 'sticker', reply_to_message_id, reply_markup)
@ -190,7 +192,7 @@ class TeleBot:
:param data:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_data(self.token, chat_id, data, 'video', reply_to_message_id, reply_markup)
@ -202,7 +204,7 @@ class TeleBot:
:param longitude:
:param reply_to_message_id:
:param reply_markup:
:return:
:return: API reply.
"""
return apihelper.send_location(self.token, chat_id, latitude, longitude, reply_to_message_id, reply_markup)
@ -212,13 +214,13 @@ class TeleBot:
The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear
its typing status).
:param chat_id:
:param action: string . typing,upload_photo,record_video,upload_video,record_audio,upload_audio,upload_document,
find_location.
:return:
:param action: One of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video',
'record_audio', 'upload_audio', 'upload_document', 'find_location'.
:return: API reply.
"""
return apihelper.send_chat_action(self.token, chat_id, action)
def message_handler(self, regexp=None, func=None, content_types=['text']):
def message_handler(self, commands=None, regexp=None, func=None, content_types=['text']):
"""
Message handler decorator.
This decorator can be used to decorate functions that must handle certain types of messages.
@ -246,27 +248,60 @@ class TeleBot:
:param regexp: Optional regular expression.
:param func: Optional lambda function. The lambda receives the message to test as the first parameter. It must return True if the command should handle the message.
:param content_types: This commands' supported content types. Must be a list. Defaults to ['text'].
:return:
"""
def decorator(fn):
self.commands.append([fn, regexp, func, content_types])
func_dict = {'function': fn, 'content_types': content_types}
if regexp:
func_dict['regexp'] = regexp if 'text' in content_types else None
if func:
func_dict['lambda'] = func
if commands:
func_dict['commands'] = commands if 'text' in content_types else None
self.message_handlers.append(func_dict)
return fn
return decorator
@staticmethod
def _test_command(command, message):
if message.content_type not in command[3]:
def is_command(text):
"""
Checks if `text` is a command. Telegram chat commands start with the '/' character.
:param text: Text to check.
:return: True if `text` is a command, else False.
"""
return text.startswith('/')
@staticmethod
def extract_command(text):
"""
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
If `text` is not a command, this function returns None.
Examples:
extract_command('/help'): 'help'
extract_command('/search black eyed peas'): 'search'
extract_command('Good day to you'): None
:param text: String to extract the command from
:return: the command if `text` is a command, else None.
"""
return text.split()[0][1:] if TeleBot.is_command(text) else None
@staticmethod
def _test_message_handler(message_handler, message):
if message.content_type not in message_handler['content_types']:
return False
if command[1] is not None and message.content_type == 'text' and re.search(command[1], message.text):
return True
if command[2] is not None:
return command[2](message)
if 'commands' in message_handler and message.content_type == 'text':
return TeleBot.extract_command(message.text) in message_handler['commands']
if 'regexp' in message_handler and message.content_type == 'text' and re.search(message_handler['regexp'], message.text):
return False
if 'lambda' in message_handler:
return message_handler['lambda'](message)
return False
def _notify_command_handlers(self, new_messages):
for message in new_messages:
for command in self.commands:
if self._test_command(command, message):
t = threading.Thread(target=command[0], args=(message,))
for message_handler in self.message_handlers:
if self._test_message_handler(message_handler, message):
t = threading.Thread(target=message_handler['function'], args=(message,))
t.start()
break

View File

@ -56,12 +56,16 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
return _make_request(token, method_url, params=payload)
def get_updates(token, offset=None):
def get_updates(token, offset=None, limit=None, timeout=None):
method_url = r'getUpdates'
if offset is not None:
return _make_request(token, method_url, params={'offset': offset})
else:
return _make_request(token, method_url)
payload = {}
if offset:
payload['offset'] = offset
if limit:
payload['limit'] = limit
if timeout:
payload['timeout'] = timeout
return _make_request(token, method_url, params=payload)
def get_user_profile_photos(token, user_id, offset=None, limit=None):