mtproto 0.0.7 → 0.0.9

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +4 -0
  3. data/ext/aes_ige/extconf.rb +3 -9
  4. data/ext/factorization/extconf.rb +2 -0
  5. data/lib/mtproto/auth_key_generator.rb +66 -103
  6. data/lib/mtproto/binary.rb +21 -0
  7. data/lib/mtproto/client/api/check_password.rb +41 -0
  8. data/lib/mtproto/client/api/export_login_token.rb +27 -0
  9. data/lib/mtproto/client/api/get_updates_difference.rb +21 -0
  10. data/lib/mtproto/client/api/get_updates_state.rb +14 -0
  11. data/lib/mtproto/client/api/get_users.rb +14 -0
  12. data/lib/mtproto/client/api/import_login_token.rb +23 -0
  13. data/lib/mtproto/client/api/send_code.rb +21 -0
  14. data/lib/mtproto/client/api/sign_in.rb +27 -0
  15. data/lib/mtproto/client/api.rb +28 -0
  16. data/lib/mtproto/client/rpc/response.rb +63 -0
  17. data/lib/mtproto/client/rpc.rb +67 -107
  18. data/lib/mtproto/client.rb +176 -31
  19. data/lib/mtproto/crypto/dh_key_exchange.rb +1 -2
  20. data/lib/mtproto/crypto/dh_validator.rb +17 -19
  21. data/lib/mtproto/crypto/factorization.rb +1 -1
  22. data/lib/mtproto/crypto/rsa_key.rb +2 -2
  23. data/lib/mtproto/crypto/srp.rb +117 -0
  24. data/lib/mtproto/delegate_methods.rb +11 -0
  25. data/lib/mtproto/message/message.rb +85 -0
  26. data/lib/mtproto/session.rb +1 -1
  27. data/lib/mtproto/tl/constructors.rb +2269 -0
  28. data/lib/mtproto/tl/object.rb +25 -0
  29. data/lib/mtproto/tl/objects/account_password.rb +72 -0
  30. data/lib/mtproto/tl/objects/authorization.rb +73 -0
  31. data/lib/mtproto/tl/objects/check_password.rb +46 -0
  32. data/lib/mtproto/tl/objects/client_dh_inner_data.rb +47 -0
  33. data/lib/mtproto/tl/objects/dh_gen_response.rb +50 -0
  34. data/lib/mtproto/tl/objects/export_login_token.rb +51 -0
  35. data/lib/mtproto/tl/objects/get_config.rb +15 -0
  36. data/lib/mtproto/tl/objects/get_difference.rb +36 -0
  37. data/lib/mtproto/tl/objects/get_password.rb +15 -0
  38. data/lib/mtproto/tl/objects/get_state.rb +15 -0
  39. data/lib/mtproto/tl/objects/get_users.rb +20 -0
  40. data/lib/mtproto/tl/objects/help_config.rb +77 -0
  41. data/lib/mtproto/tl/objects/import_login_token.rb +39 -0
  42. data/lib/mtproto/tl/objects/init_connection.rb +59 -0
  43. data/lib/mtproto/tl/objects/invoke_with_layer.rb +22 -0
  44. data/lib/mtproto/tl/objects/login_token.rb +82 -0
  45. data/lib/mtproto/tl/objects/pq_inner_data.rb +69 -0
  46. data/lib/mtproto/tl/objects/req_dh_params.rb +65 -0
  47. data/lib/mtproto/tl/objects/req_pq_multi.rb +23 -0
  48. data/lib/mtproto/tl/objects/res_pq.rb +75 -0
  49. data/lib/mtproto/tl/objects/send_code.rb +50 -0
  50. data/lib/mtproto/tl/objects/sent_code.rb +79 -0
  51. data/lib/mtproto/tl/objects/server_dh_inner_data.rb +74 -0
  52. data/lib/mtproto/tl/objects/server_dh_params.rb +53 -0
  53. data/lib/mtproto/tl/objects/set_client_dh_params.rb +48 -0
  54. data/lib/mtproto/tl/objects/sign_in.rb +47 -0
  55. data/lib/mtproto/tl/objects/update.rb +80 -0
  56. data/lib/mtproto/tl/objects/update_short.rb +22 -0
  57. data/lib/mtproto/tl/objects/update_short_message.rb +67 -0
  58. data/lib/mtproto/tl/objects/updates_difference.rb +157 -0
  59. data/lib/mtproto/tl/objects/updates_state.rb +37 -0
  60. data/lib/mtproto/tl/objects/users.rb +86 -0
  61. data/lib/mtproto/transport/abridged_packet_codec.rb +35 -12
  62. data/lib/mtproto/transport/connection.rb +23 -0
  63. data/lib/mtproto/transport/errors.rb +11 -0
  64. data/lib/mtproto/transport/packet.rb +19 -0
  65. data/lib/mtproto/transport/tcp_connection.rb +57 -46
  66. data/lib/mtproto/{tl → type}/bad_msg_notification.rb +11 -11
  67. data/lib/mtproto/{tl → type}/client_dh_inner_data.rb +1 -1
  68. data/lib/mtproto/{tl → type}/gzip_packed.rb +6 -4
  69. data/lib/mtproto/{tl → type}/message.rb +3 -3
  70. data/lib/mtproto/{tl → type}/msg_container.rb +1 -1
  71. data/lib/mtproto/{tl → type}/new_session_created.rb +1 -1
  72. data/lib/mtproto/{tl/p_q_inner_data.rb → type/pq_inner_data.rb} +1 -1
  73. data/lib/mtproto/{tl → type}/rpc_error.rb +1 -2
  74. data/lib/mtproto/{tl → type}/serializer.rb +1 -1
  75. data/lib/mtproto/{tl → type}/server_dh_inner_data.rb +1 -1
  76. data/lib/mtproto/updates_poller.rb +37 -33
  77. data/lib/mtproto/version.rb +1 -1
  78. data/lib/mtproto.rb +21 -22
  79. data/scripts/generate_constructors.rb +65 -0
  80. metadata +80 -49
  81. data/lib/mtproto/rpc/get_config.rb +0 -37
  82. data/lib/mtproto/rpc/get_contacts.rb +0 -22
  83. data/lib/mtproto/rpc/get_updates_difference.rb +0 -33
  84. data/lib/mtproto/rpc/get_updates_state.rb +0 -22
  85. data/lib/mtproto/rpc/get_users.rb +0 -22
  86. data/lib/mtproto/rpc/ping.rb +0 -26
  87. data/lib/mtproto/rpc/send_code.rb +0 -44
  88. data/lib/mtproto/rpc/send_message.rb +0 -31
  89. data/lib/mtproto/rpc/sign_in.rb +0 -52
  90. data/lib/mtproto/tl/auth_key/dh_gen_response.rb +0 -37
  91. data/lib/mtproto/tl/auth_key/req_dh_params.rb +0 -31
  92. data/lib/mtproto/tl/auth_key/req_pq_multi.rb +0 -18
  93. data/lib/mtproto/tl/auth_key/res_pq.rb +0 -62
  94. data/lib/mtproto/tl/auth_key/server_dh_params.rb +0 -43
  95. data/lib/mtproto/tl/auth_key/set_client_dh_params.rb +0 -25
  96. data/lib/mtproto/tl/code_settings.rb +0 -25
  97. data/lib/mtproto/tl/config.rb +0 -124
  98. data/lib/mtproto/tl/method_builder.rb +0 -29
  99. data/lib/mtproto/tl/rpc/auth/authorization.rb +0 -107
  100. data/lib/mtproto/tl/rpc/auth/send_code.rb +0 -28
  101. data/lib/mtproto/tl/rpc/auth/sent_code.rb +0 -36
  102. data/lib/mtproto/tl/rpc/auth/sign_in.rb +0 -32
  103. data/lib/mtproto/tl/rpc/contacts/contacts.rb +0 -155
  104. data/lib/mtproto/tl/rpc/contacts/get_contacts.rb +0 -18
  105. data/lib/mtproto/tl/rpc/help/config.rb +0 -35
  106. data/lib/mtproto/tl/rpc/help/get_config.rb +0 -17
  107. data/lib/mtproto/tl/rpc/messages/send_message.rb +0 -43
  108. data/lib/mtproto/tl/rpc/messages/updates.rb +0 -87
  109. data/lib/mtproto/tl/rpc/ping.rb +0 -18
  110. data/lib/mtproto/tl/rpc/pong.rb +0 -46
  111. data/lib/mtproto/tl/rpc/updates/difference.rb +0 -332
  112. data/lib/mtproto/tl/rpc/updates/get_difference.rb +0 -42
  113. data/lib/mtproto/tl/rpc/updates/get_state.rb +0 -17
  114. data/lib/mtproto/tl/rpc/updates/state.rb +0 -59
  115. data/lib/mtproto/tl/rpc/users/get_users.rb +0 -25
  116. data/lib/mtproto/tl/rpc/users/users.rb +0 -99
  117. data/lib/mtproto/tl/sent_code.rb +0 -128
@@ -5,86 +5,97 @@ require 'timeout'
5
5
 
6
6
  module MTProto
7
7
  module Transport
8
- class ConnectionError < StandardError; end
9
-
10
8
  class TCPConnection
11
- attr_reader :host, :port, :codec
9
+ attr_reader :host, :port
10
+ attr_accessor :wait_timeout, :read_timeout
12
11
 
13
- def initialize(host, port, codec)
12
+ def initialize(host, port, codec_class: AbridgedPacketCodec, wait_timeout: 60, read_timeout: 3)
14
13
  @host = host
15
14
  @port = port
16
- @codec = codec
15
+ @codec_class = codec_class
16
+ @wait_timeout = wait_timeout
17
+ @read_timeout = read_timeout
17
18
  @socket = nil
19
+ @codec = nil
18
20
  end
19
21
 
20
22
  def connect!
21
23
  return if connected?
22
24
 
23
25
  @socket = TCPSocket.new(@host, @port)
26
+ @codec = @codec_class.new(@socket)
24
27
 
25
- send_init_tag if @codec.class.const_defined?(:TAG)
28
+ write_init_tag
26
29
  end
27
30
 
28
- def connected?
29
- !@socket.nil? && !@socket.closed?
31
+ def disconnect!
32
+ return unless @socket
33
+
34
+ @socket.close
35
+ rescue StandardError
36
+ nil
37
+ ensure
38
+ @socket = nil
39
+ @codec = nil
30
40
  end
31
41
 
32
- def send(data)
33
- raise ConnectionError, 'Not connected' unless connected?
42
+ def not_connected?
43
+ @socket.nil? || @socket.closed?
44
+ end
34
45
 
35
- encoded = @codec.encode_packet(data)
36
- @socket.write(encoded)
46
+ def connected?
47
+ not not_connected?
37
48
  end
38
49
 
39
- def recv(timeout: 60)
40
- raise ConnectionError, 'Not connected' unless connected?
50
+ def send(packet)
51
+ raise NotConnectedError, 'Not connected' unless connected?
41
52
 
42
- Timeout.timeout(timeout) do
43
- read_packet
44
- end
45
- rescue Timeout::Error
46
- raise ConnectionError, 'Receive timeout'
53
+ @codec.send(packet)
47
54
  end
48
55
 
49
- def close
50
- return unless @socket
56
+ def receive(&)
57
+ raise NotConnectedError, 'Not connected' unless connected?
51
58
 
52
- @socket.close
53
- rescue StandardError
54
- nil
55
- ensure
56
- @socket = nil
59
+ if block_given?
60
+ receive_loop(&)
61
+ else
62
+ receive_once
63
+ end
57
64
  end
58
65
 
59
66
  private
60
67
 
61
- def send_init_tag
62
- tag = @codec.class.const_get(:TAG)
63
- @socket.write(tag) if tag
64
- end
68
+ def receive_once
69
+ return nil unless @socket.wait_readable(@wait_timeout)
65
70
 
66
- def read_packet
67
- first_byte = read_exactly(1)
68
- length = first_byte.unpack1('C')
71
+ read_packet
72
+ end
69
73
 
70
- if length >= 127
71
- length_bytes = read_exactly(3)
72
- length = (length_bytes + "\x00").unpack1('L<')
74
+ def receive_loop
75
+ loop do
76
+ @socket.wait_readable
77
+ packet = read_packet
78
+ yield packet, nil
79
+ rescue ConnectionClosedError, NotConnectedError
80
+ raise
81
+ rescue PacketReadError => e
82
+ yield nil, e
73
83
  end
84
+ end
74
85
 
75
- actual_length = length << 2
76
- read_exactly(actual_length)
86
+ def read_packet
87
+ Timeout.timeout(@read_timeout) { @codec.scan }
88
+ rescue Timeout::Error
89
+ raise PacketReadError, 'Packet read timeout'
90
+ rescue IOError, Errno::ECONNRESET => e
91
+ raise ConnectionClosedError, e.message
77
92
  end
78
93
 
79
- def read_exactly(bytes_needed)
80
- result = ''.b
81
- while result.bytesize < bytes_needed
82
- chunk = @socket.read(bytes_needed - result.bytesize)
83
- raise ConnectionError, 'EOF while reading' if chunk.nil? || chunk.empty?
94
+ def write_init_tag
95
+ return unless @codec_class.const_defined?(:TAG)
84
96
 
85
- result += chunk
86
- end
87
- result
97
+ tag = @codec_class.const_get(:TAG)
98
+ @socket.write tag if tag
88
99
  end
89
100
  end
90
101
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class BadMsgNotification
6
6
  CONSTRUCTOR = 0xa7eff811
7
7
 
@@ -28,16 +28,16 @@ module MTProto
28
28
 
29
29
  def error_message
30
30
  case @error_code
31
- when 16 then "msg_id too low (client time is wrong)"
32
- when 17 then "msg_id too high (client time needs sync)"
33
- when 18 then "incorrect two lower order msg_id bits (must be divisible by 4)"
34
- when 19 then "container msg_id is the same as previously received"
35
- when 20 then "message too old"
36
- when 32 then "msg_seqno too low"
37
- when 33 then "msg_seqno too high"
38
- when 34 then "even msg_seqno expected but odd received"
39
- when 35 then "odd msg_seqno expected but even received"
40
- when 48 then "incorrect server salt"
31
+ when 16 then 'msg_id too low (client time is wrong)'
32
+ when 17 then 'msg_id too high (client time needs sync)'
33
+ when 18 then 'incorrect two lower order msg_id bits (must be divisible by 4)'
34
+ when 19 then 'container msg_id is the same as previously received'
35
+ when 20 then 'message too old'
36
+ when 32 then 'msg_seqno too low'
37
+ when 33 then 'msg_seqno too high'
38
+ when 34 then 'even msg_seqno expected but odd received'
39
+ when 35 then 'odd msg_seqno expected but even received'
40
+ when 48 then 'incorrect server salt'
41
41
  else "unknown error code #{@error_code}"
42
42
  end
43
43
  end
@@ -3,7 +3,7 @@
3
3
  require_relative 'serializer'
4
4
 
5
5
  module MTProto
6
- module TL
6
+ module Type
7
7
  class ClientDHInnerData
8
8
  CONSTRUCTOR = 0x6643b654
9
9
 
@@ -4,7 +4,7 @@ require 'zlib'
4
4
  require 'stringio'
5
5
 
6
6
  module MTProto
7
- module TL
7
+ module Type
8
8
  module GzipPacked
9
9
  CONSTRUCTOR = 0x3072cfa1
10
10
 
@@ -19,11 +19,11 @@ module MTProto
19
19
 
20
20
  if length_byte == 254
21
21
  length_bytes = data[offset, 3]
22
- length = (length_bytes + "\x00").unpack1('L<')
22
+ length = "#{length_bytes}\u0000".unpack1('L<')
23
23
  offset += 3
24
24
  puts " [GZIP] Extended length: #{length} bytes" if $DEBUG
25
25
  elsif length_byte == 255
26
- raise "Invalid TL string length: 255"
26
+ raise 'Invalid TL string length: 255'
27
27
  else
28
28
  length = length_byte
29
29
  puts " [GZIP] Short length: #{length} bytes" if $DEBUG
@@ -32,7 +32,9 @@ module MTProto
32
32
  raise "Invalid length: #{length.inspect}" unless length.is_a?(Integer) && length > 0
33
33
 
34
34
  compressed_data = data[offset, length]
35
- raise "Not enough data: expected #{length}, got #{compressed_data&.bytesize}" if compressed_data.nil? || compressed_data.bytesize < length
35
+ if compressed_data.nil? || compressed_data.bytesize < length
36
+ raise "Not enough data: expected #{length}, got #{compressed_data&.bytesize}"
37
+ end
36
38
 
37
39
  Zlib::GzipReader.new(StringIO.new(compressed_data)).read.force_encoding(Encoding::BINARY)
38
40
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class Message
6
6
  attr_reader :auth_key_id, :msg_id, :body
7
7
 
@@ -22,8 +22,8 @@ module MTProto
22
22
  def self.deserialize(data)
23
23
  if data.bytesize < 20
24
24
  raise(ArgumentError,
25
- "Invalid MTProto message: expected at least 20 bytes, got #{data.bytesize} bytes (hex: #{data.unpack1('H*')})",
26
- )
25
+ 'Invalid MTProto message: expected at least 20 bytes, ' \
26
+ "got #{data.bytesize} bytes (hex: #{data.unpack1('H*')})")
27
27
  end
28
28
 
29
29
  auth_key_id = data[0, 8].unpack1('Q<')
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class MsgContainer
6
6
  CONSTRUCTOR = 0x73f1f8dc
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class NewSessionCreated
6
6
  CONSTRUCTOR = 0x9ec20908
7
7
 
@@ -3,7 +3,7 @@
3
3
  require_relative 'serializer'
4
4
 
5
5
  module MTProto
6
- module TL
6
+ module Type
7
7
  class PQInnerData
8
8
  CONSTRUCTOR_DC = 0xa9f55f95
9
9
  CONSTRUCTOR_TEMP_DC = 0x56fddf88
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class RpcError
6
6
  CONSTRUCTOR = 0x2144ca19
7
7
 
@@ -16,7 +16,6 @@ module MTProto
16
16
  offset += 1
17
17
 
18
18
  error_message = data[offset, message_length]
19
- offset += message_length
20
19
 
21
20
  new(error_code: error_code, error_message: error_message)
22
21
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  module Serializer
6
6
  module_function
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- module TL
4
+ module Type
5
5
  class ServerDHInnerData
6
6
  CONSTRUCTOR = 0xb5890dba
7
7
 
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'rpc/get_updates_state'
4
- require_relative 'rpc/get_updates_difference'
5
-
6
3
  module MTProto
7
4
  class UpdatesPoller
8
5
  attr_reader :state, :running
@@ -14,7 +11,7 @@ module MTProto
14
11
  @running = false
15
12
  @on_message_callbacks = []
16
13
  @on_update_callbacks = []
17
- @users_cache = {} # Cache user_id => access_hash
14
+ @users_cache = {}
18
15
  end
19
16
 
20
17
  def on_message(&block)
@@ -27,11 +24,11 @@ module MTProto
27
24
 
28
25
  def start
29
26
  raise 'Already running' if @running
30
- raise 'Auth key not generated' unless @client.auth_key
27
+ raise 'Auth key not set' unless @client.auth_key?
31
28
 
32
29
  @running = true
33
30
 
34
- @state = RPC::GetUpdatesState.new(@client).call
31
+ @state = call_with_retry { @client.api.get_updates_state }
35
32
 
36
33
  poll_loop
37
34
  end
@@ -45,65 +42,72 @@ module MTProto
45
42
  def poll_loop
46
43
  while @running
47
44
  begin
48
- difference = RPC::GetUpdatesDifference.new(@client).call(
49
- pts: @state[:pts],
50
- date: @state[:date],
51
- qts: @state[:qts]
52
- )
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
53
52
 
54
53
  process_difference(difference)
55
54
 
56
- if difference[:state]
57
- @state = @state.merge(difference[:state])
58
- elsif difference[:type] == :too_long
59
- @state = RPC::GetUpdatesState.new(@client).call
60
- elsif difference[:date]
61
- @state[:date] = difference[:date]
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
62
61
  end
63
62
 
64
63
  sleep @poll_interval
65
64
  rescue MTProto::RpcError => e
66
- puts "RPC Error during polling: #{e.message}"
65
+ warn "RPC Error during polling: #{e.message}"
67
66
  sleep @poll_interval
68
67
  rescue StandardError => e
69
- puts "Error during polling: #{e.class} - #{e.message}"
70
- puts e.backtrace.first(5)
68
+ warn "Error during polling: #{e.class} - #{e.message}"
69
+ warn e.backtrace.first(5).join("\n")
71
70
  sleep @poll_interval
72
71
  end
73
72
  end
74
73
  end
75
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
+
76
86
  def process_difference(difference)
77
- case difference[:type]
87
+ case difference.type
78
88
  when :empty
79
89
  nil
80
90
  when :difference, :slice, :short_message
81
- if difference[:users]
82
- difference[:users].each do |user|
83
- if user[:access_hash]
84
- @users_cache[user[:id]] = user[:access_hash]
85
- end
86
- end
91
+ difference.users&.each do |user|
92
+ @users_cache[user[:id]] = user[:access_hash] if user[:access_hash]
87
93
  end
88
94
 
89
- if difference[:new_messages] && !difference[:new_messages].empty?
90
- difference[:new_messages].each do |message|
95
+ if difference.new_messages && !difference.new_messages.empty?
96
+ difference.new_messages.each do |message|
91
97
  process_message(message)
92
98
  end
93
99
  end
94
100
 
95
101
  @on_update_callbacks.each { |callback| callback.call(difference) }
96
102
  when :too_long
97
- puts "Update gap too long (pts=#{difference[:pts]}), refreshing state..."
103
+ puts "Update gap too long (pts=#{difference.pts}), refreshing state..."
98
104
  end
99
105
  end
100
106
 
101
107
  def process_message(message)
102
108
  return unless message
103
109
 
104
- if message[:user_id] && @users_cache[message[:user_id]]
105
- message[:access_hash] = @users_cache[message[:user_id]]
106
- end
110
+ message[:access_hash] = @users_cache[message[:user_id]] if message[:user_id] && @users_cache[message[:user_id]]
107
111
 
108
112
  @on_message_callbacks.each { |callback| callback.call(message) }
109
113
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MTProto
4
- VERSION = '0.0.7'
4
+ VERSION = '0.0.9'
5
5
  end
data/lib/mtproto.rb CHANGED
@@ -2,21 +2,29 @@
2
2
 
3
3
  require_relative 'mtproto/version'
4
4
  require_relative 'mtproto/errors'
5
+ require_relative 'mtproto/binary'
6
+ require_relative 'mtproto/delegate_methods'
7
+ require_relative 'mtproto/transport/errors'
8
+ require_relative 'mtproto/transport/packet'
5
9
  require_relative 'mtproto/transport/abridged_packet_codec'
6
10
  require_relative 'mtproto/transport/tcp_connection'
7
- require_relative 'mtproto/tl/message'
8
- require_relative 'mtproto/tl/serializer'
9
- require_relative 'mtproto/tl/p_q_inner_data'
10
- require_relative 'mtproto/tl/server_dh_inner_data'
11
- require_relative 'mtproto/tl/client_dh_inner_data'
12
- require_relative 'mtproto/tl/bad_msg_notification'
13
- require_relative 'mtproto/tl/msg_container'
14
- require_relative 'mtproto/tl/new_session_created'
15
- require_relative 'mtproto/tl/rpc_error'
16
- require_relative 'mtproto/tl/gzip_packed'
17
- require_relative 'mtproto/tl/config'
18
- require_relative 'mtproto/tl/code_settings'
19
- require_relative 'mtproto/tl/sent_code'
11
+ require_relative 'mtproto/transport/connection'
12
+ require_relative 'mtproto/message/message'
13
+ require_relative 'mtproto/tl/constructors'
14
+ require_relative 'mtproto/tl/object'
15
+ require_relative 'mtproto/tl/objects/update'
16
+ require_relative 'mtproto/tl/objects/update_short'
17
+ require_relative 'mtproto/tl/objects/update_short_message'
18
+ require_relative 'mtproto/type/message'
19
+ require_relative 'mtproto/type/serializer'
20
+ require_relative 'mtproto/type/pq_inner_data'
21
+ require_relative 'mtproto/type/server_dh_inner_data'
22
+ require_relative 'mtproto/type/client_dh_inner_data'
23
+ require_relative 'mtproto/type/bad_msg_notification'
24
+ require_relative 'mtproto/type/msg_container'
25
+ require_relative 'mtproto/type/new_session_created'
26
+ require_relative 'mtproto/type/rpc_error'
27
+ require_relative 'mtproto/type/gzip_packed'
20
28
  require_relative 'mtproto/crypto/rsa_key'
21
29
  require_relative 'mtproto/crypto/factorization'
22
30
  require_relative 'mtproto/crypto/aes_ige'
@@ -29,15 +37,6 @@ require_relative 'mtproto/auth_key_generator'
29
37
  require_relative 'mtproto/session'
30
38
  require_relative 'mtproto/encrypted_message'
31
39
  require_relative 'mtproto/client'
32
- require_relative 'mtproto/rpc/ping'
33
- require_relative 'mtproto/rpc/get_config'
34
- require_relative 'mtproto/rpc/send_code'
35
- require_relative 'mtproto/rpc/sign_in'
36
- require_relative 'mtproto/rpc/get_users'
37
- require_relative 'mtproto/rpc/send_message'
38
- require_relative 'mtproto/rpc/get_updates_state'
39
- require_relative 'mtproto/rpc/get_updates_difference'
40
- require_relative 'mtproto/rpc/get_contacts'
41
40
  require_relative 'mtproto/updates_poller'
42
41
 
43
42
  module MTProto
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'net/http'
6
+ require 'uri'
7
+
8
+ SCHEMAS = {
9
+ 'https://core.telegram.org/schema/mtproto-json' => 'MTProto',
10
+ 'https://core.telegram.org/schema/json' => 'API'
11
+ }.freeze
12
+
13
+ def fetch_schema(url)
14
+ uri = URI(url)
15
+ response = Net::HTTP.get(uri)
16
+ JSON.parse(response)
17
+ end
18
+
19
+ def signed_to_unsigned(id)
20
+ id = id.to_i
21
+ id < 0 ? id + (2**32) : id
22
+ end
23
+
24
+ entries = {}
25
+
26
+ SCHEMAS.each do |url, label|
27
+ schema = fetch_schema(url)
28
+ puts "#{label}: #{schema['constructors'].size} constructors, #{schema['methods'].size} methods"
29
+
30
+ schema['constructors'].each do |c|
31
+ hex = signed_to_unsigned(c['id'])
32
+ entries[hex] = c['predicate']
33
+ end
34
+
35
+ schema['methods'].each do |m|
36
+ hex = signed_to_unsigned(m['id'])
37
+ entries[hex] = m['method']
38
+ end
39
+ end
40
+
41
+ puts "Total: #{entries.size} entries"
42
+
43
+ lines = entries.sort_by { |hex, _| hex }.map do |hex, name|
44
+ " 0x#{hex.to_s(16).rjust(8, '0')} => '#{name}'"
45
+ end
46
+
47
+ output = <<~RUBY
48
+ # frozen_string_literal: true
49
+
50
+ # Auto-generated from Telegram TL schemas.
51
+ # Run: ruby scripts/generate_constructors.rb
52
+
53
+ module MTProto
54
+ module TL
55
+ module Constructors
56
+ NAMES = {
57
+ #{lines.join(",\n")}
58
+ }.freeze
59
+ end
60
+ end
61
+ end
62
+ RUBY
63
+
64
+ File.write(File.expand_path('../lib/mtproto/tl/constructors.rb', __dir__), output)
65
+ puts 'Written to lib/mtproto/tl/constructors.rb'