tg_mq 0.0.3
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 +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +82 -0
- data/bin/tgmq +123 -0
- data/lib/tg-mq.rb +1 -0
- data/lib/tg_mq/configuration.rb +41 -0
- data/lib/tg_mq/connection.rb +122 -0
- data/lib/tg_mq/frame.rb +40 -0
- data/lib/tg_mq/input_shaper.rb +35 -0
- data/lib/tg_mq/message.rb +28 -0
- data/lib/tg_mq/output_shaper.rb +37 -0
- data/lib/tg_mq/version.rb +3 -0
- data/lib/tg_mq.rb +20 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f65f989683ba5ccbb0f3862df8bf42c4e28aeedc5046b2a19fafd0a3a2ffe99f
|
4
|
+
data.tar.gz: b19a7af3a43caf7146825cb8dab01b6148ee8bc570e78ef4d8c7e5418d700e1a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: afd1732c0334d14dd4c827dd9de4efe471b0e36d096c443d527119dd68ee7b270fa7fab33156f5738d7bf0cb8e6e178b23616dc01c0d92ff4586c00347bd2565
|
7
|
+
data.tar.gz: 197bf2b88aaf2550c8e20ca6f31414561a7cf7ef6b1d7037b522e3e1a936dcaf1791b4ab0bca9ea34501956534430c6f430c31095c1fffc14e0ba602e8736676
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
tg_mq (0.0.1)
|
5
|
+
activesupport (~> 6.0)
|
6
|
+
logger
|
7
|
+
telegram-bot-ruby
|
8
|
+
timeouter
|
9
|
+
zeitwerk
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activesupport (6.1.7.10)
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
i18n (>= 1.6, < 2)
|
17
|
+
minitest (>= 5.1)
|
18
|
+
tzinfo (~> 2.0)
|
19
|
+
zeitwerk (~> 2.3)
|
20
|
+
bigdecimal (3.2.2)
|
21
|
+
byebug (12.0.0)
|
22
|
+
concurrent-ruby (1.3.5)
|
23
|
+
dry-core (1.1.0)
|
24
|
+
concurrent-ruby (~> 1.0)
|
25
|
+
logger
|
26
|
+
zeitwerk (~> 2.6)
|
27
|
+
dry-inflector (1.2.0)
|
28
|
+
dry-logic (1.6.0)
|
29
|
+
bigdecimal
|
30
|
+
concurrent-ruby (~> 1.0)
|
31
|
+
dry-core (~> 1.1)
|
32
|
+
zeitwerk (~> 2.6)
|
33
|
+
dry-struct (1.8.0)
|
34
|
+
dry-core (~> 1.1)
|
35
|
+
dry-types (~> 1.8, >= 1.8.2)
|
36
|
+
ice_nine (~> 0.11)
|
37
|
+
zeitwerk (~> 2.6)
|
38
|
+
dry-types (1.8.2)
|
39
|
+
bigdecimal (~> 3.0)
|
40
|
+
concurrent-ruby (~> 1.0)
|
41
|
+
dry-core (~> 1.0)
|
42
|
+
dry-inflector (~> 1.0)
|
43
|
+
dry-logic (~> 1.4)
|
44
|
+
zeitwerk (~> 2.6)
|
45
|
+
faraday (2.13.1)
|
46
|
+
faraday-net_http (>= 2.0, < 3.5)
|
47
|
+
json
|
48
|
+
logger
|
49
|
+
faraday-multipart (1.1.0)
|
50
|
+
multipart-post (~> 2.0)
|
51
|
+
faraday-net_http (3.4.0)
|
52
|
+
net-http (>= 0.5.0)
|
53
|
+
i18n (1.14.7)
|
54
|
+
concurrent-ruby (~> 1.0)
|
55
|
+
ice_nine (0.11.2)
|
56
|
+
json (2.12.2)
|
57
|
+
logger (1.7.0)
|
58
|
+
minitest (5.25.5)
|
59
|
+
multipart-post (2.4.1)
|
60
|
+
net-http (0.6.0)
|
61
|
+
uri
|
62
|
+
telegram-bot-ruby (2.4.0)
|
63
|
+
dry-struct (~> 1.6)
|
64
|
+
faraday (~> 2.0)
|
65
|
+
faraday-multipart (~> 1.0)
|
66
|
+
zeitwerk (~> 2.6)
|
67
|
+
timeouter (0.1.3.38794)
|
68
|
+
tzinfo (2.0.6)
|
69
|
+
concurrent-ruby (~> 1.0)
|
70
|
+
uri (1.0.3)
|
71
|
+
zeitwerk (2.7.3)
|
72
|
+
|
73
|
+
PLATFORMS
|
74
|
+
ruby
|
75
|
+
x86_64-linux
|
76
|
+
|
77
|
+
DEPENDENCIES
|
78
|
+
byebug
|
79
|
+
tg_mq!
|
80
|
+
|
81
|
+
BUNDLED WITH
|
82
|
+
2.6.2
|
data/bin/tgmq
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'tg_mq'
|
5
|
+
|
6
|
+
UTIL = File.basename(__FILE__)
|
7
|
+
SELF = File.absolute_path(__FILE__)
|
8
|
+
|
9
|
+
Thread.abort_on_exception = true
|
10
|
+
|
11
|
+
[STDIN, STDOUT, STDERR].each do |io|
|
12
|
+
io.sync = true
|
13
|
+
rescue StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
@opts = {
|
17
|
+
itoken: nil,
|
18
|
+
otoken: nil,
|
19
|
+
channel: nil,
|
20
|
+
log_level: ENV.fetch('LOG_LEVEL', ::Logger::INFO)
|
21
|
+
}
|
22
|
+
|
23
|
+
parser = OptionParser.new do |o|
|
24
|
+
o.banner = "Usage: #{UTIL} [options]"
|
25
|
+
|
26
|
+
o.separator ''
|
27
|
+
o.separator 'TgMq options:'
|
28
|
+
|
29
|
+
o.on('-d', '--debug', 'Enable debug output. Overrides LOG_LEVEL environment variable') do
|
30
|
+
@opts[:log_level] = ::Logger::DEBUG
|
31
|
+
end
|
32
|
+
|
33
|
+
o.on('-s', '--silent', 'Disable info output. Overrides LOG_LEVEL environment variable') do
|
34
|
+
@opts[:log_level] = ::Logger::WARN
|
35
|
+
end
|
36
|
+
|
37
|
+
o.on('-i TOKEN', '--itoken TOKEN', String, 'Telegram Bot token for input channel') do |token|
|
38
|
+
@opts[:itoken] = token.strip
|
39
|
+
end
|
40
|
+
|
41
|
+
o.on('-o TOKEN', '--otoken TOKEN', String, 'Telegram Bot token for output channel') do |token|
|
42
|
+
@opts[:otoken] = token.strip
|
43
|
+
end
|
44
|
+
|
45
|
+
o.on('-c CHANNEL', '--channel CHANNEL', String, 'Telegram Bot chat_id to communicate through') do |channel|
|
46
|
+
@opts[:channel] = channel
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@args = parser.parse!
|
50
|
+
|
51
|
+
TgMq.configure do |config|
|
52
|
+
config.logger.level = @opts[:log_level]
|
53
|
+
end
|
54
|
+
|
55
|
+
$conn = conn = TgMq::Connection.new(itoken: @opts[:itoken], otoken: @opts[:otoken], channel: @opts[:channel])
|
56
|
+
|
57
|
+
control_queue = $queue = queue = SizedQueue.new(50)
|
58
|
+
|
59
|
+
def terminate_now
|
60
|
+
$terminate = true
|
61
|
+
STDOUT.flush
|
62
|
+
STDIN.close
|
63
|
+
$conn.stop
|
64
|
+
$queue.push(:terminate)
|
65
|
+
end
|
66
|
+
|
67
|
+
Signal.trap 'TERM' do
|
68
|
+
$terminate = true
|
69
|
+
Thread.new do
|
70
|
+
warn('Terminating gracefully...')
|
71
|
+
terminate_now
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
Signal.trap 'INT' do
|
76
|
+
$terminate = true
|
77
|
+
Thread.new do
|
78
|
+
warn('Stopping gracefully...')
|
79
|
+
terminate_now
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
reader = Thread.new(control_queue) do |q, _c|
|
84
|
+
STDIN.binmode
|
85
|
+
loop do
|
86
|
+
q.push([:in, STDIN.readpartial(3000)])
|
87
|
+
rescue EOFError
|
88
|
+
q.push([:in, 'EOF', proc { q.push(:terminate) }])
|
89
|
+
break
|
90
|
+
end
|
91
|
+
rescue StandardError
|
92
|
+
q.push(:terminate)
|
93
|
+
end
|
94
|
+
|
95
|
+
remote = Thread.new(queue, conn) do |q, c|
|
96
|
+
STDOUT.binmode
|
97
|
+
c.subscribe do |line|
|
98
|
+
q.push([:out, line])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
loop do
|
103
|
+
cmd, data, cb = queue.deq(timeout: 1)
|
104
|
+
if cmd == :terminate || $terminate
|
105
|
+
terminate_now
|
106
|
+
break
|
107
|
+
end
|
108
|
+
|
109
|
+
next if cmd.nil?
|
110
|
+
|
111
|
+
if cmd == :in
|
112
|
+
cb ? conn.enqueue_message(data, &cb) : conn.enqueue_message(data)
|
113
|
+
elsif cmd == :out
|
114
|
+
if data.strip == 'EOF'
|
115
|
+
terminate_now
|
116
|
+
else
|
117
|
+
STDOUT.write(data)
|
118
|
+
STDOUT.flush
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
[reader, remote].each(&:join)
|
data/lib/tg-mq.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative './tg_mq'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module TgMq
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :logger
|
6
|
+
|
7
|
+
def initialize(logger = ::Logger.new(STDERR, formatter: Logger::Formatter.new))
|
8
|
+
@logger = logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
9
|
+
end
|
10
|
+
|
11
|
+
module Concern
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do |_klass|
|
15
|
+
end
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
# Instantiate the Configuration singleton
|
19
|
+
# or return it. Remember that the instance
|
20
|
+
# has attribute readers so that we can access
|
21
|
+
# the configured values
|
22
|
+
def configuration
|
23
|
+
@configuration ||= TgMq::Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def config
|
27
|
+
configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
# This is the configure block definition.
|
31
|
+
# The configuration method will return the
|
32
|
+
# Configuration singleton, which is then yielded
|
33
|
+
# to the configure block. Then it's just a matter
|
34
|
+
# of using the attribute accessors we previously defined
|
35
|
+
def configure
|
36
|
+
yield(configuration)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'telegram/bot'
|
3
|
+
require 'timeouter'
|
4
|
+
require 'monitor'
|
5
|
+
|
6
|
+
module TgMq
|
7
|
+
class Connection
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
def initialize(itoken:, otoken:, channel:, logger: TgMq.config.logger)
|
11
|
+
@logger = TgMq.setup_logger(logger).tagged(self.class)
|
12
|
+
|
13
|
+
@mx = Monitor.new
|
14
|
+
|
15
|
+
@itoken = itoken
|
16
|
+
@otoken = otoken
|
17
|
+
@channel = channel
|
18
|
+
|
19
|
+
@output_bot = ::Telegram::Bot::Client.new(@otoken, timeout: 5)
|
20
|
+
@output_shaper = OutputShaper.new(chunk_size: 4080)
|
21
|
+
|
22
|
+
@input_bot = ::Telegram::Bot::Client.new(@itoken, timeout: 5)
|
23
|
+
@input_shaper = InputShaper.new(logger: logger)
|
24
|
+
|
25
|
+
# Telegram Bot api alows 30 rps, we use only 20
|
26
|
+
@delay = 60.0 / 25.0
|
27
|
+
$r = 0
|
28
|
+
|
29
|
+
# @squeue = SizedQueue.new(10)
|
30
|
+
@threads = []
|
31
|
+
@threads << start_sender(@output_shaper, @output_bot, @delay)
|
32
|
+
end
|
33
|
+
|
34
|
+
def enqueue_message(data, &cb)
|
35
|
+
logger.debug("Enqueue message of #{data.size} bytes")
|
36
|
+
@output_shaper.enqueue_data(data, &cb)
|
37
|
+
end
|
38
|
+
|
39
|
+
def stopped?
|
40
|
+
@stopped
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop(timeout = 2)
|
44
|
+
return if @stopped
|
45
|
+
|
46
|
+
@stopped = true
|
47
|
+
@output_bot.stop
|
48
|
+
@input_bot.stop
|
49
|
+
|
50
|
+
if wait_for_termination(timeout)
|
51
|
+
true
|
52
|
+
else
|
53
|
+
@threads.each(&:kill)
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def wait_for_termination(timeout = 0)
|
59
|
+
Timeouter.run(timeout) do |t|
|
60
|
+
return true if @threads.all? do |thread|
|
61
|
+
thread.join(t.left)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def subscribe(&block)
|
67
|
+
@input_bot.listen do |message|
|
68
|
+
case message
|
69
|
+
when Telegram::Bot::Types::Message
|
70
|
+
logger.debug(123_123)
|
71
|
+
text = (message&.new_chat_title || message&.text || message&.pinned_message&.text).to_s
|
72
|
+
logger.debug "Receive raw: [#{text.first(15)}...] of #{text.size} bytes"
|
73
|
+
|
74
|
+
if (data = @input_shaper.pushdata(text))
|
75
|
+
decoded = Base64.strict_decode64(data)
|
76
|
+
logger.debug "Receive payload: of #{decoded.size} bytes"
|
77
|
+
block.call(decoded)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def start_sender(output_shaper, bot, delay)
|
84
|
+
next_send_at = Time.at(0)
|
85
|
+
|
86
|
+
Thread.new(output_shaper, bot) do |c, b|
|
87
|
+
until @stopped
|
88
|
+
break if @stopped
|
89
|
+
next(sleep 1) if Time.now < next_send_at
|
90
|
+
|
91
|
+
frame = c.deq(timeout: 1)
|
92
|
+
break if @stopped
|
93
|
+
next(sleep 1) if frame.nil?
|
94
|
+
|
95
|
+
logger.debug "Sending frame [#{frame.id}] of #{frame.data.size} bytes..."
|
96
|
+
|
97
|
+
response = tgretry { b.api.sendMessage(chat_id: @channel, text: frame.data) }
|
98
|
+
sleep 0.1
|
99
|
+
pin_response = tgretry { b.api.pinChatMessage(chat_id: @channel, message_id: response.message_id) }
|
100
|
+
|
101
|
+
begin
|
102
|
+
frame.callback&.call(pin_response)
|
103
|
+
rescue StandardError
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
|
107
|
+
next_send_at = Time.now + delay * 2
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def tgretry
|
113
|
+
yield
|
114
|
+
rescue Telegram::Bot::Exceptions::ResponseError => e
|
115
|
+
if e.error_code.to_i == 429
|
116
|
+
logger.warn 'Retry packet send in 5 seconds...'
|
117
|
+
sleep 5
|
118
|
+
retry
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/tg_mq/frame.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module TgMq
|
2
|
+
class Frame
|
3
|
+
BEGIN_MSG = 'tgw'
|
4
|
+
BEGIN_RX = /^#{BEGIN_MSG}\[(?<seq>\d+):(?<msg_id>\d+):(?<num>\d+)\](?<msg>.*)/
|
5
|
+
|
6
|
+
END_MSG = ':wgt'
|
7
|
+
END_RX = /#{END_MSG}$/
|
8
|
+
|
9
|
+
attr_reader :seq, :msg_id, :num, :chunk, :callback
|
10
|
+
|
11
|
+
def initialize(seq, msg_id, num, chunk)
|
12
|
+
@seq = seq
|
13
|
+
@msg_id = msg_id
|
14
|
+
@num = num
|
15
|
+
@chunk = chunk
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse(data)
|
19
|
+
if (md = BEGIN_RX.match(data))
|
20
|
+
new(md[:seq], md[:msg_id], md[:num].to_i, md[:msg])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
"#{message_id}:#{num}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def message_id
|
29
|
+
"#{seq}:#{msg_id}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def data
|
33
|
+
"#{BEGIN_MSG}[#{id}]#{chunk}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_callback(&callback)
|
37
|
+
@callback = callback
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TgMq
|
2
|
+
class InputShaper
|
3
|
+
attr_reader :logger
|
4
|
+
|
5
|
+
def initialize(logger: TgMq.config.logger)
|
6
|
+
@logger = TgMq.setup_logger(logger).tagged(self.class)
|
7
|
+
|
8
|
+
@frames = Hash.new do |h, message_id|
|
9
|
+
h[message_id] = {
|
10
|
+
buffer: '',
|
11
|
+
frames: []
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def pushdata(text)
|
17
|
+
if (frame = Frame.parse(text))
|
18
|
+
logger.info "receive frame [#{frame.id}]"
|
19
|
+
frameset = @frames[frame.message_id]
|
20
|
+
data = frameset[:buffer] += frame.chunk
|
21
|
+
frameset[:frames] << frame
|
22
|
+
|
23
|
+
if data.end_with?(Frame::END_MSG)
|
24
|
+
@frames.delete(frame.message_id)
|
25
|
+
return data[0..-5]
|
26
|
+
end
|
27
|
+
else
|
28
|
+
logger.warn "skip [#{text.first(15)}]: not a frame"
|
29
|
+
end
|
30
|
+
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module TgMq
|
2
|
+
class Message
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def self.pack(seq, data, msg_id: Time.now.strftime('%L'), chunked: 4080)
|
6
|
+
(data + Frame::END_MSG).scan(/.{1,#{chunked}}/).each_with_index.map do |chunk, idx|
|
7
|
+
Frame.new(seq, msg_id, idx, chunk)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(seq, chunks, msg_id: Time.now.strftime('%L'))
|
12
|
+
@seq = seq
|
13
|
+
@msg_id = msg_id
|
14
|
+
@chunks = chunks
|
15
|
+
end
|
16
|
+
|
17
|
+
def each
|
18
|
+
if block_given?
|
19
|
+
idx = -1
|
20
|
+
@chunks.each do |chunk|
|
21
|
+
yield(Frame.new(@seq, @msg_id, idx += 1, chunk))
|
22
|
+
end
|
23
|
+
else
|
24
|
+
to_enum(:each)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TgMq
|
2
|
+
class OutputShaper
|
3
|
+
attr_reader :chunk_size
|
4
|
+
|
5
|
+
def initialize(chunk_size: 110)
|
6
|
+
@chunk_size = chunk_size
|
7
|
+
@seq = 0
|
8
|
+
@queue = SizedQueue.new(10)
|
9
|
+
end
|
10
|
+
|
11
|
+
def enqueue_data(data, &callback)
|
12
|
+
frames = split_to_frames(next_seq!, data).to_a
|
13
|
+
frames.last&.set_callback(&callback)
|
14
|
+
frames.each do |frame|
|
15
|
+
@queue << frame
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def deq(*args, **kwargs)
|
20
|
+
@queue.deq(*args, **kwargs)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def next_seq!
|
26
|
+
@seq += 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def split_to_frames(seq, data, msg_id: Time.now.strftime('%L'))
|
30
|
+
encoded = Base64.strict_encode64(data).strip
|
31
|
+
|
32
|
+
(encoded + Frame::END_MSG).scan(/.{1,#{chunk_size}}/).each_with_index.map do |chunk, idx|
|
33
|
+
Frame.new(seq, msg_id, idx, chunk)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/tg_mq.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
require 'zeitwerk'
|
5
|
+
|
6
|
+
loader = Zeitwerk::Loader.for_gem
|
7
|
+
loader.ignore("#{__dir__}/tg-mq.rb")
|
8
|
+
loader.inflector.inflect(
|
9
|
+
'tg_mq' => 'TgMq',
|
10
|
+
'tg-mq' => 'TgMq'
|
11
|
+
)
|
12
|
+
loader.setup
|
13
|
+
|
14
|
+
module TgMq
|
15
|
+
include Configuration::Concern
|
16
|
+
|
17
|
+
def self.setup_logger(logger)
|
18
|
+
logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tg_mq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Samoilenko Yuri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-06-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: logger
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: timeouter
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: telegram-bot-ruby
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: zeitwerk
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: byebug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Message Queue backed by Telegram Chat
|
98
|
+
email:
|
99
|
+
- kinnalru@gmail.com
|
100
|
+
executables:
|
101
|
+
- tgmq
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- Gemfile
|
106
|
+
- Gemfile.lock
|
107
|
+
- bin/tgmq
|
108
|
+
- lib/tg-mq.rb
|
109
|
+
- lib/tg_mq.rb
|
110
|
+
- lib/tg_mq/configuration.rb
|
111
|
+
- lib/tg_mq/connection.rb
|
112
|
+
- lib/tg_mq/frame.rb
|
113
|
+
- lib/tg_mq/input_shaper.rb
|
114
|
+
- lib/tg_mq/message.rb
|
115
|
+
- lib/tg_mq/output_shaper.rb
|
116
|
+
- lib/tg_mq/version.rb
|
117
|
+
homepage:
|
118
|
+
licenses: []
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubygems_version: 3.4.10
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Message Queue backed by Telegram Chat
|
139
|
+
test_files: []
|