telegem 0.2.5 → 1.0.0
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/.replit +13 -0
- data/Contributing.md +553 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +11 -0
- data/LICENSE +21 -0
- data/Readme.md +353 -0
- data/Test-Projects/.gitkeep +0 -0
- data/Test-Projects/bot_test1.rb +75 -0
- data/Test-Projects/pizza_test_bot_guide.md +163 -0
- data/docs/.gitkeep +0 -0
- data/docs/Api.md +419 -0
- data/docs/Cookbook.md +407 -0
- data/docs/How_to_use.md +571 -0
- data/docs/QuickStart.md +258 -0
- data/docs/Usage.md +717 -0
- data/lib/api/client.rb +89 -116
- data/lib/core/bot.rb +103 -92
- data/lib/core/composer.rb +36 -18
- data/lib/core/context.rb +180 -177
- data/lib/core/scene.rb +81 -71
- data/lib/session/memory_store.rb +1 -1
- data/lib/session/middleware.rb +20 -36
- data/lib/telegem.rb +57 -54
- data/lib/webhook/.gitkeep +0 -0
- data/lib/webhook/server.rb +193 -0
- metadata +38 -35
- data/telegem.gemspec +0 -43
- data/webhook/server.rb +0 -86
data/lib/session/middleware.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# lib/session/middleware.rb - UPDATED
|
|
1
2
|
module Telegem
|
|
2
3
|
module Session
|
|
3
4
|
class Middleware
|
|
@@ -9,45 +10,28 @@ module Telegem
|
|
|
9
10
|
user_id = get_user_id(ctx)
|
|
10
11
|
return next_middleware.call(ctx) unless user_id
|
|
11
12
|
|
|
13
|
+
# Load session
|
|
12
14
|
ctx.session = @store.get(user_id) || {}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
|
|
16
|
+
# Run the chain
|
|
17
|
+
result = next_middleware.call(ctx)
|
|
18
|
+
|
|
19
|
+
# Save session (regardless of result)
|
|
20
|
+
@store.set(user_id, ctx.session)
|
|
21
|
+
|
|
22
|
+
# Return whatever the chain returned
|
|
23
|
+
result
|
|
24
|
+
rescue => e
|
|
25
|
+
# Save session even on error
|
|
26
|
+
@store.set(user_id, ctx.session) if user_id && ctx.session
|
|
27
|
+
raise e
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
private
|
|
23
|
-
|
|
31
|
+
|
|
24
32
|
def get_user_id(ctx)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ctx.from.id
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class MemoryStore
|
|
32
|
-
def initialize
|
|
33
|
-
@store = {}
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def get(key)
|
|
37
|
-
@store[key]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def set(key, value)
|
|
41
|
-
@store[key] = value
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def delete(key)
|
|
45
|
-
@store.delete(key)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def clear
|
|
49
|
-
@store.clear
|
|
33
|
+
ctx.from&.id
|
|
50
34
|
end
|
|
51
35
|
end
|
|
52
36
|
end
|
|
53
|
-
end
|
|
37
|
+
end
|
data/lib/telegem.rb
CHANGED
|
@@ -1,54 +1,9 @@
|
|
|
1
|
-
# lib/telegem.rb
|
|
2
|
-
require "async"
|
|
3
|
-
require "async/http"
|
|
4
|
-
require "mime/types"
|
|
5
|
-
require 'logger'
|
|
6
|
-
require 'json'
|
|
7
|
-
|
|
1
|
+
# lib/telegem.rb - MAIN ENTRY POINT
|
|
8
2
|
module Telegem
|
|
9
|
-
VERSION =
|
|
10
|
-
|
|
11
|
-
# Define module structure
|
|
12
|
-
module API; end
|
|
13
|
-
module Core; end
|
|
14
|
-
module Session; end
|
|
15
|
-
module Markup; end
|
|
16
|
-
module Webhook; end
|
|
17
|
-
module Types; end
|
|
18
|
-
|
|
19
|
-
# Shortcut for creating a new bot
|
|
20
|
-
def self.new(token, **options)
|
|
21
|
-
Core::Bot.new(token, **options)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Configure global settings
|
|
25
|
-
def self.configure(&block)
|
|
26
|
-
yield(config) if block_given?
|
|
27
|
-
config
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.config
|
|
31
|
-
@config ||= Configuration.new
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
class Configuration
|
|
35
|
-
attr_accessor :logger, :default_adapter, :default_concurrency,
|
|
36
|
-
:default_session_store, :default_webhook_port
|
|
37
|
-
|
|
38
|
-
def initialize
|
|
39
|
-
@logger = Logger.new($stdout)
|
|
40
|
-
@default_adapter = :async_http
|
|
41
|
-
@default_concurrency = 10
|
|
42
|
-
@default_session_store = :memory
|
|
43
|
-
@default_webhook_port = 3000
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Error base class
|
|
48
|
-
class Error < StandardError; end
|
|
3
|
+
VERSION = "1.0.0".freeze
|
|
49
4
|
end
|
|
50
5
|
|
|
51
|
-
# Load
|
|
6
|
+
# Load core components
|
|
52
7
|
require_relative 'api/client'
|
|
53
8
|
require_relative 'api/types'
|
|
54
9
|
require_relative 'core/bot'
|
|
@@ -58,11 +13,59 @@ require_relative 'core/scene'
|
|
|
58
13
|
require_relative 'session/middleware'
|
|
59
14
|
require_relative 'session/memory_store'
|
|
60
15
|
require_relative 'markup/keyboard'
|
|
16
|
+
require_relative 'webhook/server'
|
|
17
|
+
|
|
18
|
+
module Telegem
|
|
19
|
+
# Main entry point: Telegem.new(token)
|
|
20
|
+
def self.new(token, **options)
|
|
21
|
+
Core::Bot.new(token, **options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Shortcut for creating keyboards
|
|
25
|
+
def self.keyboard(&block)
|
|
26
|
+
Markup.keyboard(&block)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.inline(&block)
|
|
30
|
+
Markup.inline(&block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Remove keyboard markup
|
|
34
|
+
def self.remove_keyboard(**options)
|
|
35
|
+
Markup.remove(**options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Force reply markup
|
|
39
|
+
def self.force_reply(**options)
|
|
40
|
+
Markup.force_reply(**options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Current version
|
|
44
|
+
def self.version
|
|
45
|
+
VERSION
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Framework information
|
|
49
|
+
def self.info
|
|
50
|
+
<<~INFO
|
|
51
|
+
🤖 Telegem #{VERSION}
|
|
52
|
+
Modern Telegram Bot Framework for Ruby
|
|
53
|
+
|
|
54
|
+
Features:
|
|
55
|
+
• Async HTTPX-based API client
|
|
56
|
+
• Scene system for multi-step conversations
|
|
57
|
+
• Express.js-style middleware
|
|
58
|
+
• Clean Telegraf.js-inspired DSL
|
|
59
|
+
• Webhook and polling support
|
|
60
|
+
• Built-in session management
|
|
61
|
+
• Fluent keyboard DSL
|
|
62
|
+
|
|
63
|
+
Website: https://gitlab.com/ruby-telegem/telegem
|
|
64
|
+
INFO
|
|
65
|
+
end
|
|
66
|
+
end
|
|
61
67
|
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
rescue LoadError
|
|
66
|
-
# Try root webhook directory
|
|
67
|
-
require_relative '../webhook/server'
|
|
68
|
+
# Also define a top-level shortcut for convenience
|
|
69
|
+
def Telegem(token, **options)
|
|
70
|
+
Telegem.new(token, **options)
|
|
68
71
|
end
|
|
File without changes
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# lib/webhook/server.rb - HTTPX VERSION
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'webrick'
|
|
4
|
+
|
|
5
|
+
module Telegem
|
|
6
|
+
module Webhook
|
|
7
|
+
class Server
|
|
8
|
+
attr_reader :bot, :port, :host, :logger, :server, :running
|
|
9
|
+
|
|
10
|
+
def initialize(bot, port: 3000, host: '0.0.0.0', logger: nil)
|
|
11
|
+
@bot = bot
|
|
12
|
+
@port = port
|
|
13
|
+
@host = host
|
|
14
|
+
@logger = logger || Logger.new($stdout)
|
|
15
|
+
@server = nil
|
|
16
|
+
@running = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
return if @running
|
|
21
|
+
|
|
22
|
+
@logger.info "🚀 Starting Telegem webhook server on #{@host}:#{@port}"
|
|
23
|
+
@logger.info "📝 Set your Telegram webhook to: #{webhook_url}"
|
|
24
|
+
|
|
25
|
+
@running = true
|
|
26
|
+
|
|
27
|
+
@server_thread = Thread.new do
|
|
28
|
+
begin
|
|
29
|
+
# Create WEBrick server
|
|
30
|
+
@server = WEBrick::HTTPServer.new(
|
|
31
|
+
Port: @port,
|
|
32
|
+
BindAddress: @host,
|
|
33
|
+
Logger: @logger,
|
|
34
|
+
AccessLog: []
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Mount the webhook endpoint
|
|
38
|
+
@server.mount_proc("/webhook/#{@bot.token}") do |req, res|
|
|
39
|
+
handle_webhook_request(req, res)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Mount health check
|
|
43
|
+
@server.mount_proc('/health') do |req, res|
|
|
44
|
+
res.status = 200
|
|
45
|
+
res.content_type = 'text/plain'
|
|
46
|
+
res.body = 'OK'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Mount root
|
|
50
|
+
@server.mount_proc('/') do |req, res|
|
|
51
|
+
res.status = 200
|
|
52
|
+
res.content_type = 'text/html'
|
|
53
|
+
res.body = <<~HTML
|
|
54
|
+
<html>
|
|
55
|
+
<head><title>Telegem Webhook Server</title></head>
|
|
56
|
+
<body>
|
|
57
|
+
<h1>Telegem Webhook Server</h1>
|
|
58
|
+
<p>Webhook URL: <code>#{webhook_url}</code></p>
|
|
59
|
+
<p>Status: <span style="color: green;">Running</span></p>
|
|
60
|
+
<p><a href="/health">Health Check</a></p>
|
|
61
|
+
</body>
|
|
62
|
+
</html>
|
|
63
|
+
HTML
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Handle shutdown signals
|
|
67
|
+
['INT', 'TERM'].each do |signal|
|
|
68
|
+
Signal.trap(signal) { shutdown }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Start the server
|
|
72
|
+
@server.start
|
|
73
|
+
|
|
74
|
+
rescue => e
|
|
75
|
+
@logger.error "❌ Webhook server error: #{e.class}: #{e.message}"
|
|
76
|
+
@logger.error e.backtrace.join("\n") if e.backtrace
|
|
77
|
+
raise
|
|
78
|
+
ensure
|
|
79
|
+
@running = false
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def stop
|
|
87
|
+
return unless @running
|
|
88
|
+
|
|
89
|
+
@logger.info "🛑 Stopping webhook server..."
|
|
90
|
+
@running = false
|
|
91
|
+
|
|
92
|
+
# Stop WEBrick server
|
|
93
|
+
@server&.shutdown
|
|
94
|
+
|
|
95
|
+
# Wait for server thread
|
|
96
|
+
@server_thread&.join(5)
|
|
97
|
+
|
|
98
|
+
@logger.info "✅ Webhook server stopped"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
alias_method :shutdown, :stop
|
|
102
|
+
|
|
103
|
+
def running?
|
|
104
|
+
@running
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def webhook_url
|
|
108
|
+
base_url = ENV['WEBHOOK_URL'] || "http://#{@host}:#{@port}"
|
|
109
|
+
"#{base_url}/webhook/#{@bot.token}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def handle_webhook_request(req, res)
|
|
115
|
+
# Only accept POST requests
|
|
116
|
+
unless req.request_method == 'POST'
|
|
117
|
+
res.status = 405
|
|
118
|
+
res.content_type = 'text/plain'
|
|
119
|
+
res.body = 'Method Not Allowed'
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
begin
|
|
124
|
+
# Parse the update
|
|
125
|
+
body = req.body.read
|
|
126
|
+
update_data = JSON.parse(body)
|
|
127
|
+
|
|
128
|
+
# Process the update in a separate thread to keep response fast
|
|
129
|
+
Thread.new do
|
|
130
|
+
begin
|
|
131
|
+
@bot.process(update_data)
|
|
132
|
+
rescue => e
|
|
133
|
+
@logger.error "Error processing update: #{e.message}"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Immediate response to Telegram
|
|
138
|
+
res.status = 200
|
|
139
|
+
res.content_type = 'text/plain'
|
|
140
|
+
res.body = 'OK'
|
|
141
|
+
|
|
142
|
+
rescue JSON::ParserError => e
|
|
143
|
+
@logger.error "Invalid JSON in webhook request: #{e.message}"
|
|
144
|
+
res.status = 400
|
|
145
|
+
res.content_type = 'text/plain'
|
|
146
|
+
res.body = 'Bad Request'
|
|
147
|
+
rescue => e
|
|
148
|
+
@logger.error "Error handling webhook: #{e.class}: #{e.message}"
|
|
149
|
+
res.status = 500
|
|
150
|
+
res.content_type = 'text/plain'
|
|
151
|
+
res.body = 'Internal Server Error'
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Middleware for Rack apps (Rails, Sinatra, etc.)
|
|
157
|
+
class Middleware
|
|
158
|
+
def initialize(app, bot)
|
|
159
|
+
@app = app
|
|
160
|
+
@bot = bot
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def call(env)
|
|
164
|
+
req = Rack::Request.new(env)
|
|
165
|
+
|
|
166
|
+
# Check if this is a webhook request
|
|
167
|
+
if req.post? && req.path == "/webhook/#{@bot.token}"
|
|
168
|
+
handle_webhook(req)
|
|
169
|
+
else
|
|
170
|
+
@app.call(env)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
def handle_webhook(req)
|
|
177
|
+
begin
|
|
178
|
+
update_data = JSON.parse(req.body.read)
|
|
179
|
+
|
|
180
|
+
# Process async in background
|
|
181
|
+
Thread.new { @bot.process(update_data) }
|
|
182
|
+
|
|
183
|
+
[200, { 'Content-Type' => 'text/plain' }, ['OK']]
|
|
184
|
+
rescue JSON::ParserError
|
|
185
|
+
[400, { 'Content-Type' => 'text/plain' }, ['Bad Request']]
|
|
186
|
+
rescue => e
|
|
187
|
+
@bot.logger.error("Webhook error: #{e.message}") if @bot.logger
|
|
188
|
+
[500, { 'Content-Type' => 'text/plain' }, ['Internal Server Error']]
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
metadata
CHANGED
|
@@ -1,91 +1,93 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: telegem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
8
|
-
bindir:
|
|
7
|
+
- Your Name
|
|
8
|
+
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name:
|
|
13
|
+
name: httpx
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 0.24.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 0.24.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0.60'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0.60'
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: mime-types
|
|
27
|
+
name: rake
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
43
29
|
requirements:
|
|
44
30
|
- - "~>"
|
|
45
31
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
47
|
-
type: :
|
|
32
|
+
version: '13.0'
|
|
33
|
+
type: :development
|
|
48
34
|
prerelease: false
|
|
49
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
36
|
requirements:
|
|
51
37
|
- - "~>"
|
|
52
38
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
39
|
+
version: '13.0'
|
|
54
40
|
- !ruby/object:Gem::Dependency
|
|
55
|
-
name:
|
|
41
|
+
name: rspec
|
|
56
42
|
requirement: !ruby/object:Gem::Requirement
|
|
57
43
|
requirements:
|
|
58
44
|
- - "~>"
|
|
59
45
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '
|
|
46
|
+
version: '3.0'
|
|
61
47
|
type: :development
|
|
62
48
|
prerelease: false
|
|
63
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
50
|
requirements:
|
|
65
51
|
- - "~>"
|
|
66
52
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '
|
|
53
|
+
version: '3.0'
|
|
68
54
|
- !ruby/object:Gem::Dependency
|
|
69
|
-
name:
|
|
55
|
+
name: pry
|
|
70
56
|
requirement: !ruby/object:Gem::Requirement
|
|
71
57
|
requirements:
|
|
72
58
|
- - "~>"
|
|
73
59
|
- !ruby/object:Gem::Version
|
|
74
|
-
version:
|
|
60
|
+
version: 0.14.0
|
|
75
61
|
type: :development
|
|
76
62
|
prerelease: false
|
|
77
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
64
|
requirements:
|
|
79
65
|
- - "~>"
|
|
80
66
|
- !ruby/object:Gem::Version
|
|
81
|
-
version:
|
|
82
|
-
description:
|
|
67
|
+
version: 0.14.0
|
|
68
|
+
description: Blazing-fast Telegram Bot framework with true async/await patterns, inspired
|
|
69
|
+
by Telegraf.js
|
|
83
70
|
email:
|
|
84
|
-
-
|
|
71
|
+
- your-email@example.com
|
|
85
72
|
executables: []
|
|
86
73
|
extensions: []
|
|
87
74
|
extra_rdoc_files: []
|
|
88
75
|
files:
|
|
76
|
+
- ".replit"
|
|
77
|
+
- Contributing.md
|
|
78
|
+
- Gemfile
|
|
79
|
+
- Gemfile.lock
|
|
80
|
+
- LICENSE
|
|
81
|
+
- Readme.md
|
|
82
|
+
- Test-Projects/.gitkeep
|
|
83
|
+
- Test-Projects/bot_test1.rb
|
|
84
|
+
- Test-Projects/pizza_test_bot_guide.md
|
|
85
|
+
- docs/.gitkeep
|
|
86
|
+
- docs/Api.md
|
|
87
|
+
- docs/Cookbook.md
|
|
88
|
+
- docs/How_to_use.md
|
|
89
|
+
- docs/QuickStart.md
|
|
90
|
+
- docs/Usage.md
|
|
89
91
|
- lib/api/client.rb
|
|
90
92
|
- lib/api/types.rb
|
|
91
93
|
- lib/core/bot.rb
|
|
@@ -96,8 +98,8 @@ files:
|
|
|
96
98
|
- lib/session/memory_store.rb
|
|
97
99
|
- lib/session/middleware.rb
|
|
98
100
|
- lib/telegem.rb
|
|
99
|
-
-
|
|
100
|
-
- webhook/server.rb
|
|
101
|
+
- lib/webhook/.gitkeep
|
|
102
|
+
- lib/webhook/server.rb
|
|
101
103
|
homepage: https://gitlab.com/ruby-telegem/telegem
|
|
102
104
|
licenses:
|
|
103
105
|
- MIT
|
|
@@ -105,6 +107,7 @@ metadata:
|
|
|
105
107
|
homepage_uri: https://gitlab.com/ruby-telegem/telegem
|
|
106
108
|
source_code_uri: https://gitlab.com/ruby-telegem/telegem
|
|
107
109
|
changelog_uri: https://gitlab.com/ruby-telegem/telegem/-/blob/main/CHANGELOG.md
|
|
110
|
+
documentation_uri: https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs
|
|
108
111
|
rdoc_options: []
|
|
109
112
|
require_paths:
|
|
110
113
|
- lib
|
|
@@ -112,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
112
115
|
requirements:
|
|
113
116
|
- - ">="
|
|
114
117
|
- !ruby/object:Gem::Version
|
|
115
|
-
version:
|
|
118
|
+
version: 2.7.0
|
|
116
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
120
|
requirements:
|
|
118
121
|
- - ">="
|
data/telegem.gemspec
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# telegem.gemspec
|
|
2
|
-
Gem::Specification.new do |spec|
|
|
3
|
-
spec.name = "telegem"
|
|
4
|
-
|
|
5
|
-
# Read version from lib/telegem.rb
|
|
6
|
-
version_file = File.read('lib/telegem.rb').match(/VERSION\s*=\s*['"]([^'"]+)['"]/)
|
|
7
|
-
spec.version = version_file ? version_file[1] : "0.2.5"
|
|
8
|
-
|
|
9
|
-
spec.authors = ["Phantom"]
|
|
10
|
-
spec.email = ["ynghosted@icloud.com"]
|
|
11
|
-
|
|
12
|
-
spec.summary = "Modern, async Telegram Bot API for Ruby"
|
|
13
|
-
spec.description = "A Telegraf-inspired Telegram Bot framework with async I/O"
|
|
14
|
-
spec.homepage = "https://gitlab.com/ruby-telegem/telegem"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
spec.required_ruby_version = ">= 3.0"
|
|
17
|
-
|
|
18
|
-
# Include all necessary files
|
|
19
|
-
spec.files = Dir[
|
|
20
|
-
"lib/**/*.rb", # All Ruby files in lib/
|
|
21
|
-
"webhook/**/*.rb", # Webhook files (if in root)
|
|
22
|
-
"README.md",
|
|
23
|
-
"LICENSE.txt",
|
|
24
|
-
"CHANGELOG.md",
|
|
25
|
-
"*.gemspec"
|
|
26
|
-
].select { |f| File.exist?(f) }
|
|
27
|
-
|
|
28
|
-
# This tells RubyGems to look in lib/ when requiring
|
|
29
|
-
spec.require_paths = ["lib"]
|
|
30
|
-
|
|
31
|
-
spec.metadata = {
|
|
32
|
-
"homepage_uri" => "https://gitlab.com/ruby-telegem/telegem",
|
|
33
|
-
"source_code_uri" => "https://gitlab.com/ruby-telegem/telegem",
|
|
34
|
-
"changelog_uri" => "https://gitlab.com/ruby-telegem/telegem/-/blob/main/CHANGELOG.md"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
spec.add_dependency "async", "~> 2.0"
|
|
38
|
-
spec.add_dependency "async-http", "~> 0.60"
|
|
39
|
-
spec.add_dependency "mime-types", "~> 3.4"
|
|
40
|
-
|
|
41
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
|
42
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
|
43
|
-
end
|
data/webhook/server.rb
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
module Telegem
|
|
2
|
-
module Webhook
|
|
3
|
-
class Server
|
|
4
|
-
attr_reader :bot, :endpoint, :server, :logger
|
|
5
|
-
|
|
6
|
-
def initialize(bot, endpoint: nil, logger: nil)
|
|
7
|
-
@bot = bot
|
|
8
|
-
@endpoint = endpoint || Async::HTTP::Endpoint.parse("http://0.0.0.0:3000")
|
|
9
|
-
@logger = logger || Logger.new($stdout)
|
|
10
|
-
@server = nil
|
|
11
|
-
@running = false
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def run
|
|
15
|
-
Async do |task|
|
|
16
|
-
@server = Async::HTTP::Server.new(app, @endpoint)
|
|
17
|
-
@running = true
|
|
18
|
-
|
|
19
|
-
@logger.info "Starting webhook server on #{@endpoint}"
|
|
20
|
-
@logger.info "Set your Telegram webhook to: #{webhook_url}"
|
|
21
|
-
|
|
22
|
-
@server.run
|
|
23
|
-
rescue => e
|
|
24
|
-
@logger.error "Webhook server error: #{e.message}"
|
|
25
|
-
raise
|
|
26
|
-
ensure
|
|
27
|
-
@running = false
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def stop
|
|
32
|
-
Async do
|
|
33
|
-
@server&.close
|
|
34
|
-
@running = false
|
|
35
|
-
@logger.info "Webhook server stopped"
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def running?
|
|
40
|
-
@running
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def webhook_url
|
|
44
|
-
"#{@endpoint.url}/webhook/#{@bot.token}"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def app
|
|
48
|
-
proc do |req|
|
|
49
|
-
handle_request(req)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def process_webhook_request(req)
|
|
54
|
-
Async do
|
|
55
|
-
body = req.body.read
|
|
56
|
-
data = JSON.parse(body)
|
|
57
|
-
await @bot.process(data)
|
|
58
|
-
[200, {}, ["OK"]]
|
|
59
|
-
rescue JSON::ParserError => e
|
|
60
|
-
@logger.error "Invalid JSON in webhook request: #{e.message}"
|
|
61
|
-
[400, {}, ["Bad Request"]]
|
|
62
|
-
rescue => e
|
|
63
|
-
@logger.error "Error processing webhook request: #{e.message}"
|
|
64
|
-
[500, {}, ["Internal Server Error"]]
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def handle_request(req)
|
|
69
|
-
Async do
|
|
70
|
-
case req.path
|
|
71
|
-
when "/webhook/#{@bot.token}"
|
|
72
|
-
process_webhook_request(req)
|
|
73
|
-
when "/health"
|
|
74
|
-
[200, {}, ["OK"]]
|
|
75
|
-
else
|
|
76
|
-
[404, {}, ["Not Found"]]
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def call(req)
|
|
82
|
-
handle_request(req)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|