telegram-support-bot 0.1.09 → 0.1.10
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/.idea/workspace.xml +47 -30
- data/CHANGELOG.md +13 -0
- data/README.md +45 -1
- data/lib/telegram_support_bot/state_store.rb +22 -2
- data/lib/telegram_support_bot/version.rb +1 -1
- data/lib/telegram_support_bot.rb +120 -45
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9263ca971ffb1e1bb24ae8bc23342c4596748573e7b694485173e14dd2d82d44
|
|
4
|
+
data.tar.gz: fce5aa69e55343db503d12779a3b66b4f2caabd407f18b1e6668532d1abf9bbb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60ab56248d3f245ab2aa8530f8b6c2254003e881c08f632d75e81648cafa0273d35c9cb35cd4d2aece9ec567de0e5effae6ef97205f578cc931695bfa01b1769
|
|
7
|
+
data.tar.gz: 2e6f1fa2f22a606cc418a2f3f054cc38a7565093d4187c609333583ca22db00c77b9f313f3f45aa0dac6eb5877d1386de91f2ba72730e3bab3caf5fdb9d2294f
|
data/.idea/workspace.xml
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
5
|
</component>
|
|
6
6
|
<component name="ChangeListManager">
|
|
7
|
-
<list default="true" id="edf498b0-8552-42f1-846d-0c79d29ff991" name="Changes" comment=""
|
|
8
|
-
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
9
|
-
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
10
|
-
</list>
|
|
7
|
+
<list default="true" id="edf498b0-8552-42f1-846d-0c79d29ff991" name="Changes" comment="" />
|
|
11
8
|
<option name="SHOW_DIALOG" value="false" />
|
|
12
9
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
13
10
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
14
11
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
15
12
|
</component>
|
|
13
|
+
<component name="EmbeddingIndexingInfo">
|
|
14
|
+
<option name="cachedIndexableFilesCount" value="26" />
|
|
15
|
+
</component>
|
|
16
16
|
<component name="FileTemplateManagerImpl">
|
|
17
17
|
<option name="RECENT_TEMPLATES">
|
|
18
18
|
<list>
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
<component name="MarkdownSettingsMigration">
|
|
27
27
|
<option name="stateVersion" value="1" />
|
|
28
28
|
</component>
|
|
29
|
+
<component name="McpProjectServerCommands">
|
|
30
|
+
<commands />
|
|
31
|
+
<urls />
|
|
32
|
+
</component>
|
|
29
33
|
<component name="ProjectColorInfo">{
|
|
30
34
|
"associatedIndex": 4
|
|
31
35
|
}</component>
|
|
@@ -37,30 +41,38 @@
|
|
|
37
41
|
<option name="hideEmptyMiddlePackages" value="true" />
|
|
38
42
|
<option name="showLibraryContents" value="true" />
|
|
39
43
|
</component>
|
|
40
|
-
<component name="PropertiesComponent"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
<component name="PropertiesComponent"><![CDATA[{
|
|
45
|
+
"keyToString": {
|
|
46
|
+
"DefaultRubyCreateTestTemplate": "Minitest Spec",
|
|
47
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
48
|
+
"RSpec.Unnamed.executor": "Run",
|
|
49
|
+
"Ruby.scratch_61.executor": "Run",
|
|
50
|
+
"RunOnceActivity.MCP Project settings loaded": "true",
|
|
51
|
+
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
52
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
53
|
+
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
|
54
|
+
"RunOnceActivity.git.unshallow": "true",
|
|
55
|
+
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
56
|
+
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
|
|
57
|
+
"git-widget-placeholder": "main",
|
|
58
|
+
"junie.onboarding.icon.badge.shown": "true",
|
|
59
|
+
"last_opened_file_path": "/Users/max/code/gems/telegram_support_bot",
|
|
60
|
+
"node.js.detected.package.eslint": "true",
|
|
61
|
+
"node.js.detected.package.tslint": "true",
|
|
62
|
+
"node.js.selected.package.eslint": "(autodetect)",
|
|
63
|
+
"node.js.selected.package.tslint": "(autodetect)",
|
|
64
|
+
"nodejs_package_manager_path": "npm",
|
|
65
|
+
"ruby.structure.view.model.defaults.configured": "true",
|
|
66
|
+
"settings.editor.selected.configurable": "org.jetbrains.plugins.ruby.settings.RubyActiveModuleSdkConfigurable",
|
|
67
|
+
"to.speed.mode.migration.done": "true",
|
|
68
|
+
"vue.rearranger.settings.migration": "true"
|
|
57
69
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
"keyToStringList": {
|
|
71
|
+
"com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File": [
|
|
72
|
+
"ruby"
|
|
61
73
|
]
|
|
62
74
|
}
|
|
63
|
-
}
|
|
75
|
+
}]]></component>
|
|
64
76
|
<component name="RecentsManager">
|
|
65
77
|
<key name="CopyFile.RECENT_KEYS">
|
|
66
78
|
<recent name="$PROJECT_DIR$/spec/telegram_support_bot/adapters" />
|
|
@@ -80,11 +92,7 @@
|
|
|
80
92
|
<RSPEC_RUN_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
|
|
81
93
|
<RSPEC_RUN_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
|
|
82
94
|
<EXTENSION ID="BundlerRunConfigurationExtension" BUNDLE_MODE="AUTO" bundleExecEnabled="true" />
|
|
83
|
-
<EXTENSION ID="RubyCoverageRunConfigurationExtension"
|
|
84
|
-
<COVERAGE_PATTERN ENABLED="true">
|
|
85
|
-
<PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
|
|
86
|
-
</COVERAGE_PATTERN>
|
|
87
|
-
</EXTENSION>
|
|
95
|
+
<EXTENSION ID="RubyCoverageRunConfigurationExtension" runner="rcov" />
|
|
88
96
|
<EXTENSION ID="org.jetbrains.plugins.ruby.rails.run.RailsRunConfigurationExtension" SCRATCH_USE_RAILS_RUNNER="false" />
|
|
89
97
|
<RSPEC_RUN_CONFIG_SETTINGS_ID NAME="TESTS_FOLDER_PATH" VALUE="$MODULE_DIR$/spec" />
|
|
90
98
|
<RSPEC_RUN_CONFIG_SETTINGS_ID NAME="TEST_SCRIPT_PATH" VALUE="" />
|
|
@@ -111,6 +119,7 @@
|
|
|
111
119
|
<RUBY_RUN_CONFIG NAME="ALTERN_SDK_NAME" VALUE="" />
|
|
112
120
|
<RUBY_RUN_CONFIG NAME="myPassParentEnvs" VALUE="true" />
|
|
113
121
|
<EXTENSION ID="BundlerRunConfigurationExtension" BUNDLE_MODE="AUTO" bundleExecEnabled="true" />
|
|
122
|
+
<EXTENSION ID="RubyCoverageRunConfigurationExtension" runner="rcov" />
|
|
114
123
|
<EXTENSION ID="org.jetbrains.plugins.ruby.rails.run.RailsRunConfigurationExtension" SCRATCH_USE_RAILS_RUNNER="false" />
|
|
115
124
|
<RUBY_RUN_CONFIG NAME="SCRIPT_PATH" VALUE="$APPLICATION_CONFIG_DIR$/scratches/scratch_61.rb" />
|
|
116
125
|
<RUBY_RUN_CONFIG NAME="SCRIPT_ARGS" VALUE="" />
|
|
@@ -126,6 +135,13 @@
|
|
|
126
135
|
</list>
|
|
127
136
|
</recent_temporary>
|
|
128
137
|
</component>
|
|
138
|
+
<component name="SharedIndexes">
|
|
139
|
+
<attachedChunks>
|
|
140
|
+
<set>
|
|
141
|
+
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-RM-253.30387.79" />
|
|
142
|
+
</set>
|
|
143
|
+
</attachedChunks>
|
|
144
|
+
</component>
|
|
129
145
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
130
146
|
<component name="SpringUtil" SPRING_PRE_LOADER_OPTION="true" RAKE_SPRING_PRE_LOADER_OPTION="true" RAILS_SPRING_PRE_LOADER_OPTION="true" />
|
|
131
147
|
<component name="TaskManager">
|
|
@@ -141,6 +157,7 @@
|
|
|
141
157
|
<workItem from="1708944249622" duration="627000" />
|
|
142
158
|
<workItem from="1708949675518" duration="80000" />
|
|
143
159
|
<workItem from="1708951183744" duration="310000" />
|
|
160
|
+
<workItem from="1770972800781" duration="13916000" />
|
|
144
161
|
</task>
|
|
145
162
|
<servers />
|
|
146
163
|
</component>
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.10] - 2026-02-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Multi-bot runtime support in one process with keyed configuration and processing:
|
|
11
|
+
`configure(:bot_key)` and `process_update(update, bot: :bot_key)`.
|
|
12
|
+
- Bot-scoped adapter/state-store/scheduler instances to isolate mappings, reactions, and user profiles per bot key.
|
|
13
|
+
- Redis state namespace isolation for non-default bot keys.
|
|
14
|
+
- Multi-bot isolation test coverage for message mappings, support chat routing, contact profiles, and Redis namespaces.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Backward compatibility preserved: no-arg `configure` and `process_update` continue using `:default`.
|
|
18
|
+
- Development dependency resolution now has Ruby-version-aware constraints for older runtimes.
|
|
19
|
+
|
|
7
20
|
## [0.1.09] - 2026-02-13
|
|
8
21
|
|
|
9
22
|
### Added
|
data/README.md
CHANGED
|
@@ -27,7 +27,7 @@ gem 'telegram-support-bot'
|
|
|
27
27
|
|
|
28
28
|
1. **Create Your Bot** via BotFather on Telegram to get your bot token.
|
|
29
29
|
2. **Deploy Your Application** and set up a controller action for webhook callbacks, directing them
|
|
30
|
-
to `TelegramSupportBot.process_update
|
|
30
|
+
to `TelegramSupportBot.process_update` (or `TelegramSupportBot.process_update(update, bot: :your_key)` for keyed bots).
|
|
31
31
|
3. **Set the Webhook URL** using the Telegram Bot API to your controller action.
|
|
32
32
|
|
|
33
33
|
### Setting Up Your Telegram Bot
|
|
@@ -60,6 +60,50 @@ TelegramSupportBot.configure do |config|
|
|
|
60
60
|
end
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Multiple Bots In One Process
|
|
64
|
+
|
|
65
|
+
Use keyed configuration when one app process serves multiple Telegram bots/chats:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
TelegramSupportBot.configure(:default) do |config|
|
|
69
|
+
config.adapter_options = { token: ENV.fetch('TELEGRAM_DEFAULT_TOKEN') }
|
|
70
|
+
config.support_chat_id = ENV.fetch('TELEGRAM_DEFAULT_SUPPORT_CHAT_ID')
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
TelegramSupportBot.configure(:partners) do |config|
|
|
74
|
+
config.adapter_options = { token: ENV.fetch('TELEGRAM_PARTNERS_TOKEN') }
|
|
75
|
+
config.support_chat_id = ENV.fetch('TELEGRAM_PARTNERS_SUPPORT_CHAT_ID')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Route incoming webhook to the matching bot key:
|
|
79
|
+
TelegramSupportBot.process_update(update, bot: :partners)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Backward compatibility is preserved:
|
|
83
|
+
- `TelegramSupportBot.configure { ... }` configures `:default`
|
|
84
|
+
- `TelegramSupportBot.process_update(update)` processes with `:default`
|
|
85
|
+
|
|
86
|
+
Typical webhook routing in Rails:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# legacy/default bot
|
|
90
|
+
post '/v2/telegram/support' => 'api/v2/telegram#support'
|
|
91
|
+
# keyed bot
|
|
92
|
+
post '/v2/telegram/:bot_key/support' => 'api/v2/telegram#support'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
def support
|
|
97
|
+
update = JSON.parse(request.body.read)
|
|
98
|
+
bot_key = params[:bot_key].presence&.to_sym || :default
|
|
99
|
+
TelegramSupportBot.process_update(update, bot: bot_key)
|
|
100
|
+
head :ok
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
When using Redis state store, non-default bot keys are namespaced automatically
|
|
105
|
+
(`telegram_support_bot:<bot_key>:...`) so mappings/profiles do not leak across bots.
|
|
106
|
+
|
|
63
107
|
3. **Interact with Users**: Messages to your bot will be forwarded to the support chat, and replies
|
|
64
108
|
in the chat will be sent back to the users.
|
|
65
109
|
|
|
@@ -27,9 +27,9 @@ module TelegramSupportBot
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def self.build(configuration)
|
|
30
|
+
def self.build(configuration, bot_key: TelegramSupportBot::DEFAULT_BOT_KEY)
|
|
31
31
|
backend = configuration.state_store.to_sym
|
|
32
|
-
options = configuration.state_store_options
|
|
32
|
+
options = normalize_options(configuration.state_store_options)
|
|
33
33
|
|
|
34
34
|
case backend
|
|
35
35
|
when :memory
|
|
@@ -41,6 +41,7 @@ module TelegramSupportBot
|
|
|
41
41
|
)
|
|
42
42
|
when :redis
|
|
43
43
|
require_relative 'state_stores/redis'
|
|
44
|
+
options = isolate_redis_namespace(options, bot_key)
|
|
44
45
|
StateStores::Redis.new(
|
|
45
46
|
mapping_ttl_seconds: configuration.mapping_ttl_seconds,
|
|
46
47
|
reaction_count_ttl_seconds: configuration.reaction_count_ttl_seconds,
|
|
@@ -51,6 +52,25 @@ module TelegramSupportBot
|
|
|
51
52
|
raise ArgumentError, "Unsupported state store backend: #{backend}"
|
|
52
53
|
end
|
|
53
54
|
end
|
|
55
|
+
|
|
56
|
+
def self.normalize_options(options)
|
|
57
|
+
(options || {}).each_with_object({}) do |(key, value), memo|
|
|
58
|
+
memo[key.to_sym] = value
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
private_class_method :normalize_options
|
|
62
|
+
|
|
63
|
+
def self.isolate_redis_namespace(options, bot_key)
|
|
64
|
+
normalized_bot_key = (bot_key || TelegramSupportBot::DEFAULT_BOT_KEY).to_sym
|
|
65
|
+
return options if normalized_bot_key == TelegramSupportBot::DEFAULT_BOT_KEY
|
|
66
|
+
|
|
67
|
+
base_namespace = options[:namespace] || StateStores::Redis::DEFAULT_NAMESPACE
|
|
68
|
+
suffix = ":#{normalized_bot_key}"
|
|
69
|
+
namespaced = base_namespace.to_s.end_with?(suffix) ? base_namespace.to_s : "#{base_namespace}#{suffix}"
|
|
70
|
+
|
|
71
|
+
options.merge(namespace: namespaced)
|
|
72
|
+
end
|
|
73
|
+
private_class_method :isolate_redis_namespace
|
|
54
74
|
end
|
|
55
75
|
end
|
|
56
76
|
|
data/lib/telegram_support_bot.rb
CHANGED
|
@@ -10,70 +10,153 @@ require_relative 'telegram_support_bot/adapters/telegram_bot'
|
|
|
10
10
|
require_relative 'telegram_support_bot/adapters/telegram_bot_ruby'
|
|
11
11
|
|
|
12
12
|
module TelegramSupportBot
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
DEFAULT_BOT_KEY = :default
|
|
14
|
+
BOT_CONTEXT_THREAD_KEY = :telegram_support_bot_current_bot_key
|
|
15
15
|
|
|
16
|
+
class << self
|
|
16
17
|
# Provides a method to configure the gem.
|
|
17
|
-
def configure
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
def configure(bot_key = DEFAULT_BOT_KEY)
|
|
19
|
+
key = normalize_bot_key(bot_key)
|
|
20
|
+
config = configuration(key)
|
|
21
|
+
yield(config) if block_given?
|
|
22
|
+
config
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configuration(bot_key = nil)
|
|
26
|
+
key = bot_key.nil? ? current_bot_key : normalize_bot_key(bot_key)
|
|
27
|
+
configurations[key] ||= Configuration.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def configuration=(config)
|
|
31
|
+
configurations[DEFAULT_BOT_KEY] = config
|
|
20
32
|
end
|
|
21
33
|
|
|
22
34
|
# Lazily builds and returns the adapter based on the current configuration.
|
|
23
35
|
# This method initializes the adapter when it's first called.
|
|
24
|
-
def adapter
|
|
25
|
-
|
|
36
|
+
def adapter(bot_key = nil)
|
|
37
|
+
key = bot_key.nil? ? current_bot_key : normalize_bot_key(bot_key)
|
|
38
|
+
adapters[key] ||= AdapterFactory.build(configuration(key).adapter, configuration(key).adapter_options)
|
|
26
39
|
end
|
|
27
40
|
|
|
28
|
-
def state_store
|
|
29
|
-
|
|
41
|
+
def state_store(bot_key = nil)
|
|
42
|
+
key = bot_key.nil? ? current_bot_key : normalize_bot_key(bot_key)
|
|
43
|
+
state_stores[key] ||= StateStore.build(configuration(key), bot_key: key)
|
|
30
44
|
end
|
|
31
45
|
|
|
32
|
-
def message_map
|
|
33
|
-
state_store.message_map
|
|
46
|
+
def message_map(bot_key = nil)
|
|
47
|
+
state_store(bot_key).message_map
|
|
34
48
|
end
|
|
35
49
|
|
|
36
|
-
def reverse_message_map
|
|
37
|
-
state_store.reverse_message_map
|
|
50
|
+
def reverse_message_map(bot_key = nil)
|
|
51
|
+
state_store(bot_key).reverse_message_map
|
|
38
52
|
end
|
|
39
53
|
|
|
40
|
-
def reaction_count_state
|
|
41
|
-
state_store.reaction_count_state
|
|
54
|
+
def reaction_count_state(bot_key = nil)
|
|
55
|
+
state_store(bot_key).reaction_count_state
|
|
42
56
|
end
|
|
43
57
|
|
|
44
|
-
def user_profiles
|
|
45
|
-
state_store.user_profiles
|
|
58
|
+
def user_profiles(bot_key = nil)
|
|
59
|
+
state_store(bot_key).user_profiles
|
|
46
60
|
end
|
|
47
61
|
|
|
48
|
-
def user_profile(chat_id)
|
|
49
|
-
|
|
62
|
+
def user_profile(chat_id, bot: nil)
|
|
63
|
+
profiles = user_profiles(bot)
|
|
64
|
+
profiles[chat_id] || profiles[chat_id.to_s] || profiles[chat_id.to_i]
|
|
50
65
|
end
|
|
51
66
|
|
|
52
|
-
def scheduler
|
|
53
|
-
|
|
67
|
+
def scheduler(bot_key = nil)
|
|
68
|
+
key = bot_key.nil? ? current_bot_key : normalize_bot_key(bot_key)
|
|
69
|
+
schedulers[key] ||= AutoAwayScheduler.new(adapter(key), configuration(key))
|
|
54
70
|
end
|
|
55
71
|
|
|
56
|
-
def process_update(update)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
def process_update(update, bot: DEFAULT_BOT_KEY)
|
|
73
|
+
with_bot_context(bot) do
|
|
74
|
+
# Handle different types of updates
|
|
75
|
+
if update['message']
|
|
76
|
+
# Process standard messages
|
|
77
|
+
process_message(update['message'])
|
|
78
|
+
elsif update['message_reaction']
|
|
79
|
+
process_message_reaction(update['message_reaction'])
|
|
80
|
+
elsif update['message_reaction_count']
|
|
81
|
+
process_message_reaction_count(update['message_reaction_count'])
|
|
82
|
+
elsif update['my_chat_member']
|
|
83
|
+
# Handle the bot being added to or removed from a chat
|
|
84
|
+
handle_my_chat_member_update(update['my_chat_member'])
|
|
85
|
+
# Add other update types as needed
|
|
86
|
+
else
|
|
87
|
+
# Log or handle unknown update types
|
|
88
|
+
puts "Received an unknown type of update: #{update}"
|
|
89
|
+
end
|
|
72
90
|
end
|
|
73
91
|
end
|
|
74
92
|
|
|
93
|
+
# Reset the adapter instance (useful for testing or reconfiguration).
|
|
94
|
+
def reset_adapter!(bot_key = nil)
|
|
95
|
+
reset_registry!(adapters, bot_key)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def reset_state_store!(bot_key = nil)
|
|
99
|
+
reset_registry!(state_stores, bot_key)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def reset_scheduler!(bot_key = nil)
|
|
103
|
+
reset_registry!(schedulers, bot_key)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def reset_configuration!(bot_key = nil)
|
|
107
|
+
reset_registry!(configurations, bot_key)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def reset!(bot_key = nil)
|
|
111
|
+
reset_adapter!(bot_key)
|
|
112
|
+
reset_state_store!(bot_key)
|
|
113
|
+
reset_scheduler!(bot_key)
|
|
114
|
+
reset_configuration!(bot_key)
|
|
115
|
+
end
|
|
116
|
+
|
|
75
117
|
private
|
|
76
118
|
|
|
119
|
+
def configurations
|
|
120
|
+
@configurations ||= {}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def adapters
|
|
124
|
+
@adapters ||= {}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def state_stores
|
|
128
|
+
@state_stores ||= {}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def schedulers
|
|
132
|
+
@schedulers ||= {}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def current_bot_key
|
|
136
|
+
Thread.current[BOT_CONTEXT_THREAD_KEY] || DEFAULT_BOT_KEY
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def with_bot_context(bot_key)
|
|
140
|
+
normalized_bot_key = normalize_bot_key(bot_key)
|
|
141
|
+
previous_bot_key = Thread.current[BOT_CONTEXT_THREAD_KEY]
|
|
142
|
+
Thread.current[BOT_CONTEXT_THREAD_KEY] = normalized_bot_key
|
|
143
|
+
yield
|
|
144
|
+
ensure
|
|
145
|
+
Thread.current[BOT_CONTEXT_THREAD_KEY] = previous_bot_key
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def normalize_bot_key(bot_key)
|
|
149
|
+
(bot_key || DEFAULT_BOT_KEY).to_sym
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def reset_registry!(registry, bot_key)
|
|
153
|
+
if bot_key.nil?
|
|
154
|
+
registry.clear
|
|
155
|
+
else
|
|
156
|
+
registry.delete(normalize_bot_key(bot_key))
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
77
160
|
def process_message(message)
|
|
78
161
|
chat_id = message.dig('chat', 'id')
|
|
79
162
|
|
|
@@ -511,12 +594,4 @@ module TelegramSupportBot
|
|
|
511
594
|
|
|
512
595
|
end
|
|
513
596
|
|
|
514
|
-
# Reset the adapter instance (useful for testing or reconfiguration).
|
|
515
|
-
def self.reset_adapter!
|
|
516
|
-
@adapter = nil
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
def self.reset_state_store!
|
|
520
|
-
@state_store = nil
|
|
521
|
-
end
|
|
522
597
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: telegram-support-bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Max Buslaev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis
|