tdlib-ruby 1.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.gitmodules +0 -0
- data/.travis.yml +6 -3
- data/ChangeLog.md +22 -0
- data/README.md +59 -48
- data/bin/build +12 -0
- data/lib/tdlib-ruby.rb +5 -2
- data/lib/tdlib/api.rb +20 -15
- data/lib/tdlib/client.rb +130 -126
- data/lib/tdlib/errors.rb +29 -5
- data/lib/tdlib/update_handler.rb +39 -0
- data/lib/tdlib/update_manager.rb +24 -21
- data/lib/tdlib/version.rb +1 -1
- data/spec/integration/tdlib_spec.rb +28 -15
- data/tdlib-ruby.gemspec +7 -14
- metadata +46 -16
- data/lib/tdlib/utils.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 851d0531bf3de68a43c0f72acf22aa549142fd1b866f915df4af2bf919408211
|
4
|
+
data.tar.gz: '0320249654babf8f873936c5e74e09a03b24d1689a6019f9d7edccfc72c5d96c'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a8ba653e0261bde8fd13e237846f052520d7d9cca6fd808cbbf31937a706978b7b04273931192b5494e6e004c1f06c823ed65615f3a52d5cbbd8da7c5c5bbe2
|
7
|
+
data.tar.gz: 93c09fc96b0881d372b46f4f2970b803f99f2bc569657946a431687b46ae6d8b0f47aa6e7437c580ede440248b3cc3802986dc9676084439616348107a57cdcc
|
data/.gitignore
CHANGED
data/.gitmodules
ADDED
File without changes
|
data/.travis.yml
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.
|
3
|
+
- 2.6.7
|
4
|
+
- 2.7.3
|
5
|
+
- 3.0.1
|
6
|
+
|
5
7
|
addons:
|
6
8
|
apt:
|
7
9
|
sources:
|
@@ -19,8 +21,9 @@ env:
|
|
19
21
|
global:
|
20
22
|
secure: DmAoRsr+dTPVNs486nBXzChjzCCVdoxfmSbvqMBBl0v8uuUIZD1rSfYKcEaL5pmE7vgYq3X+3Dk0gf4ef/p2xPVKqFKrkBiF/7t06WgQTH7003gHMLq3aC7R9+1xvqJDzpoc6UB59Y1fOJBe5YfqDuw1dT9a46tzY2uzoVpEpbN8M/hssaKf6Wuzvpz5yekFeXq2raPwi3aOqvkSG+ODoacVdYQgJ4Vn0//CI2HzWijkQCvdsefWQUKkbgtuLWRp3UNy8AEhVWzQnTcSM7oc+MwMsOI/90DZkTP5n2WJl/CFTM5b70VyrIciG92SvTAhhBo/p7t3QBJa6kJMPXAHh5q+3wqVQA411+CoVF48bO5rKjKY3Ply49uqAzVJRh+Tkhf5uC1pHiZ6QKGxu1Czde+mKItBpaDmJFmQi0CSdv2WYXLnJWOQIO6vc2P3liwpMDRDyaGWOQtUYS+gHAlRbD4NPycIkGjkcjmLMqSEEO1TdCpM+CYwTvNTkRS+9HrWXZNdEfWORDYHgYohoIP6kY6XWSgunUb6F6pVxLoPWJNEBEVuIMZeOa/s9oklxBzD5XXIzBx4QsPYanvfxoN1uOcXlBXbOGqwiqb+urokNDw+BzWhbA+xY03U2+yO0Ujh3HQDyMDtrXEQfaPC0SxpEvIINVYwznG4sMKvbOaCVSo=
|
21
23
|
before_install:
|
24
|
+
- gem install -v 2.1.2 bundler
|
22
25
|
- set -e
|
23
|
-
- git clone https://github.com/tdlib/td
|
26
|
+
- git clone https://github.com/tdlib/td.git
|
24
27
|
- cd td
|
25
28
|
- mkdir -p build
|
26
29
|
- cd build
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
### 3.0.1 / 2020-06-29
|
2
|
+
|
3
|
+
* Fix client dispose
|
4
|
+
|
5
|
+
### 3.0.0 / 2020-06-28
|
6
|
+
|
7
|
+
* Extract schema to separate gem
|
8
|
+
|
9
|
+
### 2.1.0 / 2019-10-18
|
10
|
+
|
11
|
+
* Support tdlib 1.5
|
12
|
+
* Fix TD::Client#dispose race condition and client crash
|
13
|
+
|
14
|
+
### 2.0.0 / 2019-02-08
|
15
|
+
|
16
|
+
* Generated types and client functions
|
17
|
+
* Async handlers
|
18
|
+
* Use ffi instead of fiddle
|
19
|
+
* Use Concurrent::Promises
|
20
|
+
* TD errors handling in promises
|
21
|
+
* Add use_file_database setting to config
|
22
|
+
|
1
23
|
### 1.0.0 / 2018-05-27
|
2
24
|
|
3
25
|
* Return promises from TD::Client#broadcast
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# tdlib-ruby
|
2
2
|
|
3
|
-
[![Maintainability](https://api.codeclimate.com/v1/badges/9362ca2682b7edbae205/maintainability)](https://codeclimate.com/github/centosadmin/tdlib-ruby/maintainability) [![Build Status](https://travis-ci.org/
|
3
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/9362ca2682b7edbae205/maintainability)](https://codeclimate.com/github/centosadmin/tdlib-ruby/maintainability) [![Build Status](https://travis-ci.org/southbridgeio/tdlib-ruby.svg?branch=master)](https://travis-ci.org/centosadmin/tdlib-ruby)
|
4
4
|
|
5
5
|
## Description
|
6
6
|
|
@@ -8,7 +8,7 @@ Ruby bindings and client for TDLib (Telegram database library).
|
|
8
8
|
|
9
9
|
## Requirements
|
10
10
|
|
11
|
-
* Ruby 2.
|
11
|
+
* Ruby 2.4+
|
12
12
|
* Compiled [tdlib](https://github.com/tdlib/td)
|
13
13
|
|
14
14
|
We have precompiled versions for CentOS 6 & 7 in our repositories:
|
@@ -23,6 +23,15 @@ http://rpms.southbridge.ru/rhel7/stable/SRPMS/
|
|
23
23
|
|
24
24
|
http://rpms.southbridge.ru/rhel6/stable/SRPMS/
|
25
25
|
|
26
|
+
## Compatibility table
|
27
|
+
|
28
|
+
| Gem Version | | tdlib version |
|
29
|
+
|:-------------:|:-:| :-----------: |
|
30
|
+
| 1.x | → | 1.0 - 1.2 |
|
31
|
+
| 2.0 | → | 1.3 |
|
32
|
+
| 2.1 | → | 1.5 |
|
33
|
+
| 2.2 | → | 1.6 |
|
34
|
+
|
26
35
|
## Install
|
27
36
|
|
28
37
|
Add to your gemfile:
|
@@ -35,7 +44,7 @@ and run *bundle install*.
|
|
35
44
|
|
36
45
|
Or just run *gem install tdlib-ruby*
|
37
46
|
|
38
|
-
## Basic example
|
47
|
+
## Basic authentication example
|
39
48
|
|
40
49
|
```ruby
|
41
50
|
require 'tdlib-ruby'
|
@@ -54,59 +63,52 @@ client = TD::Client.new
|
|
54
63
|
begin
|
55
64
|
state = nil
|
56
65
|
|
57
|
-
client.on(
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
client.on(TD::Types::Update::AuthorizationState) do |update|
|
67
|
+
state = case update.authorization_state
|
68
|
+
when TD::Types::AuthorizationState::WaitPhoneNumber
|
69
|
+
:wait_phone_number
|
70
|
+
when TD::Types::AuthorizationState::WaitCode
|
71
|
+
:wait_code
|
72
|
+
when TD::Types::AuthorizationState::WaitPassword
|
73
|
+
:wait_password
|
74
|
+
when TD::Types::AuthorizationState::Ready
|
75
|
+
:ready
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
70
79
|
end
|
80
|
+
|
81
|
+
client.connect
|
71
82
|
|
72
83
|
loop do
|
73
84
|
case state
|
74
|
-
when :
|
75
|
-
|
85
|
+
when :wait_phone_number
|
86
|
+
puts 'Please, enter your phone number:'
|
76
87
|
phone = STDIN.gets.strip
|
77
|
-
|
78
|
-
'@type' => 'setAuthenticationPhoneNumber',
|
79
|
-
'phone_number' => phone
|
80
|
-
}
|
81
|
-
client.broadcast_and_receive(params)
|
88
|
+
client.set_authentication_phone_number(phone, nil).wait
|
82
89
|
when :wait_code
|
83
|
-
|
90
|
+
puts 'Please, enter code from SMS:'
|
84
91
|
code = STDIN.gets.strip
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
client.
|
92
|
+
client.check_authentication_code(code).wait
|
93
|
+
when :wait_password
|
94
|
+
puts 'Please, enter 2FA password:'
|
95
|
+
password = STDIN.gets.strip
|
96
|
+
client.check_authentication_password(password).wait
|
90
97
|
when :ready
|
91
|
-
@me =
|
98
|
+
client.get_me.then { |user| @me = user }.rescue { |err| puts "error: #{err}" }.wait
|
92
99
|
break
|
93
100
|
end
|
101
|
+
sleep 0.1
|
94
102
|
end
|
95
103
|
|
96
104
|
ensure
|
97
|
-
client.
|
105
|
+
client.dispose
|
98
106
|
end
|
99
107
|
|
100
108
|
p @me
|
101
109
|
```
|
102
110
|
|
103
|
-
|
104
|
-
|
105
|
-
From version 1.0 TD::Client##broadcast returns [Concurrent::Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html) object.
|
106
|
-
|
107
|
-
```ruby
|
108
|
-
me = client.broadcast('@type' => 'getMe').then { |result| puts result }.rescue { |error| puts error }.value
|
109
|
-
```
|
111
|
+
Client methods are being executed asynchronously and return Concurrent::Promises::Future (see: https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md).
|
110
112
|
|
111
113
|
## Configuration
|
112
114
|
|
@@ -118,17 +120,18 @@ TD.configure do |config|
|
|
118
120
|
config.client.api_id = 12345
|
119
121
|
config.client.api_hash = 'your_api_hash'
|
120
122
|
config.client.use_test_dc = true # default: false
|
121
|
-
config.database_directory = 'path/to/db/dir' # default: "#{Dir.home}/.tdlib-ruby/db"
|
122
|
-
config.files_directory = 'path/to/files/dir' # default: "#{Dir.home}/.tdlib-ruby/files"
|
123
|
+
config.client.database_directory = 'path/to/db/dir' # default: "#{Dir.home}/.tdlib-ruby/db"
|
124
|
+
config.client.files_directory = 'path/to/files/dir' # default: "#{Dir.home}/.tdlib-ruby/files"
|
125
|
+
config.client.use_file_database = true # default: true
|
123
126
|
config.client.use_chat_info_database = true # default: true
|
124
|
-
config.use_secret_chats = true # default: true
|
125
|
-
config.use_message_database = true # default: true
|
126
|
-
config.system_language_code = 'ru' # default: 'en'
|
127
|
-
config.device_model = 'Some device model' # default: 'Ruby TD client'
|
128
|
-
config.system_version = '42' # default: 'Unknown'
|
129
|
-
config.application_version = '1.0' # default: '1.0'
|
130
|
-
config.enable_storage_optimizer = true # default: true
|
131
|
-
config.ignore_file_names = true # default: false
|
127
|
+
config.client.use_secret_chats = true # default: true
|
128
|
+
config.client.use_message_database = true # default: true
|
129
|
+
config.client.system_language_code = 'ru' # default: 'en'
|
130
|
+
config.client.device_model = 'Some device model' # default: 'Ruby TD client'
|
131
|
+
config.client.system_version = '42' # default: 'Unknown'
|
132
|
+
config.client.application_version = '1.0' # default: '1.0'
|
133
|
+
config.client.enable_storage_optimizer = true # default: true
|
134
|
+
config.client.ignore_file_names = true # default: false
|
132
135
|
end
|
133
136
|
```
|
134
137
|
|
@@ -153,6 +156,12 @@ TD::Client.new(database_directory: 'will override value from config',
|
|
153
156
|
files_directory: 'will override value from config')
|
154
157
|
```
|
155
158
|
|
159
|
+
If the tdlib schema changes, then `./bin/parse` can be run to
|
160
|
+
synchronize the Ruby types with the new schema. Please look through
|
161
|
+
`lib/tdlib/client_methods.rb` carefully, especially the set_password
|
162
|
+
method!
|
163
|
+
|
164
|
+
|
156
165
|
## License
|
157
166
|
|
158
167
|
[MIT](https://github.com/centosadmin/tdlib-ruby/blob/master/LICENSE.txt)
|
@@ -160,3 +169,5 @@ TD::Client.new(database_directory: 'will override value from config',
|
|
160
169
|
## Authors
|
161
170
|
|
162
171
|
The gem is designed by [Southbridge](https://southbridge.io)
|
172
|
+
|
173
|
+
Typeization made by [Yuri Mikhaylov](https://github.com/yurijmi)
|
data/bin/build
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'etc'
|
4
|
+
|
5
|
+
`
|
6
|
+
set -e
|
7
|
+
cd td
|
8
|
+
mkdir -p build
|
9
|
+
cd build
|
10
|
+
cmake -DCMAKE_BUILD_TYPE=Release #{'-DOPENSSL_ROOT_DIR=/opt/homebrew/Cellar/openssl@1.1/1.1.1k/' if RbConfig::CONFIG['host_os'] =~ /darwin|mac os/} -DCMAKE_INSTALL_PREFIX:PATH=../tdlib ..
|
11
|
+
cmake --build . --target install -j #{Etc.nprocessors}
|
12
|
+
`
|
data/lib/tdlib-ruby.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'tdlib/version'
|
2
2
|
require 'dry/configurable'
|
3
|
+
require 'concurrent-ruby'
|
3
4
|
|
4
5
|
module TD
|
5
6
|
extend Dry::Configurable
|
@@ -15,11 +16,12 @@ module TD
|
|
15
16
|
setting :encryption_key
|
16
17
|
|
17
18
|
setting :client do
|
18
|
-
setting :api_id
|
19
|
+
setting :api_id, &:to_i
|
19
20
|
setting :api_hash
|
20
21
|
setting :use_test_dc, false
|
21
22
|
setting :database_directory, "#{Dir.home}/.tdlib-ruby/db"
|
22
23
|
setting :files_directory, "#{Dir.home}/.tdlib-ruby/data"
|
24
|
+
setting :use_file_database, true
|
23
25
|
setting :use_chat_info_database, true
|
24
26
|
setting :use_secret_chats, true
|
25
27
|
setting :use_message_database, true
|
@@ -32,8 +34,9 @@ module TD
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
37
|
+
require 'tdlib-schema'
|
35
38
|
require 'tdlib/errors'
|
36
39
|
require 'tdlib/api'
|
37
|
-
require 'tdlib/utils'
|
38
40
|
require 'tdlib/client'
|
41
|
+
require 'tdlib/update_handler'
|
39
42
|
require 'tdlib/update_manager'
|
data/lib/tdlib/api.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'fiddle/import'
|
2
1
|
require 'json'
|
2
|
+
require 'ffi'
|
3
3
|
|
4
4
|
module TD::Api
|
5
5
|
module_function
|
@@ -18,7 +18,7 @@ module TD::Api
|
|
18
18
|
|
19
19
|
def client_receive(client, timeout)
|
20
20
|
update = Dl.td_json_client_receive(client, timeout)
|
21
|
-
|
21
|
+
JSON.parse(update) if update
|
22
22
|
end
|
23
23
|
|
24
24
|
def client_destroy(client)
|
@@ -34,7 +34,7 @@ module TD::Api
|
|
34
34
|
end
|
35
35
|
|
36
36
|
module Dl
|
37
|
-
extend
|
37
|
+
extend FFI::Library
|
38
38
|
|
39
39
|
@mutex = Mutex.new
|
40
40
|
|
@@ -42,16 +42,18 @@ module TD::Api
|
|
42
42
|
|
43
43
|
def method_missing(method_name, *args)
|
44
44
|
@mutex.synchronize do
|
45
|
-
return if respond_to?(method_name)
|
46
|
-
dlload(find_lib)
|
45
|
+
return public_send(method_name, *args) if respond_to?(method_name)
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
find_lib
|
48
|
+
|
49
|
+
attach_function :td_json_client_create, [], :pointer
|
50
|
+
attach_function :td_json_client_receive, [:pointer, :double], :string, blocking: true
|
51
|
+
attach_function :td_json_client_send, [:pointer, :string], :pointer, blocking: true
|
52
|
+
attach_function :td_json_client_execute, [:pointer, :string], :string, blocking: true
|
53
|
+
attach_function :td_json_client_destroy, [:pointer], :void
|
54
|
+
attach_function :td_set_log_file_path, [:string], :int
|
55
|
+
attach_function :td_set_log_max_file_size, [:long_long], :void
|
56
|
+
attach_function :td_set_log_verbosity_level, [:int], :void
|
55
57
|
|
56
58
|
undef method_missing
|
57
59
|
public_send(method_name, *args)
|
@@ -66,9 +68,12 @@ module TD::Api
|
|
66
68
|
elsif defined?(Rails) && File.exist?(Rails.root.join('vendor', file_name))
|
67
69
|
Rails.root.join('vendor')
|
68
70
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
full_path = File.join(lib_path.to_s, file_name)
|
72
|
+
ffi_lib full_path
|
73
|
+
full_path
|
74
|
+
rescue LoadError
|
75
|
+
ffi_lib 'tdjson'
|
76
|
+
ffi_libraries.first.name
|
72
77
|
end
|
73
78
|
|
74
79
|
def lib_extension
|
data/lib/tdlib/client.rb
CHANGED
@@ -1,108 +1,91 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
# Simple client for TDLib.
|
2
|
-
# @example
|
3
|
-
# TD.configure do |config|
|
4
|
-
# config.lib_path = 'path_to_tdlibjson'
|
5
|
-
# config.encryption_key = 'your_encryption_key'
|
6
|
-
#
|
7
|
-
# config.client.api_id = your_api_id
|
8
|
-
# config.client.api_hash = 'your_api_hash'
|
9
|
-
# end
|
10
|
-
#
|
11
|
-
# client = TD::Client.new
|
12
|
-
#
|
13
|
-
# begin
|
14
|
-
# state = nil
|
15
|
-
#
|
16
|
-
# client.on('updateAuthorizationState') do |update|
|
17
|
-
# next unless update.dig('authorization_state', '@type') == 'authorizationStateWaitPhoneNumber'
|
18
|
-
# state = :wait_phone
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# client.on('updateAuthorizationState') do |update|
|
22
|
-
# next unless update.dig('authorization_state', '@type') == 'authorizationStateWaitCode'
|
23
|
-
# state = :wait_code
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# client.on('updateAuthorizationState') do |update|
|
27
|
-
# next unless update.dig('authorization_state', '@type') == 'authorizationStateReady'
|
28
|
-
# state = :ready
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# loop do
|
32
|
-
# case state
|
33
|
-
# when :wait_phone
|
34
|
-
# p 'Please, enter your phone number:'
|
35
|
-
# phone = STDIN.gets.strip
|
36
|
-
# params = {
|
37
|
-
# '@type' => 'setAuthenticationPhoneNumber',
|
38
|
-
# 'phone_number' => phone
|
39
|
-
# }
|
40
|
-
# client.broadcast_and_receive(params)
|
41
|
-
# when :wait_code
|
42
|
-
# p 'Please, enter code from SMS:'
|
43
|
-
# code = STDIN.gets.strip
|
44
|
-
# params = {
|
45
|
-
# '@type' => 'checkAuthenticationCode',
|
46
|
-
# 'code' => code
|
47
|
-
# }
|
48
|
-
# client.broadcast_and_receive(params)
|
49
|
-
# when :ready
|
50
|
-
# @me = client.broadcast_and_receive('@type' => 'getMe')
|
51
|
-
# break
|
52
|
-
# end
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# ensure
|
56
|
-
# client.close
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# p @me
|
60
4
|
class TD::Client
|
61
5
|
include Concurrent
|
6
|
+
include TD::ClientMethods
|
62
7
|
|
63
8
|
TIMEOUT = 20
|
64
9
|
|
10
|
+
def self.ready(*args)
|
11
|
+
new(*args).connect
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [FFI::Pointer] td_client
|
15
|
+
# @param [TD::UpdateManager] update_manager
|
16
|
+
# @param [Numeric] timeout
|
17
|
+
# @param [Hash] extra_config optional configuration hash that will be merged into tdlib client configuration
|
65
18
|
def initialize(td_client = TD::Api.client_create,
|
66
19
|
update_manager = TD::UpdateManager.new(td_client),
|
67
|
-
|
20
|
+
timeout: TIMEOUT,
|
68
21
|
**extra_config)
|
69
22
|
@td_client = td_client
|
23
|
+
@ready = false
|
24
|
+
@alive = true
|
70
25
|
@update_manager = update_manager
|
26
|
+
@timeout = timeout
|
71
27
|
@config = TD.config.client.to_h.merge(extra_config)
|
72
|
-
@proxy = proxy
|
73
28
|
@ready_condition_mutex = Mutex.new
|
74
29
|
@ready_condition = ConditionVariable.new
|
75
|
-
|
76
|
-
|
30
|
+
end
|
31
|
+
|
32
|
+
# Adds initial authorization state handler and runs update manager
|
33
|
+
# Returns future that will be fulfilled when client is ready
|
34
|
+
# @return [Concurrent::Promises::Future]
|
35
|
+
def connect
|
36
|
+
on TD::Types::Update::AuthorizationState do |update|
|
37
|
+
case update.authorization_state
|
38
|
+
when TD::Types::AuthorizationState::WaitTdlibParameters
|
39
|
+
set_tdlib_parameters(parameters: TD::Types::TdlibParameters.new(**@config))
|
40
|
+
when TD::Types::AuthorizationState::WaitEncryptionKey
|
41
|
+
check_database_encryption_key(encryption_key: TD.config.encryption_key).then do
|
42
|
+
@ready_condition_mutex.synchronize do
|
43
|
+
@ready = true
|
44
|
+
@ready_condition.broadcast
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
# do nothing
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@update_manager.run(callback: method(:handle_update))
|
53
|
+
ready
|
77
54
|
end
|
78
55
|
|
79
56
|
# Sends asynchronous request to the TDLib client and returns Promise object
|
80
|
-
# @see
|
57
|
+
# @see TD::ClientMethods List of available queries as methods
|
58
|
+
# @see https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md
|
59
|
+
# Concurrent::Promise documentation
|
81
60
|
# @example
|
82
|
-
# client.broadcast(some_query).then { |result| puts result }.rescue
|
61
|
+
# client.broadcast(some_query).then { |result| puts result }.rescue { |error| puts [error.code, error.message] }
|
83
62
|
# @param [Hash] query
|
84
|
-
# @
|
85
|
-
|
86
|
-
|
87
|
-
|
63
|
+
# @return [Concurrent::Promises::Future]
|
64
|
+
def broadcast(query)
|
65
|
+
return dead_client_promise if dead?
|
66
|
+
|
67
|
+
Promises.future do
|
88
68
|
condition = ConditionVariable.new
|
89
|
-
extra =
|
69
|
+
extra = SecureRandom.uuid
|
90
70
|
result = nil
|
91
71
|
mutex = Mutex.new
|
92
|
-
|
93
|
-
|
72
|
+
|
73
|
+
@update_manager << TD::UpdateHandler.new(TD::Types::Base, extra, disposable: true) do |update|
|
94
74
|
mutex.synchronize do
|
95
75
|
result = update
|
96
|
-
@update_manager.remove_handler(handler)
|
97
76
|
condition.signal
|
98
77
|
end
|
99
78
|
end
|
100
|
-
|
79
|
+
|
101
80
|
query['@extra'] = extra
|
81
|
+
|
102
82
|
mutex.synchronize do
|
103
|
-
|
104
|
-
condition.wait(mutex, timeout)
|
105
|
-
|
83
|
+
send_to_td_client(query)
|
84
|
+
condition.wait(mutex, @timeout)
|
85
|
+
error = nil
|
86
|
+
error = result if result.is_a?(TD::Types::Error)
|
87
|
+
error = timeout_error if result.nil?
|
88
|
+
raise TD::Error.new(error) if error
|
106
89
|
result
|
107
90
|
end
|
108
91
|
end
|
@@ -111,8 +94,8 @@ class TD::Client
|
|
111
94
|
# Sends asynchronous request to the TDLib client and returns received update synchronously
|
112
95
|
# @param [Hash] query
|
113
96
|
# @return [Hash]
|
114
|
-
def fetch(query
|
115
|
-
broadcast(query
|
97
|
+
def fetch(query)
|
98
|
+
broadcast(query).value!
|
116
99
|
end
|
117
100
|
|
118
101
|
alias broadcast_and_receive fetch
|
@@ -121,70 +104,91 @@ class TD::Client
|
|
121
104
|
# Only a few requests can be executed synchronously
|
122
105
|
# @param [Hash] query
|
123
106
|
def execute(query)
|
107
|
+
return dead_client_error if dead?
|
124
108
|
TD::Api.client_execute(@td_client, query)
|
125
109
|
end
|
126
110
|
|
127
|
-
# Returns current authorization state (it's offline request)
|
128
|
-
# @return [Hash]
|
129
|
-
def authorization_state
|
130
|
-
broadcast_and_receive('@type' => 'getAuthorizationState')
|
131
|
-
end
|
132
|
-
|
133
111
|
# Binds passed block as a handler for updates with type of *update_type*
|
134
|
-
# @param [String] update_type
|
112
|
+
# @param [String, Class] update_type
|
135
113
|
# @yield [update] yields update to the block as soon as it's received
|
136
|
-
def on(update_type, &
|
137
|
-
|
138
|
-
|
139
|
-
|
114
|
+
def on(update_type, &action)
|
115
|
+
if update_type.is_a?(String)
|
116
|
+
if (type_const = TD::Types::LOOKUP_TABLE[update_type])
|
117
|
+
update_type = TD::Types.const_get("TD::Types::#{type_const}")
|
118
|
+
else
|
119
|
+
raise ArgumentError.new("Can't find class for #{update_type}")
|
120
|
+
end
|
140
121
|
end
|
141
|
-
|
122
|
+
|
123
|
+
unless update_type < TD::Types::Base
|
124
|
+
raise ArgumentError.new("Wrong type specified (#{update_type}). Should be of kind TD::Types::Base")
|
125
|
+
end
|
126
|
+
|
127
|
+
@update_manager << TD::UpdateHandler.new(update_type, &action)
|
142
128
|
end
|
143
129
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
130
|
+
# returns future that will be fulfilled when client is ready
|
131
|
+
# @return [Concurrent::Promises::Future]
|
132
|
+
def ready
|
133
|
+
return dead_client_promise if dead?
|
134
|
+
return Promises.fulfilled_future(self) if ready?
|
135
|
+
|
136
|
+
Promises.future do
|
137
|
+
@ready_condition_mutex.synchronize do
|
138
|
+
next self if @ready || (@ready_condition.wait(@ready_condition_mutex, @timeout) && @ready)
|
139
|
+
raise TD::Error.new(timeout_error)
|
140
|
+
end
|
148
141
|
end
|
149
142
|
end
|
150
143
|
|
144
|
+
# @deprecated
|
145
|
+
def on_ready(&action)
|
146
|
+
ready.then(&action).value!
|
147
|
+
end
|
148
|
+
|
151
149
|
# Stops update manager and destroys TDLib client
|
152
|
-
def
|
153
|
-
|
154
|
-
|
150
|
+
def dispose
|
151
|
+
return if dead?
|
152
|
+
close.then { get_authorization_state }
|
153
|
+
end
|
154
|
+
|
155
|
+
def alive?
|
156
|
+
@alive
|
157
|
+
end
|
158
|
+
|
159
|
+
def dead?
|
160
|
+
!alive?
|
161
|
+
end
|
162
|
+
|
163
|
+
def ready?
|
164
|
+
@ready
|
155
165
|
end
|
156
166
|
|
157
167
|
private
|
158
168
|
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
if TD.config.encryption_key
|
169
|
-
encryption_key_query['encryption_key'] = TD.config.encryption_key
|
170
|
-
end
|
169
|
+
def handle_update(update)
|
170
|
+
return unless update.is_a?(TD::Types::Update::AuthorizationState) && update.authorization_state.is_a?(TD::Types::AuthorizationState::Closed)
|
171
|
+
@alive = false
|
172
|
+
@ready = false
|
173
|
+
sleep 0.001
|
174
|
+
TD::Api.client_destroy(@td_client)
|
175
|
+
throw(:client_closed)
|
176
|
+
end
|
171
177
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
end
|
188
|
-
@update_manager.add_handler(handler)
|
178
|
+
def send_to_td_client(query)
|
179
|
+
return unless alive?
|
180
|
+
TD::Api.client_send(@td_client, query)
|
181
|
+
end
|
182
|
+
|
183
|
+
def timeout_error
|
184
|
+
TD::Types::Error.new(code: 0, message: 'Timeout error')
|
185
|
+
end
|
186
|
+
|
187
|
+
def dead_client_promise
|
188
|
+
Promises.rejected_future(dead_client_error)
|
189
|
+
end
|
190
|
+
|
191
|
+
def dead_client_error
|
192
|
+
TD::Error.new(TD::Types::Error.new(code: 0, message: 'TD client is dead'))
|
189
193
|
end
|
190
194
|
end
|
data/lib/tdlib/errors.rb
CHANGED
@@ -1,8 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module TD
|
2
|
+
class MissingLibPathError < StandardError
|
3
|
+
def initialize(message = 'Please, configure the path to tdlibjson library')
|
4
|
+
super
|
5
|
+
end
|
4
6
|
end
|
5
|
-
end
|
6
7
|
|
7
|
-
class
|
8
|
+
# Proxy class that is used in failed promises to represent TDlib errors
|
9
|
+
class Error < StandardError
|
10
|
+
def initialize(td_error)
|
11
|
+
@td_error = td_error
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method, *args)
|
15
|
+
@td_error.public_send(method, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to_missing?(*args)
|
19
|
+
@td_error.respond_to?(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
@td_error.inspect
|
24
|
+
end
|
25
|
+
|
26
|
+
def message
|
27
|
+
@td_error.message
|
28
|
+
end
|
29
|
+
|
30
|
+
alias inspect to_s
|
31
|
+
end
|
8
32
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class TD::UpdateHandler
|
2
|
+
include Concurrent::Async
|
3
|
+
|
4
|
+
attr_reader :update_type, :extra
|
5
|
+
|
6
|
+
def initialize(update_type, extra = nil, disposable: false, &action)
|
7
|
+
super()
|
8
|
+
|
9
|
+
@action = action
|
10
|
+
@update_type = update_type
|
11
|
+
@extra = extra
|
12
|
+
@disposable = disposable
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(update)
|
16
|
+
action.call(update)
|
17
|
+
rescue StandardError => e
|
18
|
+
warn("Uncaught exception in handler #{self}: #{e.message}")
|
19
|
+
raise
|
20
|
+
end
|
21
|
+
|
22
|
+
def match?(update, extra = nil)
|
23
|
+
update.is_a?(update_type) && (self.extra.nil? || self.extra == extra)
|
24
|
+
end
|
25
|
+
|
26
|
+
def disposable?
|
27
|
+
disposable
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"TD::UpdateHandler (#{update_type}#{": #{extra}" if extra})#{' disposable' if disposable?}"
|
32
|
+
end
|
33
|
+
|
34
|
+
alias inspect to_s
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :action, :disposable
|
39
|
+
end
|
data/lib/tdlib/update_manager.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
class TD::UpdateManager
|
2
2
|
TIMEOUT = 30
|
3
3
|
|
4
|
-
attr_reader :handlers
|
5
|
-
|
6
4
|
def initialize(td_client)
|
7
5
|
@td_client = td_client
|
8
|
-
@handlers =
|
6
|
+
@handlers = Concurrent::Array.new
|
9
7
|
@mutex = Mutex.new
|
10
8
|
end
|
11
9
|
|
@@ -13,31 +11,36 @@ class TD::UpdateManager
|
|
13
11
|
@mutex.synchronize { @handlers << handler }
|
14
12
|
end
|
15
13
|
|
16
|
-
|
14
|
+
alias << add_handler
|
15
|
+
|
16
|
+
def run(callback: nil)
|
17
17
|
Thread.start do
|
18
|
-
|
18
|
+
catch(:client_closed) { loop { handle_update(callback: callback) } }
|
19
|
+
@mutex.synchronize { @handlers = [] }
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
|
-
|
23
|
-
@update_loop_thread = Thread.start do
|
24
|
-
loop { stopped? ? break : handle_update }
|
25
|
-
end
|
26
|
-
end
|
23
|
+
private
|
27
24
|
|
28
|
-
|
29
|
-
@stopped = true
|
30
|
-
end
|
25
|
+
attr_reader :handlers
|
31
26
|
|
32
|
-
def
|
33
|
-
|
34
|
-
end
|
27
|
+
def handle_update(callback: nil)
|
28
|
+
update = TD::Api.client_receive(@td_client, TIMEOUT)
|
35
29
|
|
36
|
-
|
30
|
+
unless update.nil?
|
31
|
+
extra = update.delete('@extra')
|
32
|
+
update = TD::Types.wrap(update)
|
33
|
+
callback&.call(update)
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
match_handlers!(update, extra).each { |h| h.async.run(update) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def match_handlers!(update, extra)
|
40
|
+
@mutex.synchronize do
|
41
|
+
matched_handlers = handlers.select { |h| h.match?(update, extra) }
|
42
|
+
matched_handlers.each { |h| handlers.delete(h) if h.disposable? }
|
43
|
+
matched_handlers
|
44
|
+
end
|
42
45
|
end
|
43
46
|
end
|
data/lib/tdlib/version.rb
CHANGED
@@ -2,8 +2,10 @@ require 'spec_helper'
|
|
2
2
|
require 'tdlib-ruby'
|
3
3
|
|
4
4
|
describe TD::Client do
|
5
|
-
let(:client) { TD::Client.new }
|
6
|
-
let(:payload) { { '@type'
|
5
|
+
let(:client) { TD::Client.new(timeout: timeout).tap(&:connect) }
|
6
|
+
let!(:payload) { { '@type' => 'getTextEntities', 'text' => text } }
|
7
|
+
let!(:text) { '@telegram' }
|
8
|
+
let(:timeout) { TD::Client::TIMEOUT }
|
7
9
|
|
8
10
|
before do
|
9
11
|
TD.configure do |config|
|
@@ -17,6 +19,14 @@ describe TD::Client do
|
|
17
19
|
TD::Api.set_log_verbosity_level(1)
|
18
20
|
end
|
19
21
|
|
22
|
+
around do |example|
|
23
|
+
begin
|
24
|
+
example.run
|
25
|
+
ensure
|
26
|
+
client.dispose
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
describe '#on_ready' do
|
21
31
|
subject { client.on_ready { [client, 'ready'] } }
|
22
32
|
|
@@ -24,32 +34,35 @@ describe TD::Client do
|
|
24
34
|
it { is_expected.to include('ready') }
|
25
35
|
|
26
36
|
context 'when timeout reached' do
|
27
|
-
|
37
|
+
let(:timeout) { 0.0001 }
|
28
38
|
|
29
|
-
|
39
|
+
subject { client.on_ready { [client, 'ready'] } }
|
40
|
+
|
41
|
+
it { expect { subject }.to raise_error(TD::Error) }
|
30
42
|
end
|
31
43
|
end
|
32
44
|
|
33
45
|
describe '#broadcast' do
|
34
46
|
context 'when no block given' do
|
35
|
-
subject { client.
|
47
|
+
subject { client.ready.then { client.get_text_entities(text: text) }.flat.wait }
|
36
48
|
|
37
49
|
it { expect { subject }.not_to raise_error(Exception) }
|
38
|
-
it { is_expected.to satisfy
|
39
|
-
it { is_expected.to satisfy { |result|
|
40
|
-
it { is_expected.to satisfy { |result| sleep 1; result.value['@type'] == 'textEntities' } }
|
50
|
+
it { is_expected.to satisfy(&:fulfilled?) }
|
51
|
+
it { is_expected.to satisfy { |result| result.value.is_a?(TD::Types::TextEntities) } }
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
44
|
-
describe '#
|
45
|
-
subject { client.on_ready { client.
|
55
|
+
describe '#fetch' do
|
56
|
+
subject { client.on_ready { client.fetch(payload) } }
|
46
57
|
|
47
|
-
it { is_expected.to
|
58
|
+
it { is_expected.to respond_to(:entities) }
|
48
59
|
|
49
60
|
context 'when timeout reached' do
|
50
|
-
|
61
|
+
let(:timeout) { 0.0001 }
|
62
|
+
|
63
|
+
subject { client.on_ready { client.fetch(payload) } }
|
51
64
|
|
52
|
-
it { expect { subject }.to raise_error(TD::
|
65
|
+
it { expect { subject }.to raise_error(TD::Error) }
|
53
66
|
end
|
54
67
|
end
|
55
68
|
|
@@ -64,7 +77,7 @@ describe TD::Client do
|
|
64
77
|
it 'runs block on update' do
|
65
78
|
subject
|
66
79
|
sleep 1
|
67
|
-
expect(@result).to
|
80
|
+
expect(@result).to respond_to(:entities)
|
68
81
|
end
|
69
82
|
end
|
70
83
|
|
@@ -74,7 +87,7 @@ describe TD::Client do
|
|
74
87
|
subject do
|
75
88
|
client.on_ready do
|
76
89
|
client.broadcast(payload) do
|
77
|
-
client.
|
90
|
+
client.fetch(payload)
|
78
91
|
end
|
79
92
|
sleep 1
|
80
93
|
end
|
data/tdlib-ruby.gemspec
CHANGED
@@ -14,26 +14,19 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.email = "ask@southbridge.io"
|
15
15
|
gem.homepage = "https://github.com/centosadmin/tdlib-ruby"
|
16
16
|
|
17
|
-
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.files = `git ls-files`.split($/) - ['lib/tdlib/td_api_tl_parser.rb']
|
18
18
|
|
19
|
-
`git submodule --quiet foreach --recursive pwd`.split($/).each do |submodule|
|
20
|
-
submodule.sub!("#{Dir.pwd}/",'')
|
21
|
-
|
22
|
-
Dir.chdir(submodule) do
|
23
|
-
`git ls-files`.split($/).map do |subpath|
|
24
|
-
gem.files << File.join(submodule,subpath)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
19
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
29
20
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
30
21
|
gem.require_paths = ['lib']
|
31
22
|
|
32
|
-
gem.add_runtime_dependency 'dry-configurable', '~> 0.
|
33
|
-
gem.add_runtime_dependency 'concurrent-ruby',
|
23
|
+
gem.add_runtime_dependency 'dry-configurable', '~> 0.9'
|
24
|
+
gem.add_runtime_dependency 'concurrent-ruby', '~> 1.1'
|
25
|
+
gem.add_runtime_dependency 'ffi', '~> 1.0'
|
26
|
+
gem.add_runtime_dependency 'tdlib-schema'
|
34
27
|
|
35
|
-
gem.add_development_dependency 'bundler', '~>
|
36
|
-
gem.add_development_dependency 'rake', '
|
28
|
+
gem.add_development_dependency 'bundler', '~> 2.0'
|
29
|
+
gem.add_development_dependency 'rake', '~> 13.0'
|
37
30
|
gem.add_development_dependency 'rspec', '~> 3.0'
|
38
31
|
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
39
32
|
gem.add_development_dependency 'yard', '~> 0.9'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tdlib-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Southbridge
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-configurable
|
@@ -16,16 +16,30 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ffi
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
@@ -38,34 +52,48 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tdlib-schema
|
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'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
75
|
+
version: '2.0'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
82
|
+
version: '2.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
|
-
- -
|
87
|
+
- - "~>"
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
89
|
+
version: '13.0'
|
62
90
|
type: :development
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
|
-
- -
|
94
|
+
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
96
|
+
version: '13.0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: rspec
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,12 +153,14 @@ dependencies:
|
|
125
153
|
description: Ruby bindings and client for TDlib
|
126
154
|
email: ask@southbridge.io
|
127
155
|
executables:
|
156
|
+
- build
|
128
157
|
- console
|
129
158
|
extensions: []
|
130
159
|
extra_rdoc_files: []
|
131
160
|
files:
|
132
161
|
- ".document"
|
133
162
|
- ".gitignore"
|
163
|
+
- ".gitmodules"
|
134
164
|
- ".rspec"
|
135
165
|
- ".travis.yml"
|
136
166
|
- ".yardopts"
|
@@ -139,13 +169,14 @@ files:
|
|
139
169
|
- LICENSE.txt
|
140
170
|
- README.md
|
141
171
|
- Rakefile
|
172
|
+
- bin/build
|
142
173
|
- bin/console
|
143
174
|
- lib/tdlib-ruby.rb
|
144
175
|
- lib/tdlib/api.rb
|
145
176
|
- lib/tdlib/client.rb
|
146
177
|
- lib/tdlib/errors.rb
|
178
|
+
- lib/tdlib/update_handler.rb
|
147
179
|
- lib/tdlib/update_manager.rb
|
148
|
-
- lib/tdlib/utils.rb
|
149
180
|
- lib/tdlib/version.rb
|
150
181
|
- spec/integration/tdlib_spec.rb
|
151
182
|
- spec/spec_helper.rb
|
@@ -155,7 +186,7 @@ homepage: https://github.com/centosadmin/tdlib-ruby
|
|
155
186
|
licenses:
|
156
187
|
- MIT
|
157
188
|
metadata: {}
|
158
|
-
post_install_message:
|
189
|
+
post_install_message:
|
159
190
|
rdoc_options: []
|
160
191
|
require_paths:
|
161
192
|
- lib
|
@@ -170,9 +201,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
201
|
- !ruby/object:Gem::Version
|
171
202
|
version: '0'
|
172
203
|
requirements: []
|
173
|
-
|
174
|
-
|
175
|
-
signing_key:
|
204
|
+
rubygems_version: 3.1.4
|
205
|
+
signing_key:
|
176
206
|
specification_version: 4
|
177
207
|
summary: Ruby bindings and client for TDlib
|
178
208
|
test_files:
|