mtproto 0.0.11 → 0.0.13
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/lib/mtproto/tl/objects/updates_difference.rb +52 -55
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +0 -1
- metadata +1 -2
- data/lib/mtproto/updates_poller.rb +0 -115
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef5c11c5bf0b9bfe4f3b80e905270264b5658bc55a2932e92c945df8ba0dc723
|
|
4
|
+
data.tar.gz: 58fec06d053d66b52c382049e7fb917dbf0c4af2395c7f81f5dcb66d70778228
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b108736ec52172e501b8609b6c8b5596052b7fa80d72bfaa6cadb393baddbe89ec009148da487f3b8c16b9a6000e5bdea4aa5b15c77fd9ddd19ce43ae8db6763
|
|
7
|
+
data.tar.gz: 3268f1b6943ea7c470ee274a56cbc3e4d3c5a2aebff7e8b5b4522805e8a922756932cb396909650f520cb3153d75d8e34a61e5952916602421ed01df2b9e5c7e
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../schema'
|
|
4
|
+
|
|
3
5
|
module MTProto
|
|
4
6
|
module TL
|
|
5
7
|
class UpdatesDifference
|
|
6
|
-
attr_reader :type, :date, :seq, :new_messages, :
|
|
8
|
+
attr_reader :type, :date, :seq, :new_messages, :pts, :state
|
|
9
|
+
|
|
10
|
+
SCHEMA_PATH = File.expand_path('../../../../data/tl-schema.json', __dir__)
|
|
7
11
|
|
|
8
|
-
def initialize(type:, date: nil, seq: nil, new_messages: [],
|
|
12
|
+
def initialize(type:, date: nil, seq: nil, new_messages: [], pts: nil, state: nil)
|
|
9
13
|
@type = type
|
|
10
14
|
@date = date
|
|
11
15
|
@seq = seq
|
|
12
16
|
@new_messages = new_messages
|
|
13
|
-
@users = users
|
|
14
17
|
@pts = pts
|
|
15
18
|
@state = state
|
|
16
19
|
end
|
|
17
20
|
|
|
21
|
+
def self.schema
|
|
22
|
+
@schema ||= Schema.new(SCHEMA_PATH)
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
def self.parse(data)
|
|
19
26
|
constructor = data[0, 4].unpack1('L<')
|
|
20
27
|
|
|
@@ -31,6 +38,10 @@ module MTProto
|
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
|
|
41
|
+
MESSAGE_CONSTRUCTOR = Constructors::MESSAGE
|
|
42
|
+
MESSAGE_SERVICE = 0x7a800e0a
|
|
43
|
+
MESSAGE_EMPTY = 0x90a6ca84
|
|
44
|
+
|
|
34
45
|
class << self
|
|
35
46
|
private
|
|
36
47
|
|
|
@@ -42,19 +53,21 @@ module MTProto
|
|
|
42
53
|
)
|
|
43
54
|
end
|
|
44
55
|
|
|
56
|
+
# updates.difference: new_messages new_encrypted_messages other_updates chats users state
|
|
45
57
|
def parse_difference(data, constructor)
|
|
46
58
|
offset = 4
|
|
47
59
|
|
|
48
60
|
messages, offset = parse_messages_vector(data, offset)
|
|
49
|
-
offset = skip_vector(data, offset) #
|
|
50
|
-
offset = skip_vector(data, offset) # other_updates
|
|
51
|
-
offset = skip_vector(data, offset) # chats
|
|
52
|
-
|
|
61
|
+
offset = schema.skip_vector(data, offset) # new_encrypted_messages
|
|
62
|
+
offset = schema.skip_vector(data, offset) # other_updates
|
|
63
|
+
offset = schema.skip_vector(data, offset) # chats
|
|
64
|
+
offset = schema.skip_vector(data, offset) # users
|
|
65
|
+
state = UpdatesState.parse(data[offset..])
|
|
53
66
|
|
|
54
67
|
new(
|
|
55
68
|
type: constructor == Constructors::UPDATES_DIFFERENCE ? :difference : :slice,
|
|
56
69
|
new_messages: messages,
|
|
57
|
-
|
|
70
|
+
state: state
|
|
58
71
|
)
|
|
59
72
|
end
|
|
60
73
|
|
|
@@ -65,71 +78,55 @@ module MTProto
|
|
|
65
78
|
|
|
66
79
|
messages = []
|
|
67
80
|
count.times do
|
|
68
|
-
|
|
81
|
+
constructor = data[offset, 4].unpack1('L<')
|
|
82
|
+
msg = extract_message(data, offset, constructor)
|
|
69
83
|
messages << msg if msg
|
|
84
|
+
offset = schema.skip(data, offset)
|
|
70
85
|
end
|
|
71
86
|
[messages, offset]
|
|
72
87
|
end
|
|
73
88
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
offset += 4
|
|
77
|
-
|
|
78
|
-
return [nil, offset] unless msg_constructor == Constructors::MESSAGE
|
|
89
|
+
def extract_message(data, offset, constructor)
|
|
90
|
+
return unless constructor == MESSAGE_CONSTRUCTOR
|
|
79
91
|
|
|
92
|
+
offset += 4 # constructor
|
|
80
93
|
flags = data[offset, 4].unpack1('L<')
|
|
81
94
|
offset += 4
|
|
82
|
-
|
|
95
|
+
flags2 = data[offset, 4].unpack1('L<')
|
|
96
|
+
offset += 4
|
|
97
|
+
id = data[offset, 4].unpack1('l<')
|
|
83
98
|
offset += 4
|
|
84
|
-
|
|
99
|
+
|
|
100
|
+
offset = schema.skip(data, offset) if flags.anybits?(1 << 8) # from_id (Peer)
|
|
85
101
|
offset += 4 if flags.anybits?(1 << 29) # from_boosts_applied
|
|
86
|
-
offset
|
|
102
|
+
peer_type, peer_id, offset = parse_peer(data, offset)
|
|
103
|
+
offset = schema.skip(data, offset) if flags.anybits?(1 << 28) # saved_peer_id
|
|
104
|
+
offset = schema.skip(data, offset) if flags.anybits?(1 << 2) # fwd_from
|
|
87
105
|
offset += 8 if flags.anybits?(1 << 11) # via_bot_id
|
|
106
|
+
offset += 8 if flags2.anybits?(1 << 0) # via_business_bot_id
|
|
107
|
+
offset = schema.skip(data, offset) if flags.anybits?(1 << 3) # reply_to
|
|
108
|
+
|
|
88
109
|
date = data[offset, 4].unpack1('L<')
|
|
89
110
|
offset += 4
|
|
90
|
-
message_text,
|
|
111
|
+
message_text, = read_tl_string(data, offset)
|
|
91
112
|
|
|
92
|
-
|
|
93
|
-
rescue StandardError
|
|
94
|
-
[nil, offset]
|
|
113
|
+
{ id: id, date: date, message: message_text, peer_type: peer_type, peer_id: peer_id }
|
|
95
114
|
end
|
|
96
115
|
|
|
97
|
-
def
|
|
98
|
-
offset
|
|
99
|
-
count = data[offset, 4].unpack1('L<')
|
|
116
|
+
def parse_peer(data, offset)
|
|
117
|
+
constructor = data[offset, 4].unpack1('L<')
|
|
100
118
|
offset += 4
|
|
101
119
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
user_id = data[offset, 8].unpack1('Q<')
|
|
112
|
-
offset += 8
|
|
113
|
-
|
|
114
|
-
access_hash = nil
|
|
115
|
-
if flags.anybits?(1 << 0)
|
|
116
|
-
access_hash = data[offset, 8].unpack1('Q<')
|
|
117
|
-
offset += 8
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
users << { id: user_id, access_hash: access_hash }
|
|
121
|
-
rescue StandardError
|
|
122
|
-
break
|
|
120
|
+
case constructor
|
|
121
|
+
when Constructors::PEER_USER
|
|
122
|
+
[:user, data[offset, 8].unpack1('Q<'), offset + 8]
|
|
123
|
+
when Constructors::PEER_CHAT
|
|
124
|
+
[:chat, data[offset, 8].unpack1('Q<'), offset + 8]
|
|
125
|
+
when Constructors::PEER_CHANNEL
|
|
126
|
+
[:channel, data[offset, 8].unpack1('Q<'), offset + 8]
|
|
127
|
+
else
|
|
128
|
+
raise "Unknown peer constructor: 0x#{constructor.to_s(16)}"
|
|
123
129
|
end
|
|
124
|
-
[users, offset]
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def skip_vector(data, offset)
|
|
128
|
-
offset += 4 # vector constructor
|
|
129
|
-
count = data[offset, 4].unpack1('L<')
|
|
130
|
-
offset += 4
|
|
131
|
-
count.times { offset += 4 }
|
|
132
|
-
offset
|
|
133
130
|
end
|
|
134
131
|
|
|
135
132
|
def read_tl_string(data, offset)
|
|
@@ -144,7 +141,7 @@ module MTProto
|
|
|
144
141
|
total = 1 + len
|
|
145
142
|
end
|
|
146
143
|
padding = (4 - (total % 4)) % 4
|
|
147
|
-
[data[offset + (total - len), len], offset + total + padding]
|
|
144
|
+
[data[offset + (total - len), len].force_encoding('UTF-8'), offset + total + padding]
|
|
148
145
|
end
|
|
149
146
|
end
|
|
150
147
|
end
|
data/lib/mtproto/version.rb
CHANGED
data/lib/mtproto.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mtproto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artem Levenkov
|
|
@@ -137,7 +137,6 @@ files:
|
|
|
137
137
|
- lib/mtproto/transport/errors.rb
|
|
138
138
|
- lib/mtproto/transport/packet.rb
|
|
139
139
|
- lib/mtproto/transport/tcp_connection.rb
|
|
140
|
-
- lib/mtproto/updates_poller.rb
|
|
141
140
|
- lib/mtproto/version.rb
|
|
142
141
|
- scripts/generate_constructors.rb
|
|
143
142
|
- tmp/.keep
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module MTProto
|
|
4
|
-
class UpdatesPoller
|
|
5
|
-
attr_reader :state, :running
|
|
6
|
-
|
|
7
|
-
def initialize(client, poll_interval: 1.0)
|
|
8
|
-
@client = client
|
|
9
|
-
@poll_interval = poll_interval
|
|
10
|
-
@state = nil
|
|
11
|
-
@running = false
|
|
12
|
-
@on_message_callbacks = []
|
|
13
|
-
@on_update_callbacks = []
|
|
14
|
-
@users_cache = {}
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def on_message(&block)
|
|
18
|
-
@on_message_callbacks << block
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def on_update(&block)
|
|
22
|
-
@on_update_callbacks << block
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def start
|
|
26
|
-
raise 'Already running' if @running
|
|
27
|
-
raise 'Auth key not set' unless @client.auth_key?
|
|
28
|
-
|
|
29
|
-
@running = true
|
|
30
|
-
|
|
31
|
-
@state = call_with_retry { @client.api.get_updates_state }
|
|
32
|
-
|
|
33
|
-
poll_loop
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def stop
|
|
37
|
-
@running = false
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def poll_loop
|
|
43
|
-
while @running
|
|
44
|
-
begin
|
|
45
|
-
difference = call_with_retry do
|
|
46
|
-
@client.api.get_updates_difference(
|
|
47
|
-
pts: @state.pts,
|
|
48
|
-
date: @state.date,
|
|
49
|
-
qts: @state.qts
|
|
50
|
-
)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
process_difference(difference)
|
|
54
|
-
|
|
55
|
-
if difference.state
|
|
56
|
-
@state = difference.state
|
|
57
|
-
elsif difference.type == :too_long
|
|
58
|
-
@state = call_with_retry { @client.api.get_updates_state }
|
|
59
|
-
elsif difference.date
|
|
60
|
-
@state.date = difference.date
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
sleep @poll_interval
|
|
64
|
-
rescue MTProto::RpcError => e
|
|
65
|
-
warn "RPC Error during polling: #{e.message}"
|
|
66
|
-
sleep @poll_interval
|
|
67
|
-
rescue StandardError => e
|
|
68
|
-
warn "Error during polling: #{e.class} - #{e.message}"
|
|
69
|
-
warn e.backtrace.first(5).join("\n")
|
|
70
|
-
sleep @poll_interval
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def call_with_retry(max_retries: 5)
|
|
76
|
-
retries = 0
|
|
77
|
-
begin
|
|
78
|
-
yield
|
|
79
|
-
rescue MTProto::UnexpectedConstructorError, RuntimeError
|
|
80
|
-
retries += 1
|
|
81
|
-
retry if retries < max_retries
|
|
82
|
-
raise
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def process_difference(difference)
|
|
87
|
-
case difference.type
|
|
88
|
-
when :empty
|
|
89
|
-
nil
|
|
90
|
-
when :difference, :slice, :short_message
|
|
91
|
-
difference.users&.each do |user|
|
|
92
|
-
@users_cache[user[:id]] = user[:access_hash] if user[:access_hash]
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
if difference.new_messages && !difference.new_messages.empty?
|
|
96
|
-
difference.new_messages.each do |message|
|
|
97
|
-
process_message(message)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
@on_update_callbacks.each { |callback| callback.call(difference) }
|
|
102
|
-
when :too_long
|
|
103
|
-
puts "Update gap too long (pts=#{difference.pts}), refreshing state..."
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def process_message(message)
|
|
108
|
-
return unless message
|
|
109
|
-
|
|
110
|
-
message[:access_hash] = @users_cache[message[:user_id]] if message[:user_id] && @users_cache[message[:user_id]]
|
|
111
|
-
|
|
112
|
-
@on_message_callbacks.each { |callback| callback.call(message) }
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|