telegem 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Readme.md +2 -2
- data/Starts_HallofFame.md +65 -0
- data/Test-Projects/bot.md +145 -0
- data/Test-Projects/bot1.rb +91 -0
- data/bin/telegem-ssl +44 -0
- data/docs-src/Bot-registration_.PNG +0 -0
- data/docs-src/bot.md +349 -180
- data/docs-src/ctx.md +399 -0
- data/docs-src/webhook.md +341 -0
- data/lib/api/client.rb +72 -27
- data/lib/core/bot.rb +81 -149
- data/lib/telegem.rb +1 -1
- data/lib/webhook/server.rb +149 -290
- data/public/index.html +481 -0
- metadata +32 -24
- data/Test-Projects/Movie-tracker-bot/Gemfile +0 -2
- data/Test-Projects/Movie-tracker-bot/bot.rb +0 -62
- data/Test-Projects/Movie-tracker-bot/handlers/.gitkeep +0 -0
- data/Test-Projects/Movie-tracker-bot/handlers/add_1_.rb +0 -160
- data/Test-Projects/Movie-tracker-bot/handlers/add_2_.rb +0 -139
- data/Test-Projects/Movie-tracker-bot/handlers/premium.rb +0 -13
- data/Test-Projects/Movie-tracker-bot/handlers/report.rb +0 -31
- data/Test-Projects/Movie-tracker-bot/handlers/search.rb +0 -150
- data/Test-Projects/Movie-tracker-bot/handlers/sponsor.rb +0 -14
- data/Test-Projects/Movie-tracker-bot/handlers/start.rb +0 -48
- data/Test-Projects/Movie-tracker-bot/handlers/watch.rb +0 -210
- data/Test-Projects/Test-submitted-by-marvel/.gitkeep +0 -0
- data/Test-Projects/Test-submitted-by-marvel/Marvel-bot.md +0 -3
- data/Test-Projects/bot_test1.rb +0 -75
- data/Test-Projects/pizza_test_bot_guide.md +0 -163
- data/docs-src/understanding-ctx.md +0 -581
- /data/{Test-Projects → bin}/.gitkeep +0 -0
- /data/{Test-Projects/Movie-tracker-bot → public}/.gitkeep +0 -0
data/lib/core/bot.rb
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
require 'concurrent'
|
|
2
2
|
require 'logger'
|
|
3
|
+
require 'async'
|
|
3
4
|
|
|
4
5
|
module Telegem
|
|
5
6
|
module Core
|
|
6
7
|
class Bot
|
|
7
8
|
attr_reader :token, :api, :handlers, :middleware, :logger, :scenes,
|
|
8
|
-
:running, :
|
|
9
|
+
:running, :session_store
|
|
9
10
|
|
|
10
11
|
def initialize(token, **options)
|
|
11
12
|
@token = token
|
|
12
13
|
@api = API::Client.new(token, **options.slice(:logger, :timeout))
|
|
13
|
-
@api_mutex = Mutex.new # ← LINE 1 ADDED HERE
|
|
14
14
|
|
|
15
15
|
@handlers = {
|
|
16
16
|
message: [],
|
|
@@ -27,57 +27,27 @@ module Telegem
|
|
|
27
27
|
@logger = options[:logger] || Logger.new($stdout)
|
|
28
28
|
@error_handler = nil
|
|
29
29
|
@session_store = options[:session_store] || Session::MemoryStore.new
|
|
30
|
-
|
|
31
|
-
@
|
|
32
|
-
@
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
@polling_thread = nil
|
|
36
|
-
@running = false
|
|
37
|
-
@offset = nil
|
|
38
|
-
|
|
39
|
-
start_workers(options[:worker_count] || 5)
|
|
30
|
+
|
|
31
|
+
@running = false
|
|
32
|
+
@offset = 0
|
|
33
|
+
@polling_options = options.slice(:timeout, :limit, :allowed_updates) || {}
|
|
40
34
|
end
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
timeout: 30,
|
|
48
|
-
limit: 100,
|
|
49
|
-
allowed_updates: nil
|
|
50
|
-
}.merge(options)
|
|
51
|
-
|
|
52
|
-
@offset = nil
|
|
53
|
-
|
|
54
|
-
@logger.info "🤖 Starting Telegem bot (polling mode)..."
|
|
55
|
-
|
|
56
|
-
@polling_thread = Thread.new do
|
|
57
|
-
Thread.current.abort_on_exception = false
|
|
58
|
-
poll_loop
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
self
|
|
36
|
+
def start_polling(**options)
|
|
37
|
+
@running = true
|
|
38
|
+
@polling_options = options
|
|
39
|
+
Async do
|
|
40
|
+
poll_loop # Now runs in Async context
|
|
62
41
|
end
|
|
42
|
+
end
|
|
63
43
|
|
|
64
44
|
def shutdown
|
|
65
45
|
return unless @running
|
|
66
46
|
|
|
67
47
|
@logger.info "🛑 Shutting down bot..."
|
|
68
48
|
@running = false
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@polling_thread.join(3)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
stop_workers
|
|
75
|
-
|
|
76
|
-
@api.close if @api.respond_to?(:close)
|
|
77
|
-
|
|
78
|
-
@logger.info "✅ Bot shutdown complete"
|
|
79
|
-
end
|
|
80
|
-
|
|
49
|
+
sleep 0.1
|
|
50
|
+
end
|
|
81
51
|
def running?
|
|
82
52
|
@running
|
|
83
53
|
end
|
|
@@ -128,16 +98,16 @@ module Telegem
|
|
|
128
98
|
end
|
|
129
99
|
end
|
|
130
100
|
|
|
131
|
-
def set_webhook(url, **options)
|
|
132
|
-
@api.call!('setWebhook', { url: url }.merge(options))
|
|
101
|
+
def set_webhook(url, **options, &callback)
|
|
102
|
+
@api.call!('setWebhook', { url: url }.merge(options), &callback)
|
|
133
103
|
end
|
|
134
|
-
|
|
135
|
-
def delete_webhook
|
|
136
|
-
@api.call!('deleteWebhook', {})
|
|
104
|
+
|
|
105
|
+
def delete_webhook(&callback)
|
|
106
|
+
@api.call!('deleteWebhook', {}, &callback)
|
|
137
107
|
end
|
|
138
|
-
|
|
139
|
-
def get_webhook_info
|
|
140
|
-
@api.call!('getWebhookInfo', {})
|
|
108
|
+
|
|
109
|
+
def get_webhook_info(&callback)
|
|
110
|
+
@api.call!('getWebhookInfo', {}, &callback)
|
|
141
111
|
end
|
|
142
112
|
|
|
143
113
|
def process(update_data)
|
|
@@ -147,112 +117,74 @@ module Telegem
|
|
|
147
117
|
|
|
148
118
|
private
|
|
149
119
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
sleep 0.1 unless @offset.nil?
|
|
164
|
-
|
|
165
|
-
rescue => e
|
|
166
|
-
handle_error(e)
|
|
167
|
-
sleep 5
|
|
168
|
-
end
|
|
120
|
+
def poll_loop
|
|
121
|
+
fetch_updates do |result|
|
|
122
|
+
if result && result['ok']
|
|
123
|
+
handle_updates_response(result)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
if @running
|
|
127
|
+
# Schedule next poll in NEW async context
|
|
128
|
+
Async { |task|
|
|
129
|
+
task.sleep(1)
|
|
130
|
+
poll_loop
|
|
131
|
+
}
|
|
169
132
|
end
|
|
170
|
-
|
|
171
|
-
@logger.debug "Exiting polling loop"
|
|
172
133
|
end
|
|
173
|
-
|
|
174
|
-
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def fetch_updates(&completion_callback)
|
|
175
137
|
params = {
|
|
176
|
-
timeout: @polling_options[:timeout],
|
|
177
|
-
limit: @polling_options[:limit]
|
|
138
|
+
timeout: @polling_options[:timeout] || 30,
|
|
139
|
+
limit: @polling_options[:limit] || 100
|
|
178
140
|
}
|
|
179
141
|
params[:offset] = @offset if @offset
|
|
180
142
|
params[:allowed_updates] = @polling_options[:allowed_updates] if @polling_options[:allowed_updates]
|
|
181
|
-
|
|
182
|
-
@logger.debug
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
updates = api_response['result'] || []
|
|
197
|
-
|
|
198
|
-
if updates.any?
|
|
199
|
-
@logger.debug "Processing #{updates.length} update(s)"
|
|
200
|
-
|
|
201
|
-
updates.each do |update_data|
|
|
202
|
-
@update_queue << [update_data, nil]
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
@offset = updates.last['update_id'] + 1
|
|
206
|
-
@logger.debug "Updated offset to #{@offset}"
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def start_workers(count)
|
|
211
|
-
count.times do |i|
|
|
212
|
-
@worker_threads << Thread.new do
|
|
213
|
-
Thread.current.abort_on_exception = false
|
|
214
|
-
worker_loop(i)
|
|
143
|
+
|
|
144
|
+
@logger.debug "Fetching updates with offset: #{@offset}"
|
|
145
|
+
|
|
146
|
+
@api.call!('getUpdates', params) do |updates_array, error|
|
|
147
|
+
if error
|
|
148
|
+
@logger.error "Polling error: #{error.message}"
|
|
149
|
+
completion_callback.call(nil, error) if completion_callback
|
|
150
|
+
else
|
|
151
|
+
|
|
152
|
+
# Success
|
|
153
|
+
if updates_array && updates_array.is_a?(Array)
|
|
154
|
+
result = { 'ok' => true, 'result' => updates_array }
|
|
155
|
+
completion_callback.call(result, nil) if completion_callback
|
|
156
|
+
else
|
|
157
|
+
completion_callback.call(nil, nil) if completion_callback
|
|
215
158
|
end
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def stop_workers
|
|
221
|
-
@logger.debug "Stopping worker threads"
|
|
222
|
-
|
|
223
|
-
@worker_threads.size.times { @update_queue << :shutdown }
|
|
224
|
-
|
|
225
|
-
@worker_threads.each do |thread|
|
|
226
|
-
thread.join(2) if thread.alive?
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
@worker_threads.clear
|
|
159
|
+
end
|
|
160
|
+
end
|
|
230
161
|
end
|
|
231
|
-
|
|
232
|
-
def worker_loop(id)
|
|
233
|
-
@logger.debug "Worker #{id} started"
|
|
234
|
-
|
|
235
|
-
while @running
|
|
236
|
-
begin
|
|
237
|
-
task = @update_queue.pop
|
|
238
|
-
|
|
239
|
-
break if task == :shutdown
|
|
240
|
-
|
|
241
|
-
update_data, callback = task
|
|
242
|
-
process_update(Types::Update.new(update_data))
|
|
162
|
+
|
|
243
163
|
|
|
244
|
-
callback&.call if callback.respond_to?(:call)
|
|
245
|
-
|
|
246
|
-
rescue => e
|
|
247
|
-
@logger.error "Worker #{id} error: #{e.message}"
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
@logger.debug "Worker #{id} stopped"
|
|
252
|
-
end
|
|
253
164
|
|
|
165
|
+
def handle_updates_response(api_response)
|
|
166
|
+
if api_response['ok']
|
|
167
|
+
updates = api_response['result'] || []
|
|
168
|
+
updates.each do |data|
|
|
169
|
+
Async do |task|
|
|
170
|
+
update_object = Types::Update.new(data)
|
|
171
|
+
process_update(update_object)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
if updates.any?
|
|
175
|
+
@offset = updates.last['update_id'] + 1
|
|
176
|
+
@logger.debug "Updated offset to; #{@offset}"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
254
181
|
def process_update(update)
|
|
255
|
-
|
|
182
|
+
if update.message&.text && @logger
|
|
183
|
+
user = update.message.from
|
|
184
|
+
cmd = update.message.text.split.first
|
|
185
|
+
@logger.info("#{cmd} - #{user.username || user.first_name}")
|
|
186
|
+
end
|
|
187
|
+
|
|
256
188
|
ctx = Context.new(update, self)
|
|
257
189
|
|
|
258
190
|
begin
|
|
@@ -262,7 +194,7 @@ module Telegem
|
|
|
262
194
|
rescue => e
|
|
263
195
|
handle_error(e, ctx)
|
|
264
196
|
end
|
|
265
|
-
|
|
197
|
+
|
|
266
198
|
end
|
|
267
199
|
|
|
268
200
|
def run_middleware_chain(ctx, &final)
|
|
@@ -361,4 +293,4 @@ module Telegem
|
|
|
361
293
|
end
|
|
362
294
|
end
|
|
363
295
|
end
|
|
364
|
-
end
|
|
296
|
+
end
|