matrix_sdk 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +11 -7
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +15 -0
- data/Rakefile +5 -0
- data/examples/simple_client.rb +49 -2
- data/lib/matrix_sdk/api.rb +273 -27
- data/lib/matrix_sdk/client.rb +77 -20
- data/lib/matrix_sdk/errors.rb +8 -0
- data/lib/matrix_sdk/extensions.rb +2 -1
- data/lib/matrix_sdk/mxid.rb +82 -0
- data/lib/matrix_sdk/response.rb +1 -0
- data/lib/matrix_sdk/room.rb +20 -2
- data/lib/matrix_sdk/version.rb +1 -1
- data/lib/matrix_sdk.rb +1 -0
- data/matrix-sdk.gemspec +6 -3
- metadata +33 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39fdb05386da317f2810f25e668ae14bdd261c807bafc61056fa09dd1d6a8175
|
4
|
+
data.tar.gz: 88b32840ca73b6588f36e35edcccac15e721b071c69a60c6cfc383dceaf67e5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b04d1f07b5d9dd97f3a80a2adffe9a4a29983efc4ee7d1c116c0036233e017d5d9ead02abc9a3048fc9b0ba51c1ee3353fd7ae999a7b5bfc8a41294cd9c1b47c
|
7
|
+
data.tar.gz: a27b7a3bf9b8c411e6026107d3d0a66cd0e86ac96f6bd6284ccc37ec35e3fd67a94a99b1ad2e67f948dd63003bd4f7495fc66baf3b0d1dc880ee300e1aa49b70
|
data/.gitlab-ci.yml
CHANGED
@@ -7,27 +7,31 @@ cache:
|
|
7
7
|
- vendor/ruby
|
8
8
|
|
9
9
|
before_script:
|
10
|
-
- gem install bundler
|
10
|
+
- gem install bundler -N
|
11
11
|
- bundle install -j $(nproc) --path vendor
|
12
12
|
|
13
13
|
rubocop:
|
14
14
|
before_script: []
|
15
15
|
script:
|
16
|
-
- gem install rubocop
|
17
|
-
- rubocop
|
16
|
+
- gem install rubocop -N
|
17
|
+
- rubocop lib
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
test:
|
20
|
+
script:
|
21
|
+
- GENERATE_REPORTS=true CI_REPORTS=reports bundle exec rake test
|
22
|
+
artifacts:
|
23
|
+
reports:
|
24
|
+
junit: "reports/TEST-*.xml"
|
22
25
|
|
23
26
|
pages:
|
24
27
|
stage: deploy
|
25
28
|
before_script: []
|
26
29
|
script:
|
27
|
-
- gem install yard
|
30
|
+
- gem install yard -N
|
28
31
|
- yard doc -o public/
|
29
32
|
artifacts:
|
30
33
|
paths:
|
31
34
|
- public/
|
32
35
|
only:
|
33
36
|
- master
|
37
|
+
when: always
|
data/.rubocop.yml
CHANGED
@@ -4,6 +4,10 @@ AllCops:
|
|
4
4
|
- '*.spec'
|
5
5
|
- 'Rakefile'
|
6
6
|
|
7
|
+
# Broken in CI
|
8
|
+
Lint/Void:
|
9
|
+
Enabled: false
|
10
|
+
|
7
11
|
# Don't enforce documentation
|
8
12
|
Style/Documentation:
|
9
13
|
Enabled: false
|
@@ -12,7 +16,7 @@ Metrics/ClassLength:
|
|
12
16
|
Enabled: false
|
13
17
|
|
14
18
|
Metrics/MethodLength:
|
15
|
-
Max:
|
19
|
+
Max: 50
|
16
20
|
|
17
21
|
Metrics/LineLength:
|
18
22
|
Max: 190
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## v0.0.4 - 2019-02-20
|
2
|
+
|
3
|
+
- Adds a parameter to the client abstraction to allow retrying syncs on timeouts
|
4
|
+
- Adds support for token-based login in the client abstraction
|
5
|
+
- Adds rudimentary username and password validation in the client abstraction
|
6
|
+
- Adds MXID validation in the client abstraction
|
7
|
+
- Adds a method to discover a homeserver address based on a domain.
|
8
|
+
- Supporting both SRV and .well-known lookups
|
9
|
+
- Adds methods from the r0.4.0 spec
|
10
|
+
- Adds support for version 3 event IDs
|
11
|
+
- Extends the connection exceptions with a specific timeout error
|
12
|
+
- Sets a series of filters in the simple client example to skip unhandled event
|
13
|
+
- Fixes an exception when null values end up in the body cleaner during debugging
|
14
|
+
- Fixes an error with CGI not being required correctly
|
15
|
+
|
1
16
|
## v0.0.3 - 2018-08-14
|
2
17
|
|
3
18
|
- Adds missing accessors for HTTP timeout
|
data/Rakefile
CHANGED
data/examples/simple_client.rb
CHANGED
@@ -3,19 +3,61 @@
|
|
3
3
|
require 'io/console'
|
4
4
|
require 'matrix_sdk'
|
5
5
|
|
6
|
+
# A filter to only discover joined rooms
|
7
|
+
ROOM_DISCOVERY_FILTER = {
|
8
|
+
event_fields: %w[sender membership],
|
9
|
+
presence: { senders: [], types: [] },
|
10
|
+
account_data: { senders: [], types: [] },
|
11
|
+
room: {
|
12
|
+
ephemeral: { senders: [], types: [] },
|
13
|
+
state: {
|
14
|
+
senders: [],
|
15
|
+
types: [
|
16
|
+
'm.room.aliases',
|
17
|
+
'm.room.canonical_alias',
|
18
|
+
'm.room.member'
|
19
|
+
]
|
20
|
+
},
|
21
|
+
timeline: { senders: [], types: [] },
|
22
|
+
account_data: { senders: [], types: [] }
|
23
|
+
}
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
# A filter to only retrieve messages from rooms
|
27
|
+
ROOM_STATE_FILTER = {
|
28
|
+
presence: { senders: [], types: [] },
|
29
|
+
account_data: { senders: [], types: [] },
|
30
|
+
room: {
|
31
|
+
ephemeral: { senders: [], types: [] },
|
32
|
+
state: {
|
33
|
+
types: ['m.room.member']
|
34
|
+
},
|
35
|
+
timeline: {
|
36
|
+
types: ['m.room.message']
|
37
|
+
},
|
38
|
+
account_data: { senders: [], types: [] }
|
39
|
+
}
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
|
6
43
|
class SimpleClient < MatrixSdk::Client
|
7
44
|
def initialize(hs_url)
|
8
45
|
super hs_url, sync_filter_limit: 10
|
9
46
|
|
10
47
|
@pls = {}
|
48
|
+
@tracked_rooms = []
|
49
|
+
@filter = ROOM_STATE_FILTER.dup
|
11
50
|
end
|
12
51
|
|
13
52
|
def add_listener(room)
|
14
53
|
room.on_event.add_handler { |ev| on_message(room, ev) }
|
54
|
+
@tracked_rooms << room.id
|
15
55
|
end
|
16
56
|
|
17
57
|
def run
|
18
|
-
|
58
|
+
# Only track messages from the listened rooms
|
59
|
+
@filter[:room][:rooms] = @tracked_rooms
|
60
|
+
start_listener_thread(filter: @filter.to_json)
|
19
61
|
end
|
20
62
|
|
21
63
|
private
|
@@ -64,7 +106,12 @@ if $PROGRAM_NAME == __FILE__
|
|
64
106
|
password = STDIN.noecho(&:gets).strip
|
65
107
|
|
66
108
|
puts 'Logging in...'
|
67
|
-
client.login(user, password,
|
109
|
+
client.login(user, password, no_sync: true)
|
110
|
+
|
111
|
+
# Only retrieve list of joined room in first sync
|
112
|
+
sync_filter = client.sync_filter.merge(ROOM_DISCOVERY_FILTER)
|
113
|
+
sync_filter[:room][:state][:senders] << client.mxid
|
114
|
+
client.listen_for_events(5, filter: sync_filter.to_json)
|
68
115
|
|
69
116
|
puts 'Finding room...'
|
70
117
|
room = client.find_room(ARGV.last)
|
data/lib/matrix_sdk/api.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'matrix_sdk'
|
2
2
|
|
3
|
+
require 'cgi'
|
3
4
|
require 'json'
|
4
5
|
require 'net/http'
|
5
6
|
require 'openssl'
|
@@ -9,17 +10,19 @@ module MatrixSdk
|
|
9
10
|
class Api
|
10
11
|
USER_AGENT = "Ruby Matrix SDK v#{MatrixSdk::VERSION}".freeze
|
11
12
|
DEFAULT_HEADERS = {
|
12
|
-
'accept'
|
13
|
+
'accept' => 'application/json',
|
13
14
|
'user-agent' => USER_AGENT
|
14
15
|
}.freeze
|
15
16
|
|
16
|
-
attr_accessor :access_token, :device_id, :autoretry, :global_headers
|
17
|
+
attr_accessor :access_token, :connection_address, :connection_port, :device_id, :autoretry, :global_headers
|
17
18
|
attr_reader :homeserver, :validate_certificate, :read_timeout
|
18
19
|
|
19
20
|
ignore_inspect :access_token, :logger
|
20
21
|
|
21
22
|
# @param homeserver [String,URI] The URL to the Matrix homeserver, without the /_matrix/ part
|
22
23
|
# @param params [Hash] Additional parameters on creation
|
24
|
+
# @option params [String] :address The connection address to the homeserver, if different to the HS URL
|
25
|
+
# @option params [Integer] :port The connection port to the homeserver, if different to the HS URL
|
23
26
|
# @option params [String] :access_token The access token to use for the connection
|
24
27
|
# @option params [String] :device_id The ID of the logged in decide to use
|
25
28
|
# @option params [Boolean] :autoretry (true) Should requests automatically be retried in case of rate limits
|
@@ -32,15 +35,11 @@ module MatrixSdk
|
|
32
35
|
def initialize(homeserver, params = {})
|
33
36
|
@homeserver = homeserver
|
34
37
|
@homeserver = URI.parse("#{'https://' unless @homeserver.start_with? 'http'}#{@homeserver}") unless @homeserver.is_a? URI
|
35
|
-
if @homeserver.path
|
36
|
-
@homeserver.path = begin
|
37
|
-
split = @homeserver.path.rpartition '_matrix/'
|
38
|
-
(split[(split.find_index '_matrix/')] = '/') rescue nil
|
39
|
-
split.join
|
40
|
-
end
|
41
|
-
end
|
38
|
+
@homeserver.path.gsub!(/\/?_matrix\/?/, '') if @homeserver.path =~ /_matrix\/?$/
|
42
39
|
raise 'Please use the base URL for your HS (without /_matrix/)' if @homeserver.path.include? '/_matrix/'
|
43
40
|
|
41
|
+
@connection_address = params.fetch(:address, nil)
|
42
|
+
@connection_port = params.fetch(:port, nil)
|
44
43
|
@access_token = params.fetch(:access_token, nil)
|
45
44
|
@device_id = params.fetch(:device_id, nil)
|
46
45
|
@autoretry = params.fetch(:autoretry, true)
|
@@ -55,6 +54,60 @@ module MatrixSdk
|
|
55
54
|
@homeserver.userinfo = '' unless params[:skip_login]
|
56
55
|
end
|
57
56
|
|
57
|
+
# Create an API connection to a domain entry
|
58
|
+
#
|
59
|
+
# This will follow the server discovery spec for client-server and federation
|
60
|
+
#
|
61
|
+
# @example Opening a Matrix API connection to a homeserver
|
62
|
+
# hs = MatrixSdk::API.new_for_domain 'example.com'
|
63
|
+
# hs.connection_address
|
64
|
+
# # => 'matrix.example.com'
|
65
|
+
# hs.connection_port
|
66
|
+
# # => 443
|
67
|
+
#
|
68
|
+
# @param domain [String] The domain to set up the API connection for, can contain a ':' to denote a port
|
69
|
+
# @param params [Hash] Additional options to pass to .new
|
70
|
+
# @return [API] The API connection
|
71
|
+
def self.new_for_domain(domain, params = {})
|
72
|
+
# Attempt SRV record discovery
|
73
|
+
srv = if domain.include? ':'
|
74
|
+
addr, port = domain.split ':'
|
75
|
+
Resolv::DNS::Resource::IN::SRV.new 10, 1, port.to_i, addr
|
76
|
+
else
|
77
|
+
require 'resolv'
|
78
|
+
resolver = Resolv::DNS.new
|
79
|
+
begin
|
80
|
+
resolver.getresource("_matrix._tcp.#{domain}")
|
81
|
+
rescue Resolv::ResolvError
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Attempt .well-known discovery
|
87
|
+
if srv.nil?
|
88
|
+
well_known = begin
|
89
|
+
data = Net::HTTP.get("https://#{domain}/.well-known/matrix/client")
|
90
|
+
JSON.parse(data)
|
91
|
+
rescue StandardError
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
return new(well_known['m.homeserver']['base_url']) if well_known &&
|
96
|
+
well_known.key?('m.homeserver') &&
|
97
|
+
well_known['m.homerserver'].key?('base_url')
|
98
|
+
end
|
99
|
+
|
100
|
+
# Fall back to A record on domain
|
101
|
+
srv ||= Resolv::DNS::Resource::IN::SRV.new 10, 1, 8448, domain
|
102
|
+
|
103
|
+
domain = domain.split(':').first if domain.include? ':'
|
104
|
+
new("https://#{domain}",
|
105
|
+
params.merge(
|
106
|
+
address: srv.target.to_s,
|
107
|
+
port: srv.port
|
108
|
+
))
|
109
|
+
end
|
110
|
+
|
58
111
|
# Gets the logger for the API
|
59
112
|
# @return [Logging::Logger] The API-scope logger
|
60
113
|
def logger
|
@@ -81,6 +134,7 @@ module MatrixSdk
|
|
81
134
|
def homeserver=(hs_info)
|
82
135
|
# TODO: DNS query for SRV information about HS?
|
83
136
|
return unless hs_info.is_a? URI
|
137
|
+
|
84
138
|
@http.finish if @http
|
85
139
|
@homeserver = hs_info
|
86
140
|
end
|
@@ -88,14 +142,32 @@ module MatrixSdk
|
|
88
142
|
# Gets the available client API versions
|
89
143
|
# @return [Array]
|
90
144
|
def client_api_versions
|
91
|
-
@client_api_versions ||= request(:get, :client, '/versions').versions
|
145
|
+
@client_api_versions ||= request(:get, :client, '/versions').versions.tap do |vers|
|
146
|
+
vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
|
147
|
+
def latest
|
148
|
+
latest
|
149
|
+
end
|
150
|
+
CODE
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Gets the list of available unstable client API features
|
155
|
+
# @return [Array]
|
156
|
+
def client_api_unstable_features
|
157
|
+
@client_api_unstable_features ||= request(:get, :client, '/versions').unstable_features.tap do |vers|
|
158
|
+
vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
|
159
|
+
def has?(feature)
|
160
|
+
fetch(feature, nil)
|
161
|
+
end
|
162
|
+
CODE
|
163
|
+
end
|
92
164
|
end
|
93
165
|
|
94
166
|
# Gets the server version
|
95
167
|
# @note This uses the unstable federation/v1 API
|
96
168
|
def server_version
|
97
169
|
Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
|
98
|
-
resp.instance_eval <<-'CODE', __FILE__, __LINE__
|
170
|
+
resp.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
|
99
171
|
def to_s
|
100
172
|
"#{name} #{version}"
|
101
173
|
end
|
@@ -195,11 +267,21 @@ module MatrixSdk
|
|
195
267
|
end
|
196
268
|
|
197
269
|
# Logs out the currently logged in user
|
198
|
-
# @return [Response]
|
270
|
+
# @return [Response] An empty response if the logout was successful
|
271
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-logout
|
272
|
+
# The Matrix Spec, for more information about the call and response
|
199
273
|
def logout
|
200
274
|
request(:post, :client_r0, '/logout')
|
201
275
|
end
|
202
276
|
|
277
|
+
# Creates a new room
|
278
|
+
# @param params [Hash] The room creation details
|
279
|
+
# @option params [Symbol] :visibility (:public) The room visibility
|
280
|
+
# @option params [String] :room_alias A room alias to apply on creation
|
281
|
+
# @option params [Boolean] :invite Should the room be created invite-only
|
282
|
+
# @return [Response] A response hash with ...
|
283
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-createroom
|
284
|
+
# The Matrix Spec, for more information about the call and response
|
203
285
|
def create_room(params = {})
|
204
286
|
content = {
|
205
287
|
visibility: params.fetch(:visibility, :public)
|
@@ -210,12 +292,31 @@ module MatrixSdk
|
|
210
292
|
request(:post, :client_r0, '/createRoom', content)
|
211
293
|
end
|
212
294
|
|
295
|
+
# Joins a room
|
296
|
+
# @param id_or_alias [MXID,String] The room ID or Alias to join
|
297
|
+
# @return [Response] A response hash with the parameter :room_id
|
298
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-join-roomidoralias
|
299
|
+
# The Matrix Spec, for more information about the call and response
|
213
300
|
def join_room(id_or_alias)
|
301
|
+
# id_or_alias = MXID.new id_or_alias.to_s unless id_or_alias.is_a? MXID
|
302
|
+
# raise ArgumentError, 'Not a room ID or alias' unless id_or_alias.room?
|
303
|
+
|
214
304
|
id_or_alias = CGI.escape id_or_alias.to_s
|
215
305
|
|
216
306
|
request(:post, :client_r0, "/join/#{id_or_alias}")
|
217
307
|
end
|
218
308
|
|
309
|
+
# Sends a state event to a room
|
310
|
+
# @param room_id [MXID,String] The room ID to send the state event to
|
311
|
+
# @param event_type [String] The event type to send
|
312
|
+
# @param content [Hash] The contents of the state event
|
313
|
+
# @param params [Hash] Options for the request
|
314
|
+
# @option params [Integer] :timestamp The timestamp when the event was created, only used for AS events
|
315
|
+
# @option params [String] :state_key The state key of the event, if there is one
|
316
|
+
# @return [Response] A response hash with the parameter :event_id
|
317
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
|
318
|
+
# https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype
|
319
|
+
# The Matrix Spec, for more information about the call and response
|
219
320
|
def send_state_event(room_id, event_type, content, params = {})
|
220
321
|
query = {}
|
221
322
|
query[:ts] = params[:timestamp].to_i if params.key? :timestamp
|
@@ -227,6 +328,16 @@ module MatrixSdk
|
|
227
328
|
request(:put, :client_r0, "/rooms/#{room_id}/state/#{event_type}#{"/#{state_key}" unless state_key.nil?}", body: content, query: query)
|
228
329
|
end
|
229
330
|
|
331
|
+
# Sends a message event to a room
|
332
|
+
# @param room_id [MXID,String] The room ID to send the message event to
|
333
|
+
# @param event_type [String] The event type of the message
|
334
|
+
# @param content [Hash] The contents of the message
|
335
|
+
# @param params [Hash] Options for the request
|
336
|
+
# @option params [Integer] :timestamp The timestamp when the event was created, only used for AS events
|
337
|
+
# @option params [Integer] :txn_id The ID of the transaction, or automatically generated
|
338
|
+
# @return [Response] A response hash with the parameter :event_id
|
339
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
340
|
+
# The Matrix Spec, for more information about the call and response
|
230
341
|
def send_message_event(room_id, event_type, content, params = {})
|
231
342
|
query = {}
|
232
343
|
query[:ts] = params[:timestamp].to_i if params.key? :timestamp
|
@@ -241,7 +352,17 @@ module MatrixSdk
|
|
241
352
|
request(:put, :client_r0, "/rooms/#{room_id}/send/#{event_type}/#{txn_id}", body: content, query: query)
|
242
353
|
end
|
243
354
|
|
244
|
-
|
355
|
+
# Redact an event in a room
|
356
|
+
# @param room_id [MXID,String] The room ID to send the message event to
|
357
|
+
# @param event_id [String] The event ID of the event to redact
|
358
|
+
# @param params [Hash] Options for the request
|
359
|
+
# @option params [Integer] :timestamp The timestamp when the event was created, only used for AS events
|
360
|
+
# @option params [String] :reason The reason for the redaction
|
361
|
+
# @option params [Integer] :txn_id The ID of the transaction, or automatically generated
|
362
|
+
# @return [Response] A response hash with the parameter :event_id
|
363
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
364
|
+
# The Matrix Spec, for more information about the call and response
|
365
|
+
def redact_event(room_id, event_id, params = {})
|
245
366
|
query = {}
|
246
367
|
query[:ts] = params[:timestamp].to_i if params.key? :timestamp
|
247
368
|
|
@@ -252,12 +373,53 @@ module MatrixSdk
|
|
252
373
|
txn_id = params.fetch(:txn_id, "#{txn_id}#{Time.now.to_i}")
|
253
374
|
|
254
375
|
room_id = CGI.escape room_id.to_s
|
255
|
-
|
376
|
+
event_id = CGI.escape event_id.to_s
|
256
377
|
txn_id = CGI.escape txn_id.to_s
|
257
378
|
|
258
|
-
request(:put, :client_r0, "/rooms/#{room_id}/redact/#{
|
379
|
+
request(:put, :client_r0, "/rooms/#{room_id}/redact/#{event_id}/#{txn_id}", body: content, query: query)
|
259
380
|
end
|
260
381
|
|
382
|
+
# Send a content message to a room
|
383
|
+
#
|
384
|
+
# @example Sending an image to a room
|
385
|
+
# send_content('!abcd123:localhost',
|
386
|
+
# 'mxc://localhost/1234567',
|
387
|
+
# 'An image of a cat',
|
388
|
+
# 'm.image',
|
389
|
+
# extra_information: {
|
390
|
+
# h: 128,
|
391
|
+
# w: 128,
|
392
|
+
# mimetype: 'image/png',
|
393
|
+
# size: 1024
|
394
|
+
# })
|
395
|
+
#
|
396
|
+
# @example Sending a file to a room
|
397
|
+
# send_content('!example:localhost',
|
398
|
+
# 'mxc://localhost/fileurl',
|
399
|
+
# 'Contract.pdf',
|
400
|
+
# 'm.file',
|
401
|
+
# extra_content: {
|
402
|
+
# filename: 'contract.pdf'
|
403
|
+
# },
|
404
|
+
# extra_information: {
|
405
|
+
# mimetype: 'application/pdf',
|
406
|
+
# size: 96674
|
407
|
+
# })
|
408
|
+
#
|
409
|
+
# @param room_id [MXID,String] The room ID to send the content to
|
410
|
+
# @param url [URI,String] The URL to the content
|
411
|
+
# @param name [String] The name of the content
|
412
|
+
# @param msg_type [String] The message type of the content
|
413
|
+
# @param params [Hash] Options for the request
|
414
|
+
# @option params [Hash] :extra_information ({}) Extra information for the content
|
415
|
+
# @option params [Hash] :extra_content Extra data to insert into the content hash
|
416
|
+
# @return [Response] A response hash with the parameter :event_id
|
417
|
+
# @see send_message_event For more information on the underlying call
|
418
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-image
|
419
|
+
# https://matrix.org/docs/spec/client_server/r0.3.0.html#m-file
|
420
|
+
# https://matrix.org/docs/spec/client_server/r0.3.0.html#m-video
|
421
|
+
# https://matrix.org/docs/spec/client_server/r0.3.0.html#m-audio
|
422
|
+
# The Matrix Spec, for more information about the call and response
|
261
423
|
def send_content(room_id, url, name, msg_type, params = {})
|
262
424
|
content = {
|
263
425
|
url: url,
|
@@ -265,22 +427,47 @@ module MatrixSdk
|
|
265
427
|
body: name,
|
266
428
|
info: params.delete(:extra_information) { {} }
|
267
429
|
}
|
430
|
+
content.merge!(params.fetch(:extra_content)) if params.key? :extra_content
|
268
431
|
|
269
432
|
send_message_event(room_id, 'm.room.message', content, params)
|
270
433
|
end
|
271
434
|
|
435
|
+
# Send a geographic location to a room
|
436
|
+
#
|
437
|
+
# @param room_id [MXID,String] The room ID to send the location to
|
438
|
+
# @param geo_uri [URI,String] The geographical URI to send
|
439
|
+
# @param name [String] The name of the location
|
440
|
+
# @param params [Hash] Options for the request
|
441
|
+
# @option params [Hash] :extra_information ({}) Extra information for the location
|
442
|
+
# @option params [URI,String] :thumbnail_url The URL to a thumbnail of the location
|
443
|
+
# @option params [Hash] :thumbnail_info Image information about the location thumbnail
|
444
|
+
# @return [Response] A response hash with the parameter :event_id
|
445
|
+
# @see send_message_event For more information on the underlying call
|
446
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-location
|
447
|
+
# The Matrix Spec, for more information about the call and response
|
272
448
|
def send_location(room_id, geo_uri, name, params = {})
|
273
449
|
content = {
|
274
450
|
geo_uri: geo_uri,
|
275
451
|
msgtype: 'm.location',
|
276
|
-
body: name
|
452
|
+
body: name,
|
453
|
+
info: params.delete(:extra_information) { {} }
|
277
454
|
}
|
278
|
-
content[:thumbnail_url] = params.delete(:thumbnail_url) if params.key? :thumbnail_url
|
279
|
-
content[:thumbnail_info] = params.delete(:thumbnail_info) if params.key? :thumbnail_info
|
455
|
+
content[:info][:thumbnail_url] = params.delete(:thumbnail_url) if params.key? :thumbnail_url
|
456
|
+
content[:info][:thumbnail_info] = params.delete(:thumbnail_info) if params.key? :thumbnail_info
|
280
457
|
|
281
458
|
send_message_event(room_id, 'm.room.message', content, params)
|
282
459
|
end
|
283
460
|
|
461
|
+
# Send a plaintext message to a room
|
462
|
+
#
|
463
|
+
# @param room_id [MXID,String] The room ID to send the message to
|
464
|
+
# @param message [String] The message to send
|
465
|
+
# @param params [Hash] Options for the request
|
466
|
+
# @option params [String] :msg_type ('m.text') The message type to send
|
467
|
+
# @return [Response] A response hash with the parameter :event_id
|
468
|
+
# @see send_message_event For more information on the underlying call
|
469
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-text
|
470
|
+
# The Matrix Spec, for more information about the call and response
|
284
471
|
def send_message(room_id, message, params = {})
|
285
472
|
content = {
|
286
473
|
msgtype: params.delete(:msg_type) { 'm.text' },
|
@@ -289,6 +476,16 @@ module MatrixSdk
|
|
289
476
|
send_message_event(room_id, 'm.room.message', content, params)
|
290
477
|
end
|
291
478
|
|
479
|
+
# Send a plaintext emote to a room
|
480
|
+
#
|
481
|
+
# @param room_id [MXID,String] The room ID to send the message to
|
482
|
+
# @param emote [String] The emote to send
|
483
|
+
# @param params [Hash] Options for the request
|
484
|
+
# @option params [String] :msg_type ('m.emote') The message type to send
|
485
|
+
# @return [Response] A response hash with the parameter :event_id
|
486
|
+
# @see send_message_event For more information on the underlying call
|
487
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-emote
|
488
|
+
# The Matrix Spec, for more information about the call and response
|
292
489
|
def send_emote(room_id, emote, params = {})
|
293
490
|
content = {
|
294
491
|
msgtype: params.delete(:msg_type) { 'm.emote' },
|
@@ -297,6 +494,16 @@ module MatrixSdk
|
|
297
494
|
send_message_event(room_id, 'm.room.message', content, params)
|
298
495
|
end
|
299
496
|
|
497
|
+
# Send a plaintext notice to a room
|
498
|
+
#
|
499
|
+
# @param room_id [MXID,String] The room ID to send the message to
|
500
|
+
# @param notice [String] The notice to send
|
501
|
+
# @param params [Hash] Options for the request
|
502
|
+
# @option params [String] :msg_type ('m.notice') The message type to send
|
503
|
+
# @return [Response] A response hash with the parameter :event_id
|
504
|
+
# @see send_message_event For more information on the underlying call
|
505
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-notice
|
506
|
+
# The Matrix Spec, for more information about the call and response
|
300
507
|
def send_notice(room_id, notice, params = {})
|
301
508
|
content = {
|
302
509
|
msgtype: params.delete(:msg_type) { 'm.notice' },
|
@@ -305,6 +512,18 @@ module MatrixSdk
|
|
305
512
|
send_message_event(room_id, 'm.room.message', content, params)
|
306
513
|
end
|
307
514
|
|
515
|
+
# Retrieve additional messages in a room
|
516
|
+
#
|
517
|
+
# @param room_id [MXID,String] The room ID to retrieve messages for
|
518
|
+
# @param token [String] The token to start retrieving from, can be from a sync or from an earlier get_room_messages call
|
519
|
+
# @param direction [:b,:f] The direction to retrieve messages
|
520
|
+
# @param params [Hash] Additional options for the request
|
521
|
+
# @option params [Integer] :limit (10) The limit of messages to retrieve
|
522
|
+
# @option params [String] :to A token to limit retrieval to
|
523
|
+
# @option params [String] :filter A filter to limit the retrieval to
|
524
|
+
# @return [Response] A response hash with the message information containing :start, :end, and :chunk fields
|
525
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-rooms-roomid-messages
|
526
|
+
# The Matrix Spec, for more information about the call and response
|
308
527
|
def get_room_messages(room_id, token, direction, params = {})
|
309
528
|
query = {
|
310
529
|
roomId: room_id,
|
@@ -313,12 +532,20 @@ module MatrixSdk
|
|
313
532
|
limit: params.fetch(:limit, 10)
|
314
533
|
}
|
315
534
|
query[:to] = params[:to] if params.key? :to
|
535
|
+
query[:filter] = params.fetch(:filter) if params.key? :filter
|
316
536
|
|
317
537
|
room_id = CGI.escape room_id.to_s
|
318
538
|
|
319
539
|
request(:get, :client_r0, "/rooms/#{room_id}/messages", query: query)
|
320
540
|
end
|
321
541
|
|
542
|
+
# Reads the latest instance of a room state event
|
543
|
+
#
|
544
|
+
# @param room_id [MXID,String] The room ID to read from
|
545
|
+
# @param state_type [String] The state type to read
|
546
|
+
# @return [Response] A response hash with the contents of the state event
|
547
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype
|
548
|
+
# The Matrix Spec, for more information about the call and response
|
322
549
|
def get_room_state(room_id, state_type)
|
323
550
|
room_id = CGI.escape room_id.to_s
|
324
551
|
state_type = CGI.escape state_type.to_s
|
@@ -326,6 +553,13 @@ module MatrixSdk
|
|
326
553
|
request(:get, :client_r0, "/rooms/#{room_id}/state/#{state_type}")
|
327
554
|
end
|
328
555
|
|
556
|
+
# Gets the display name of a room
|
557
|
+
#
|
558
|
+
# @param room_id [MXID,String] The room ID to look up
|
559
|
+
# @return [Response] A response hash with the parameter :name
|
560
|
+
# @see get_room_state
|
561
|
+
# @see https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-name
|
562
|
+
# The Matrix Spec, for more information about the event and data
|
329
563
|
def get_room_name(room_id)
|
330
564
|
get_room_state(room_id, 'm.room.name')
|
331
565
|
end
|
@@ -452,9 +686,12 @@ module MatrixSdk
|
|
452
686
|
request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags/#{tag}", body: content)
|
453
687
|
end
|
454
688
|
|
455
|
-
|
456
|
-
|
457
|
-
|
689
|
+
def get_account_data(user_id, type_key)
|
690
|
+
user_id = CGI.escape user_id.to_s
|
691
|
+
type_key = CGI.escape type_key.to_s
|
692
|
+
|
693
|
+
request(:get, :client_r0, "/user/#{user_id}/account_data/#{type_key}")
|
694
|
+
end
|
458
695
|
|
459
696
|
def set_account_data(user_id, type_key, account_data)
|
460
697
|
user_id = CGI.escape user_id.to_s
|
@@ -463,9 +700,13 @@ module MatrixSdk
|
|
463
700
|
request(:put, :client_r0, "/user/#{user_id}/account_data/#{type_key}", body: account_data)
|
464
701
|
end
|
465
702
|
|
466
|
-
|
467
|
-
|
468
|
-
|
703
|
+
def get_room_account_data(user_id, room_id, type_key)
|
704
|
+
user_id = CGI.escape user_id.to_s
|
705
|
+
room_id = CGI.escape room_id.to_s
|
706
|
+
type_key = CGI.escape type_key.to_s
|
707
|
+
|
708
|
+
request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type_key}")
|
709
|
+
end
|
469
710
|
|
470
711
|
def set_room_account_data(user_id, room_id, type_key, account_data)
|
471
712
|
user_id = CGI.escape user_id.to_s
|
@@ -617,6 +858,7 @@ module MatrixSdk
|
|
617
858
|
|
618
859
|
if response.is_a? Net::HTTPTooManyRequests
|
619
860
|
raise MatrixRequestError.new(data, response.code) unless autoretry
|
861
|
+
|
620
862
|
failures += 1
|
621
863
|
waittime = data[:retry_after_ms] || data[:error][:retry_after_ms] || @backoff_time
|
622
864
|
sleep(waittime.to_f / 1000.0)
|
@@ -625,7 +867,8 @@ module MatrixSdk
|
|
625
867
|
|
626
868
|
return MatrixSdk::Response.new self, data if response.is_a? Net::HTTPSuccess
|
627
869
|
raise MatrixRequestError.new(data, response.code) if data
|
628
|
-
|
870
|
+
|
871
|
+
raise MatrixConnectionError.class_by_code(response.code), response
|
629
872
|
end
|
630
873
|
end
|
631
874
|
|
@@ -645,8 +888,11 @@ module MatrixSdk
|
|
645
888
|
logger.debug "#{dir} #{h}"
|
646
889
|
end
|
647
890
|
logger.debug dir
|
648
|
-
clean_body = JSON.parse(http.body)
|
891
|
+
clean_body = JSON.parse(http.body) rescue nil if http.body
|
892
|
+
clean_body.keys.each { |k| clean_body[k] = '[ REDACTED ]' if %w[password access_token].include?(k) }.to_json if clean_body
|
649
893
|
logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
|
894
|
+
rescue StandardError => ex
|
895
|
+
logger.warn "#{ex.class} occured while printing request debug; #{ex.message}\n#{ex.backtrace.join "\n"}"
|
650
896
|
end
|
651
897
|
|
652
898
|
def transaction_id
|
@@ -661,7 +907,7 @@ module MatrixSdk
|
|
661
907
|
end
|
662
908
|
|
663
909
|
def http
|
664
|
-
@http ||= Net::HTTP.new homeserver.host, homeserver.port
|
910
|
+
@http ||= Net::HTTP.new (@connection_address || homeserver.host), (@connection_port || homeserver.port)
|
665
911
|
return @http if @http.active?
|
666
912
|
|
667
913
|
@http.read_timeout = read_timeout
|
data/lib/matrix_sdk/client.rb
CHANGED
@@ -7,20 +7,23 @@ module MatrixSdk
|
|
7
7
|
extend Forwardable
|
8
8
|
|
9
9
|
attr_reader :api
|
10
|
-
attr_writer :mxid
|
11
10
|
attr_accessor :cache, :sync_filter
|
12
11
|
|
13
12
|
events :event, :presence_event, :invite_event, :left_event, :ephemeral_event
|
14
13
|
ignore_inspect :api,
|
15
14
|
:on_event, :on_presence_event, :on_invite_event, :on_left_event, :on_ephemeral_event
|
16
15
|
|
17
|
-
alias user_id= mxid=
|
18
|
-
|
19
16
|
def_delegators :@api,
|
20
17
|
:access_token, :access_token=, :device_id, :device_id=, :homeserver, :homeserver=,
|
21
18
|
:validate_certificate, :validate_certificate=
|
22
19
|
|
23
|
-
|
20
|
+
# @param hs_url [String,URI,Api] The URL to the Matrix homeserver, without the /_matrix/ part, or an existing Api instance
|
21
|
+
# @param client_cache [:all,:some,:none] (:all) How much data should be cached in the client
|
22
|
+
# @param params [Hash] Additional parameters on creation
|
23
|
+
# @option params [String,MXID] :user_id The user ID of the logged-in user
|
24
|
+
# @option params [Integer] :sync_filter_limit (20) Limit of timeline entries in syncs
|
25
|
+
# @see MatrixSdk::Api.new for additional usable params
|
26
|
+
def initialize(hs_url, client_cache: :all, **params)
|
24
27
|
event_initialize
|
25
28
|
|
26
29
|
params[:user_id] ||= params[:mxid] if params[:mxid]
|
@@ -36,7 +39,7 @@ module MatrixSdk
|
|
36
39
|
|
37
40
|
@rooms = {}
|
38
41
|
@users = {}
|
39
|
-
@cache =
|
42
|
+
@cache = client_cache
|
40
43
|
|
41
44
|
@sync_token = nil
|
42
45
|
@sync_thread = nil
|
@@ -54,6 +57,7 @@ module MatrixSdk
|
|
54
57
|
raise ArgumentError, 'Cache value must be one of of [:all, :some, :none]' unless %i[all some none].include? @cache
|
55
58
|
|
56
59
|
return unless params[:user_id]
|
60
|
+
|
57
61
|
@mxid = params[:user_id]
|
58
62
|
end
|
59
63
|
|
@@ -67,7 +71,15 @@ module MatrixSdk
|
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
74
|
+
def mxid=(id)
|
75
|
+
id = MXID.new id.to_s unless id.is_a? MXID
|
76
|
+
raise ArgumentError, 'Must be a User ID' unless id.user?
|
77
|
+
|
78
|
+
@mxid = id
|
79
|
+
end
|
80
|
+
|
70
81
|
alias user_id mxid
|
82
|
+
alias user_id= mxid=
|
71
83
|
|
72
84
|
def rooms
|
73
85
|
@rooms.values
|
@@ -79,15 +91,48 @@ module MatrixSdk
|
|
79
91
|
end
|
80
92
|
|
81
93
|
def register_with_password(username, password)
|
94
|
+
username = username.to_s unless username.is_a?(String)
|
95
|
+
password = password.to_s unless password.is_a?(String)
|
96
|
+
|
97
|
+
raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
|
98
|
+
raise ArgumentError, "Password can't be nil or empty" if password.nil? || username.empty?
|
99
|
+
|
82
100
|
data = api.register(auth: { type: 'm.login.dummy' }, username: username, password: password)
|
83
101
|
post_authentication(data)
|
84
102
|
end
|
85
103
|
|
86
|
-
def login(username, password,
|
104
|
+
def login(username, password, sync_timeout: 15, full_state: false, **params)
|
105
|
+
username = username.to_s unless username.is_a?(String)
|
106
|
+
password = password.to_s unless password.is_a?(String)
|
107
|
+
|
108
|
+
raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
|
109
|
+
raise ArgumentError, "Password can't be nil or empty" if password.nil? || password.empty?
|
110
|
+
|
87
111
|
data = api.login(user: username, password: password)
|
88
112
|
post_authentication(data)
|
89
113
|
|
90
|
-
|
114
|
+
return if params[:no_sync]
|
115
|
+
|
116
|
+
sync timeout: sync_timeout,
|
117
|
+
full_state: full_state,
|
118
|
+
allow_sync_retry: params.fetch(:allow_sync_retry, nil)
|
119
|
+
end
|
120
|
+
|
121
|
+
def login_with_token(username, token, sync_timeout: 15, full_state: false, **params)
|
122
|
+
username = username.to_s unless username.is_a?(String)
|
123
|
+
token = token.to_s unless token.is_a?(String)
|
124
|
+
|
125
|
+
raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
|
126
|
+
raise ArgumentError, "Token can't be nil or empty" if token.nil? || token.empty?
|
127
|
+
|
128
|
+
data = api.login(user: username, token: token, type: 'm.login.token')
|
129
|
+
post_authentication(data)
|
130
|
+
|
131
|
+
return if params[:no_sync]
|
132
|
+
|
133
|
+
sync timeout: sync_timeout,
|
134
|
+
full_state: full_state,
|
135
|
+
allow_sync_retry: params.fetch(:allow_sync_retry, nil)
|
91
136
|
end
|
92
137
|
|
93
138
|
def logout
|
@@ -128,10 +173,11 @@ module MatrixSdk
|
|
128
173
|
def upload(content, content_type)
|
129
174
|
data = api.media_upload(content, content_type)
|
130
175
|
return data[:content_uri] if data.key? :content_uri
|
176
|
+
|
131
177
|
raise MatrixUnexpectedResponseError, 'Upload succeeded, but no media URI returned'
|
132
178
|
end
|
133
179
|
|
134
|
-
def listen_for_events(timeout
|
180
|
+
def listen_for_events(timeout: 30, **arguments)
|
135
181
|
sync(arguments.merge(timeout: timeout))
|
136
182
|
end
|
137
183
|
|
@@ -144,6 +190,7 @@ module MatrixSdk
|
|
144
190
|
|
145
191
|
def stop_listener_thread
|
146
192
|
return unless @sync_thread
|
193
|
+
|
147
194
|
@should_listen = false
|
148
195
|
@sync_thread.join if @sync_thread.alive?
|
149
196
|
@sync_thread = nil
|
@@ -151,17 +198,14 @@ module MatrixSdk
|
|
151
198
|
|
152
199
|
private
|
153
200
|
|
154
|
-
def listen_forever(
|
155
|
-
|
156
|
-
params[:bad_sync_timeout] = params.fetch(:bad_sync_timeout, 5)
|
157
|
-
params[:sync_interval] = params.fetch(:sync_interval, 30)
|
158
|
-
|
159
|
-
bad_sync_timeout = params[:bad_sync_timeout]
|
201
|
+
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval: 30, **params)
|
202
|
+
orig_bad_sync_timeout = bad_sync_timeout.dup
|
160
203
|
while @should_listen
|
161
204
|
begin
|
162
|
-
sync(timeout: timeout)
|
163
|
-
|
164
|
-
|
205
|
+
sync(params.merge(timeout: timeout))
|
206
|
+
|
207
|
+
bad_sync_timeout = orig_bad_sync_timeout
|
208
|
+
sleep(sync_interval) if sync_interval > 0
|
165
209
|
rescue MatrixRequestError => ex
|
166
210
|
logger.warn("A #{ex.class} occurred during sync")
|
167
211
|
if ex.httpstatus >= 500
|
@@ -215,14 +259,27 @@ module MatrixSdk
|
|
215
259
|
end
|
216
260
|
end
|
217
261
|
|
218
|
-
def sync(
|
262
|
+
def sync(skip_store_batch: false, **params)
|
219
263
|
extra_params = {
|
220
264
|
filter: sync_filter.to_json
|
221
265
|
}
|
222
266
|
extra_params[:since] = @next_batch unless @next_batch.nil?
|
223
|
-
data = api.sync params.merge(extra_params)
|
224
|
-
@next_batch = data[:next_batch]
|
225
267
|
|
268
|
+
attempts = 0
|
269
|
+
data = loop do
|
270
|
+
begin
|
271
|
+
break api.sync extra_params.merge(params)
|
272
|
+
rescue MatrixTimeoutError => ex
|
273
|
+
raise ex if (attempts += 1) > params.fetch(:allow_sync_retry, 0)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
@next_batch = data[:next_batch] unless skip_store_batch
|
278
|
+
|
279
|
+
handle_sync_response(data)
|
280
|
+
end
|
281
|
+
|
282
|
+
def handle_sync_response(data)
|
226
283
|
data[:presence][:events].each do |presence_update|
|
227
284
|
fire_presence_event(MatrixEvent.new(self, presence_update))
|
228
285
|
end
|
data/lib/matrix_sdk/errors.rb
CHANGED
@@ -23,6 +23,14 @@ module MatrixSdk
|
|
23
23
|
|
24
24
|
# An error raised when errors occur in the connection layer
|
25
25
|
class MatrixConnectionError < MatrixError
|
26
|
+
def self.class_by_code(code)
|
27
|
+
return MatrixTimeoutError if code == 504
|
28
|
+
|
29
|
+
MatrixConnectionError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class MatrixTimeoutError < MatrixConnectionError
|
26
34
|
end
|
27
35
|
|
28
36
|
# An error raised when the homeserver returns an unexpected response to the client
|
@@ -56,7 +56,7 @@ def ignore_inspect(*symbols)
|
|
56
56
|
.reject { |f| %i[#{symbols.map { |s| "@#{s}" }.join ' '}].include? f }
|
57
57
|
.map { |f| "\#{f}=\#{instance_variable_get(f).inspect}" }.join " " }}>"
|
58
58
|
end
|
59
|
-
*, __FILE__, __LINE__ -
|
59
|
+
*, __FILE__, __LINE__ - 6
|
60
60
|
end
|
61
61
|
|
62
62
|
module MatrixSdk
|
@@ -146,6 +146,7 @@ module MatrixSdk
|
|
146
146
|
|
147
147
|
def method_missing(method, *args)
|
148
148
|
return event[method] if event.key? method
|
149
|
+
|
149
150
|
super
|
150
151
|
end
|
151
152
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module MatrixSdk
|
2
|
+
class MXID
|
3
|
+
attr_accessor :sigil, :localpart, :domain, :port
|
4
|
+
|
5
|
+
# @param identifier [String] The Matrix ID string in the format of '&<localpart>:<domain>' where '&' is the sigil
|
6
|
+
def initialize(identifier)
|
7
|
+
raise ArugmentError, 'Identifier must be a String' unless identifier.is_a? String
|
8
|
+
raise ArgumentError, 'Identifier is too long' if identifier.size > 255
|
9
|
+
raise ArgumentError, 'Identifier lacks required data' unless identifier =~ %r{^([@!$+#][^:]+:[^:]+(?::\d+)?)|(\$[A-Za-z0-9+/]+)$}
|
10
|
+
|
11
|
+
@sigil = identifier[0]
|
12
|
+
@localpart, @domain, @port = identifier[1..-1].split(':')
|
13
|
+
|
14
|
+
raise ArgumentError, 'Identifier is not a valid MXID' unless valid?
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#{sigil}#{localpart}#{domain ? ':' + domain : ''}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the type of the ID
|
22
|
+
#
|
23
|
+
# @return [Symbol] The MXID type, one of (:user_id, :room_id, :event_id, :group_id, or :room_alias)
|
24
|
+
def type
|
25
|
+
case sigil
|
26
|
+
when '@'
|
27
|
+
:user_id
|
28
|
+
when '!'
|
29
|
+
:room_id
|
30
|
+
when '$'
|
31
|
+
:event_id
|
32
|
+
when '+'
|
33
|
+
:group_id
|
34
|
+
when '#'
|
35
|
+
:room_alias
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Checks if the ID is valid
|
40
|
+
#
|
41
|
+
# @return [Boolean] If the ID is a valid Matrix ID
|
42
|
+
def valid?
|
43
|
+
!type.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Check if the ID is of a user
|
47
|
+
# @return [Boolean] if the ID is of the user_id type
|
48
|
+
def user?
|
49
|
+
type == :user_id
|
50
|
+
end
|
51
|
+
|
52
|
+
# Check if the ID is of a group
|
53
|
+
# @return [Boolean] if the ID is of the group_id type
|
54
|
+
def group?
|
55
|
+
type == :group_id
|
56
|
+
end
|
57
|
+
|
58
|
+
# Check if the ID is of a room
|
59
|
+
# @return [Boolean] if the ID is of the room_id or room_alias types
|
60
|
+
def room?
|
61
|
+
type == :room_id || type == :room_alias
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check if the ID is of a event
|
65
|
+
# @return [Boolean] if the ID is of the event_id type
|
66
|
+
def event?
|
67
|
+
type == :event_id
|
68
|
+
end
|
69
|
+
|
70
|
+
# Check if the ID is a room_id
|
71
|
+
# @return [Boolean] if the ID is of the room_id type
|
72
|
+
def room_id?
|
73
|
+
type == :room_id
|
74
|
+
end
|
75
|
+
|
76
|
+
# Check if the ID is a room_alias
|
77
|
+
# @return [Boolean] if the ID is of the room_alias type
|
78
|
+
def room_alias?
|
79
|
+
type == :room_alias
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/matrix_sdk/response.rb
CHANGED
data/lib/matrix_sdk/room.rb
CHANGED
@@ -115,6 +115,7 @@ module MatrixSdk
|
|
115
115
|
|
116
116
|
client.api.get_room_members(id)[:chunk].each do |chunk|
|
117
117
|
next unless chunk [:content][:membership] == 'join'
|
118
|
+
|
118
119
|
ensure_member(User.new(client, chunk[:state_key], display_name: chunk[:content].fetch(:displayname)))
|
119
120
|
end
|
120
121
|
members
|
@@ -149,7 +150,7 @@ module MatrixSdk
|
|
149
150
|
# Possible message types as defined by the spec
|
150
151
|
def send_html(html, body = nil, msg_type = 'm.text')
|
151
152
|
content = {
|
152
|
-
body: body
|
153
|
+
body: body || html.gsub(/<\/?[^>]*>/, ''),
|
153
154
|
msgtype: msg_type,
|
154
155
|
format: 'org.matrix.custom.html',
|
155
156
|
formatted_body: html
|
@@ -338,6 +339,7 @@ module MatrixSdk
|
|
338
339
|
# @note the avatar URL should be a mxc:// URI
|
339
340
|
def set_user_profile(params = {})
|
340
341
|
return nil unless params[:display_name] || params[:avatar_url]
|
342
|
+
|
341
343
|
data = client.api.get_membership(id, client.mxid)
|
342
344
|
raise "Can't set profile if you haven't joined the room" unless data[:membership] == 'join'
|
343
345
|
|
@@ -348,7 +350,21 @@ module MatrixSdk
|
|
348
350
|
end
|
349
351
|
|
350
352
|
def tags
|
351
|
-
client.api.get_user_tags(client.mxid, id)
|
353
|
+
client.api.get_user_tags(client.mxid, id)[:tags].tap do |tag_obj|
|
354
|
+
tag_obj.instance_variable_set(:@room, self)
|
355
|
+
tag_obj.define_singleton_method(:room) do
|
356
|
+
@room
|
357
|
+
end
|
358
|
+
tag_obj.define_singleton_method(:add) do |tag, params = {}|
|
359
|
+
@room.add_tag(tag.to_s.to_sym, params)
|
360
|
+
self[tag.to_s.to_sym] = params
|
361
|
+
self
|
362
|
+
end
|
363
|
+
tag_obj.define_singleton_method(:remove) do |tag|
|
364
|
+
@room.remove_tag(tag.to_s.to_sym)
|
365
|
+
delete tag.to_s.to_sym
|
366
|
+
end
|
367
|
+
end
|
352
368
|
end
|
353
369
|
|
354
370
|
def remove_tag(tag)
|
@@ -458,6 +474,7 @@ module MatrixSdk
|
|
458
474
|
# @return [Boolean] if the change was successful
|
459
475
|
def modify_user_power_levels(users = nil, users_default = nil)
|
460
476
|
return false if users.nil? && users_default.nil?
|
477
|
+
|
461
478
|
data = client.api.get_power_levels(id)
|
462
479
|
data[:users_default] = users_default unless users_default.nil?
|
463
480
|
|
@@ -479,6 +496,7 @@ module MatrixSdk
|
|
479
496
|
# @return [Boolean] if the change was successful
|
480
497
|
def modify_required_power_levels(events = nil, params = {})
|
481
498
|
return false if events.nil? && (params.nil? || params.empty?)
|
499
|
+
|
482
500
|
data = client.api.get_power_levels(id)
|
483
501
|
data.merge!(params)
|
484
502
|
data.delete_if { |_k, v| v.nil? }
|
data/lib/matrix_sdk/version.rb
CHANGED
data/lib/matrix_sdk.rb
CHANGED
@@ -6,6 +6,7 @@ autoload :Logging, 'logging'
|
|
6
6
|
module MatrixSdk
|
7
7
|
autoload :Api, 'matrix_sdk/api'
|
8
8
|
autoload :Client, 'matrix_sdk/client'
|
9
|
+
autoload :MXID, 'matrix_sdk/mxid'
|
9
10
|
autoload :Response, 'matrix_sdk/response'
|
10
11
|
autoload :Room, 'matrix_sdk/room'
|
11
12
|
autoload :User, 'matrix_sdk/user'
|
data/matrix-sdk.gemspec
CHANGED
@@ -18,7 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
|
19
19
|
spec.add_dependency 'logging', '~> 2'
|
20
20
|
|
21
|
-
spec.add_development_dependency '
|
22
|
-
spec.add_development_dependency '
|
23
|
-
spec.add_development_dependency '
|
21
|
+
spec.add_development_dependency 'mocha'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'test-unit'
|
24
|
+
|
25
|
+
# TODO: Put this in a better location
|
26
|
+
spec.add_development_dependency 'ci_reporter_test_unit'
|
24
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matrix_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Olofsson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logging
|
@@ -25,47 +25,61 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: mocha
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: test-unit
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ci_reporter_test_unit
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
82
|
+
version: '0'
|
69
83
|
description: ''
|
70
84
|
email:
|
71
85
|
- ace@haxalot.com
|
@@ -88,6 +102,7 @@ files:
|
|
88
102
|
- lib/matrix_sdk/client.rb
|
89
103
|
- lib/matrix_sdk/errors.rb
|
90
104
|
- lib/matrix_sdk/extensions.rb
|
105
|
+
- lib/matrix_sdk/mxid.rb
|
91
106
|
- lib/matrix_sdk/response.rb
|
92
107
|
- lib/matrix_sdk/room.rb
|
93
108
|
- lib/matrix_sdk/user.rb
|
@@ -113,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
128
|
version: '0'
|
114
129
|
requirements: []
|
115
130
|
rubyforge_project:
|
116
|
-
rubygems_version: 2.7.
|
131
|
+
rubygems_version: 2.7.7
|
117
132
|
signing_key:
|
118
133
|
specification_version: 4
|
119
134
|
summary: ''
|