forked from Darutik/e621bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
telebot.py
101 lines (81 loc) · 2.61 KB
/
telebot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# -*- coding: utf-8 -*-
from httpclient import HttpClient
from request import Request
from threading import Semaphore
import re
import time
import concurrent.futures
import socket
import requests.exceptions
CMD_REGEX = re.compile(r'\/([a-z0-9]+)(?:@([a-z0-9_]+))?(?:\s+(.*))?', re.IGNORECASE)
class TeleBot:
def __init__(self, apikey, name, commands, workers = 5):
self.apikey = apikey
self.name = name
self.commands = commands
self.lastUpdate = 0
self.updateTimeout = 30
self.workerPool = concurrent.futures.ThreadPoolExecutor(max_workers = workers)
self.workerSemaphore = Semaphore(workers)
self.httpClient = HttpClient()
self.httpClient.userAgent = 'Telegram Bot (@%s)' % (name)
def request(self, op, params, **kwargs):
url = 'https://api.telegram.org/bot%s/%s' % (self.apikey, op)
reply = self.httpClient.getJSON(url, params, **kwargs)
if not reply['ok']:
raise ValueError('Telegram replied with an error: %s' % repr(reply))
return reply['result']
def get_updates(self, start):
params = {
'offset': start,
'timeout': self.updateTimeout
}
try:
return self.request('getUpdates', params, timeout = self.updateTimeout)
except requests.exceptions.Timeout:
return []
def send_message(self, chat, text, **kwargs):
params = {
'chat_id': chat,
'text': text,
'reply_to_message_id': kwargs.pop('reply_to', None),
'parse_mode': kwargs.pop('markup', None)
}
return self.request('sendMessage', params)
def handle_update(self, update):
workerSemaphore = self.workerSemaphore
try:
request = Request(self, update)
except Exception as e:
print('Could not parse request: %s' % (repr(e)))
return
def async_command(request):
print('Servicing %s' % (request.readable))
try:
request.execute()
except Exception as e:
request.reply('Got an exception attempting to execute request: %s' % (repr(e)))
# Running it on callback ensures it will *always* free the semaphore no matter what the hell happens with the task
def free_lock(future):
workerSemaphore.release()
workerSemaphore.acquire()
future = self.workerPool.submit(async_command, request)
future.add_done_callback(free_lock)
def run_iteration(self):
updates = []
try:
updates = self.get_updates(self.lastUpdate)
except Exception as e:
print('Got exception reading server status: ' + str(e))
time.sleep(3)
for update in updates:
self.handle_update(update)
self.lastUpdate = max(self.lastUpdate, update['update_id'] + 1)
def run_main(self):
try:
while True:
self.run_iteration()
except KeyboardInterrupt:
pass
print('Shutting down...')
self.workerPool.shutdown()