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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/Readme.md +2 -2
  3. data/Starts_HallofFame.md +65 -0
  4. data/Test-Projects/bot.md +145 -0
  5. data/Test-Projects/bot1.rb +91 -0
  6. data/bin/telegem-ssl +44 -0
  7. data/docs-src/Bot-registration_.PNG +0 -0
  8. data/docs-src/bot.md +349 -180
  9. data/docs-src/ctx.md +399 -0
  10. data/docs-src/webhook.md +341 -0
  11. data/lib/api/client.rb +72 -27
  12. data/lib/core/bot.rb +81 -149
  13. data/lib/telegem.rb +1 -1
  14. data/lib/webhook/server.rb +149 -290
  15. data/public/index.html +481 -0
  16. metadata +32 -24
  17. data/Test-Projects/Movie-tracker-bot/Gemfile +0 -2
  18. data/Test-Projects/Movie-tracker-bot/bot.rb +0 -62
  19. data/Test-Projects/Movie-tracker-bot/handlers/.gitkeep +0 -0
  20. data/Test-Projects/Movie-tracker-bot/handlers/add_1_.rb +0 -160
  21. data/Test-Projects/Movie-tracker-bot/handlers/add_2_.rb +0 -139
  22. data/Test-Projects/Movie-tracker-bot/handlers/premium.rb +0 -13
  23. data/Test-Projects/Movie-tracker-bot/handlers/report.rb +0 -31
  24. data/Test-Projects/Movie-tracker-bot/handlers/search.rb +0 -150
  25. data/Test-Projects/Movie-tracker-bot/handlers/sponsor.rb +0 -14
  26. data/Test-Projects/Movie-tracker-bot/handlers/start.rb +0 -48
  27. data/Test-Projects/Movie-tracker-bot/handlers/watch.rb +0 -210
  28. data/Test-Projects/Test-submitted-by-marvel/.gitkeep +0 -0
  29. data/Test-Projects/Test-submitted-by-marvel/Marvel-bot.md +0 -3
  30. data/Test-Projects/bot_test1.rb +0 -75
  31. data/Test-Projects/pizza_test_bot_guide.md +0 -163
  32. data/docs-src/understanding-ctx.md +0 -581
  33. /data/{Test-Projects → bin}/.gitkeep +0 -0
  34. /data/{Test-Projects/Movie-tracker-bot → public}/.gitkeep +0 -0
@@ -0,0 +1,341 @@
1
+ Webhook Guide for Telegem
2
+
3
+ This guide explains how to set up and use webhooks with Telegem. Telegram bots require HTTPS webhooks, and this guide covers all setup options.
4
+
5
+ 🎯 Quick Start
6
+
7
+ Choose your hosting type and follow the appropriate section:
8
+
9
+ - VPS/Dedicated Server → Use the CLI tool for automatic SSL
10
+ - Cloud Platforms (Render, Railway, Heroku) → Use environment variables
11
+ - Manual Setup → Provide your own certificates
12
+ - Development/Testing → Use polling instead
13
+
14
+ 🔐 SSL Requirements
15
+
16
+ Important: Telegram requires HTTPS webhooks. HTTP will not work. You must configure SSL using one of these methods:
17
+
18
+ Method 1: VPS/Dedicated Server (Recommended)
19
+
20
+ For servers where you have shell access and can run commands:
21
+
22
+ ```bash
23
+ # 1. Install Telegem
24
+ gem install telegem
25
+
26
+ # 2. Run the SSL setup tool
27
+ telegem-ssl your-domain.com your-email@example.com
28
+
29
+ # Example:
30
+ telegem-ssl bot.myapp.com admin@myapp.com
31
+ ```
32
+
33
+ What this does:
34
+
35
+ - Installs certbot if not present
36
+ - Gets a free SSL certificate from Let's Encrypt
37
+ - Creates .telegem-ssl configuration file
38
+ - Certificates auto-renew every 90 days
39
+
40
+ Your bot code:
41
+
42
+ ```ruby
43
+ require 'telegem'
44
+
45
+ bot = Telegem.new(ENV['TELEGRAM_BOT_TOKEN'])
46
+
47
+ # Start webhook - automatically detects .telegem-ssl file
48
+ bot.webhook
49
+
50
+ # Or get the webhook server for more control
51
+ server = bot.webhook
52
+ server.set_webhook
53
+ ```
54
+
55
+ Method 2: Cloud Platforms (Render, Railway, Heroku)
56
+
57
+ For platforms that provide SSL automatically:
58
+
59
+ ```bash
60
+ # Set these environment variables
61
+ export TELEGRAM_BOT_TOKEN=your_bot_token
62
+ export TELEGEM_WEBHOOK_URL=https://your-app.onrender.com
63
+ export WEBHOOK_SECRET_TOKEN=optional_secret_token
64
+ ```
65
+
66
+ Your bot code:
67
+
68
+ ```ruby
69
+ require 'telegem'
70
+
71
+ bot = Telegem.new(ENV['TELEGRAM_BOT_TOKEN'])
72
+
73
+ # Start webhook - detects TELEGEM_WEBHOOK_URL
74
+ server = bot.webhook
75
+
76
+ # Set the webhook with Telegram
77
+ webhook_url = server.set_webhook
78
+ puts "Webhook URL: #{webhook_url}"
79
+ ```
80
+
81
+ Cloud Platform Specifics:
82
+
83
+ Platform TELEGEM_WEBHOOK_URL Example
84
+ Render https://your-app.onrender.com
85
+ Railway https://your-app.railway.app
86
+ Heroku https://your-app.herokuapp.com
87
+ Fly.io https://your-app.fly.dev
88
+
89
+ Method 3: Manual Certificate Setup
90
+
91
+ If you already have SSL certificates:
92
+
93
+ ```ruby
94
+ require 'telegem'
95
+
96
+ bot = Telegem.new(ENV['TELEGRAM_BOT_TOKEN'])
97
+
98
+ # Provide certificate paths
99
+ server = bot.webhook(ssl: {
100
+ cert_path: "/path/to/certificate.pem",
101
+ key_path: "/path/to/private-key.pem"
102
+ })
103
+
104
+ server.set_webhook
105
+ ```
106
+
107
+ 📡 Webhook Server Methods
108
+
109
+ Once you have a webhook server instance, you can use these methods:
110
+
111
+ ```ruby
112
+ server = bot.webhook # or bot.webhook(options)
113
+
114
+ # Start the server (runs in background)
115
+ server.run
116
+
117
+ # Get the webhook URL for Telegram
118
+ url = server.webhook_url
119
+ # => "https://your-domain.com/webhook/abc123def456"
120
+
121
+ # Set webhook with Telegram (recommended)
122
+ server.set_webhook
123
+
124
+ # Additional options for set_webhook
125
+ server.set_webhook(
126
+ max_connections: 40,
127
+ allowed_updates: ["message", "callback_query"]
128
+ )
129
+
130
+ # Check webhook info from Telegram
131
+ info = server.get_webhook_info
132
+
133
+ # Delete webhook
134
+ server.delete_webhook
135
+
136
+ # Stop the server
137
+ server.stop
138
+
139
+ # Check if server is running
140
+ server.running? # => true/false
141
+
142
+ # Health check endpoint
143
+ # Your server automatically provides: /health
144
+ ```
145
+
146
+ 🔒 Security: Secret Tokens
147
+
148
+ Telegem automatically generates and uses secret tokens to prevent unauthorized access:
149
+
150
+ ```ruby
151
+ # Auto-generated (recommended)
152
+ server = bot.webhook
153
+ puts server.secret_token # => "abc123def456"
154
+
155
+ # Custom token
156
+ server = bot.webhook(secret_token: "my_custom_secret")
157
+
158
+ # Via environment variable
159
+ export WEBHOOK_SECRET_TOKEN=my_custom_secret
160
+ ```
161
+
162
+ Webhook URL format:
163
+
164
+ ```
165
+ https://your-domain.com/abc123def456
166
+ ```
167
+
168
+ Only requests to this exact path will be processed. All other paths return 404.
169
+
170
+ 🏥 Health Monitoring
171
+
172
+ Your webhook server automatically provides a health endpoint:
173
+
174
+ ```bash
175
+ curl https://your-domain.com/health
176
+ # Returns: {"status":"ok","mode":"cli","ssl":true}
177
+ ```
178
+
179
+ Use this for:
180
+
181
+ - Platform health checks (Render, Railway)
182
+ - Load balancer health checks
183
+ - Monitoring and alerts
184
+
185
+ 🔧 Configuration Options
186
+
187
+ Full list of webhook method options:
188
+
189
+ ```ruby
190
+ bot.webhook(
191
+ port: 3000, # Port to listen on
192
+ host: '0.0.0.0', # Host to bind to
193
+ secret_token: nil, # Custom secret token
194
+ logger: custom_logger, # Custom logger
195
+ ssl: { # SSL options
196
+ cert_path: '/path/to/cert.pem',
197
+ key_path: '/path/to/key.pem'
198
+ }
199
+ )
200
+ ```
201
+
202
+ 🚫 Common Errors & Solutions
203
+
204
+ Error: "No SSL configured"
205
+
206
+ Solution: Choose one:
207
+
208
+ 1. Run telegem-ssl your-domain.com (VPS)
209
+ 2. Set TELEGEM_WEBHOOK_URL environment variable (Cloud)
210
+ 3. Provide certificate paths manually
211
+ 4. Use bot.start_polling() instead
212
+
213
+ Error: "Telegram webhook failed"
214
+
215
+ Solution:
216
+
217
+ ```ruby
218
+ # Check current webhook info
219
+ info = server.get_webhook_info
220
+ puts info.inspect
221
+
222
+ # Delete and retry
223
+ server.delete_webhook
224
+ server.set_webhook
225
+ ```
226
+
227
+ Error: "Certificate not found"
228
+
229
+ Solution:
230
+
231
+ ```bash
232
+ # Regenerate certificates
233
+ telegem-ssl your-domain.com --force
234
+
235
+ # Or check file permissions
236
+ ls -la /etc/letsencrypt/live/your-domain.com/
237
+ ```
238
+
239
+ 🔄 Polling vs Webhook
240
+
241
+ When to use each:
242
+
243
+ -Use Case Recommended Method
244
+ Development/Testing bot.start_polling()
245
+ -Production (VPS) bot.webhook() with CLI
246
+ -Production (Cloud) bot.webhook() with env var
247
+ -Limited Resources bot.start_polling()
248
+ -High Traffic bot.webhook()
249
+
250
+ Polling example (for development):
251
+
252
+ ```ruby
253
+ bot.start_polling(
254
+ timeout: 30,
255
+ limit: 100,
256
+ allowed_updates: ["message"]
257
+ )
258
+ ```
259
+
260
+ 📋 Complete Example
261
+
262
+ VPS Production Setup (bot.rb):
263
+
264
+ ```ruby
265
+ #!/usr/bin/env ruby
266
+ require 'telegem'
267
+
268
+ bot = Telegem.new(ENV['TELEGRAM_BOT_TOKEN'])
269
+
270
+ # Command handlers
271
+ bot.command("start") do |ctx|
272
+ ctx.reply("Welcome!")
273
+ end
274
+
275
+ bot.command("help") do |ctx|
276
+ ctx.reply("Available commands: /start, /help")
277
+ end
278
+
279
+ # Start webhook
280
+ server = bot.webhook
281
+
282
+ # Set webhook with Telegram
283
+ server.set_webhook(
284
+ max_connections: 40,
285
+ allowed_updates: ["message", "callback_query"]
286
+ )
287
+
288
+ puts "✅ Bot running with webhook: #{server.webhook_url}"
289
+ puts "🩺 Health check: #{server.webhook_url.gsub(/\/[^\/]+$/, '/health')}"
290
+
291
+ # Keep the script running
292
+ sleep while true
293
+ ```
294
+
295
+ Cloud Platform Setup (bot.rb):
296
+
297
+ ```ruby
298
+ #!/usr/bin/env ruby
299
+ require 'telegem'
300
+
301
+ bot = Telegem.new(ENV['TELEGRAM_BOT_TOKEN'])
302
+
303
+ # Add your command handlers here
304
+ bot.command("start") { |ctx| ctx.reply("Hello from cloud!") }
305
+
306
+ # Start webhook (auto-detects cloud mode)
307
+ server = bot.webhook
308
+
309
+ # Output the webhook URL
310
+ puts "Webhook URL: #{server.webhook_url}"
311
+
312
+ # Keep running
313
+ sleep while true
314
+ ```
315
+
316
+ 🚀 Deployment Checklist
317
+
318
+ Before deploying to production:
319
+
320
+ - SSL is configured (CLI, Cloud, or Manual)
321
+ - TELEGRAM_BOT_TOKEN is set
322
+ - WEBHOOK_SECRET_TOKEN is set (optional but recommended)
323
+ - TELEGEM_WEBHOOK_URL is set (for cloud platforms)
324
+ - Port is correctly configured (usually ENV['PORT'] on cloud)
325
+ - Health endpoint is responding (/health)
326
+ - Webhook is set with Telegram (server.set_webhook)
327
+
328
+ 📞 Getting Help
329
+
330
+ If you encounter issues:
331
+
332
+ 1. Check the logs: tail -f log/bot.log
333
+ 2. Verify SSL: curl https://your-domain.com/health
334
+ 3. Check Telegram webhook: server.get_webhook_info
335
+ 4. Enable debug logging: Logger.new($stdout, level: :debug)
336
+
337
+ For more help, visit the Telegem GitLab repository.
338
+
339
+ ---
340
+
341
+ Next Steps: After setting up your webhook, learn about Middleware, Scenes, and Advanced Features in the Telegem framework.
data/lib/api/client.rb CHANGED
@@ -14,7 +14,7 @@ module Telegem
14
14
  @logger = options[:logger] || Logger.new($stdout)
15
15
  timeout = options[:timeout] || 30
16
16
 
17
- @http = HTTPX.with(
17
+ @http = HTTPX.plugin(:callbacks).with(
18
18
  timeout: {
19
19
  request_timeout: timeout,
20
20
  connect_timeout: 10,
@@ -27,36 +27,81 @@ module Telegem
27
27
  }
28
28
  )
29
29
  end
30
-
31
30
  def call(method, params = {})
32
- url = "#{BASE_URL}/bot#{@token}/#{method}"
33
- @logger.debug("API Call: #{method}") if @logger
34
- @http.post(url, json: params.compact)
35
- end
36
-
37
- def call!(method, params = {})
38
- @mutex.synchronize do
39
- url = "#{BASE_URL}/bot#{@token}/#{method}"
40
-
41
- @logger.debug("API Call (sync): #{method}") if @logger
42
-
43
- begin
44
- response = @http.post(url, json: params.compact)
45
-
46
- if response.respond_to?(:status) && response.status == 200
47
- json = response.json
48
- return json['result'] if json && json['ok']
31
+ url = "#{BASE_URL}/bot#{@token}/#{method}"
32
+ @logger.debug("API Call: #{method}") if @logger
33
+
34
+ http_sync = HTTPX.with(
35
+ timeout: {
36
+ request_timeout: 30,
37
+ connect_timeout: 10,
38
+ write_timeout: 10,
39
+ read_timeout: 30
40
+ },
41
+ headers: {
42
+ 'Content-Type' => 'application/json',
43
+ 'User-Agent' => "Telegem/#{Telegem::VERSION}"
44
+ }
45
+ )
46
+
47
+ response = http_sync.post(url, json: params.compact).wait
48
+ response.json
49
+ end
50
+ def call!(method, params = {}, &callback)
51
+ url = "#{BASE_URL}/bot#{@token}/#{method}"
52
+
53
+ session = HTTPX.plugin(:callbacks).with(
54
+ timeout: {
55
+ request_timeout: 30,
56
+ connect_timeout: 10,
57
+ write_timeout: 10,
58
+ read_timeout: 30
59
+ },
60
+ headers: {
61
+ 'Content-Type' => 'application/json',
62
+ 'User-Agent' => "Telegem/#{Telegem::VERSION}"
63
+ }
64
+ )
65
+
66
+ # Set up the callbacks BEFORE making the request
67
+ if callback
68
+ session.on_response_completed do |request, response|
69
+ begin
70
+ if response.status == 200
71
+ json = response.json
72
+ if json && json['ok']
73
+ # Success: callback with result
74
+ callback.call(json['result'], nil)
75
+ @logger.debug("API Response: #{json}") if @logger
76
+ else
77
+ # API error (non-200 OK)
78
+ error_msg = json ? json['description'] : "No JSON response"
79
+ error_code = json['error_code'] if json
80
+ callback.call(nil, APIError.new("API Error: #{error_msg}", error_code))
49
81
  end
50
-
51
- @logger.error("API Error: HTTP #{response.status}") if response.respond_to?(:status) && @logger
52
- rescue => e
53
- @logger.error("Exception: #{e.message}") if @logger
82
+ else
83
+ # HTTP error
84
+ callback.call(nil, NetworkError.new("HTTP #{response.status}"))
54
85
  end
55
-
56
- nil
57
- end
86
+ rescue JSON::ParserError
87
+ callback.call(nil, NetworkError.new("Invalid JSON response"))
88
+ rescue => e
89
+ callback.call(nil, e)
58
90
  end
59
-
91
+ end
92
+
93
+ session.on_request_error do |request, error|
94
+ # Network/connection errors
95
+ callback.call(nil, error)
96
+ end
97
+ end
98
+
99
+ # Make the request and return immediately (async)
100
+ session.post(url, json: params.compact)
101
+
102
+ # Return the session if needed (optional)
103
+ # session
104
+ end
60
105
  def upload(method, params)
61
106
  url = "#{BASE_URL}/bot#{@token}/#{method}"
62
107