matrix_sdk 2.3.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +2 -0
- data/lib/matrix_sdk/api.rb +52 -18
- data/lib/matrix_sdk/client.rb +41 -27
- data/lib/matrix_sdk/mxid.rb +41 -1
- data/lib/matrix_sdk/protocols/cs.rb +134 -108
- data/lib/matrix_sdk/protocols/msc.rb +5 -0
- data/lib/matrix_sdk/room.rb +106 -39
- data/lib/matrix_sdk/rooms/space.rb +79 -0
- data/lib/matrix_sdk/user.rb +4 -4
- data/lib/matrix_sdk/util/events.rb +4 -6
- data/lib/matrix_sdk/util/extensions.rb +13 -19
- data/lib/matrix_sdk/util/tinycache.rb +31 -7
- data/lib/matrix_sdk/util/tinycache_adapter.rb +5 -0
- data/lib/matrix_sdk/util/uri.rb +101 -0
- data/lib/matrix_sdk/version.rb +1 -1
- data/lib/matrix_sdk.rb +10 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50821866efab2cbd39daf23bc9ff3bd7864bca5638f76c766a8ba26ab91c7423
|
4
|
+
data.tar.gz: 2601cf5141e824b322f5310e09b72d42059162e1ac87da11243167d2604f1801
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bb45dfcb6696b75ed0be95b92fbb3f569b258d4d0456a3cd8ea16fd22d5e3d5050607e6229bfa0e32b84fc0248e554db8f93d48cd970b2ff95475cf0bcfba85
|
7
|
+
data.tar.gz: 58d8524e9d83ef570ca19a41f28758fc129c1a3988ea3522a994e58eaa93c4807850b63a2171423dd69a948738e69468542d56d882ecf98c60e6f8607928b6d1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
## 2.6.0 - 2022-07-15
|
2
|
+
|
3
|
+
- Adds some multi-thread usage support to the API (create your API/client with `threadsafe: :multithread/true/false`)
|
4
|
+
The API will currently default to running with multi-threaded requests. In case your application is single-threaded - or never performs requests from multiple threads - then you can set `threadsafe: true/false` to support connection reuse.
|
5
|
+
- Changes room finding to ignore non-canonical aliases by default
|
6
|
+
- Improves room alias handling
|
7
|
+
- Improves Ruby 3.0+ support
|
8
|
+
- Improves debug output by supporting PP (Ruby pretty print) on all MatrixSdk objects
|
9
|
+
|
10
|
+
## 2.5.0 - 2022-01-14
|
11
|
+
|
12
|
+
- Adds preliminary support for the Matrix v1.1 `client/v3` API
|
13
|
+
- Adds some support for knocking rooms
|
14
|
+
- Adds mutex synchronization on API requests to avoid some threading issues
|
15
|
+
- Fixes error on attempting to skip cache for certain requests (#19)
|
16
|
+
- Fixes inconsistency in MXID typing for the Client abstraction (#18 #20)
|
17
|
+
- Fixes missed autoloader entries for errors (#22)
|
18
|
+
- Fixes some potential issues arising from broken user-provided state data
|
19
|
+
|
20
|
+
## 2.4.0 - 2021-07-19
|
21
|
+
|
22
|
+
- Adds support for matrix: URI's according to MSC2312
|
23
|
+
- Adds some basic support for detecting Spaces (MSC1772)
|
24
|
+
- Fixes sync against Synapse 1.38.0 missing empty fields
|
25
|
+
|
1
26
|
## 2.3.0 - 2021-03-26
|
2
27
|
|
3
28
|
- Adds support for Ruby 3.0 (#15)
|
data/README.md
CHANGED
data/lib/matrix_sdk/api.rb
CHANGED
@@ -19,7 +19,7 @@ module MatrixSdk
|
|
19
19
|
}.freeze
|
20
20
|
|
21
21
|
attr_accessor :access_token, :connection_address, :connection_port, :device_id, :autoretry, :global_headers
|
22
|
-
attr_reader :homeserver, :validate_certificate, :open_timeout, :read_timeout, :well_known, :proxy_uri
|
22
|
+
attr_reader :homeserver, :validate_certificate, :open_timeout, :read_timeout, :well_known, :proxy_uri, :threadsafe
|
23
23
|
|
24
24
|
ignore_inspect :access_token, :logger
|
25
25
|
|
@@ -39,7 +39,10 @@ module MatrixSdk
|
|
39
39
|
# @option params [Hash] :global_headers Additional headers to set for all requests
|
40
40
|
# @option params [Boolean] :skip_login Should the API skip logging in if the HS URL contains user information
|
41
41
|
# @option params [Boolean] :synapse (true) Is the API connecting to a Synapse instance
|
42
|
-
# @option params [
|
42
|
+
# @option params [Boolean,:multithread] :threadsafe (:multithread) Should the connection be threadsafe/mutexed - or
|
43
|
+
# safe for simultaneous multi-thread usage. Will default to +:multithread+ - a.k.a. per-thread HTTP connections
|
44
|
+
# and requests
|
45
|
+
# @note Using threadsafe +:multithread+ currently doesn't support connection re-use
|
43
46
|
def initialize(homeserver, **params)
|
44
47
|
@homeserver = homeserver
|
45
48
|
raise ArgumentError, 'Homeserver URL must be String or URI' unless @homeserver.is_a?(String) || @homeserver.is_a?(URI)
|
@@ -57,14 +60,16 @@ module MatrixSdk
|
|
57
60
|
@validate_certificate = params.fetch(:validate_certificate, false)
|
58
61
|
@transaction_id = params.fetch(:transaction_id, 0)
|
59
62
|
@backoff_time = params.fetch(:backoff_time, 5000)
|
60
|
-
@open_timeout = params.fetch(:open_timeout,
|
61
|
-
@read_timeout = params.fetch(:read_timeout,
|
63
|
+
@open_timeout = params.fetch(:open_timeout, nil)
|
64
|
+
@read_timeout = params.fetch(:read_timeout, nil)
|
62
65
|
@well_known = params.fetch(:well_known, {})
|
63
66
|
@global_headers = DEFAULT_HEADERS.dup
|
64
67
|
@global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers
|
65
68
|
@synapse = params.fetch(:synapse, true)
|
66
69
|
@http = nil
|
67
70
|
|
71
|
+
self.threadsafe = params.fetch(:threadsafe, :multithread)
|
72
|
+
|
68
73
|
([params.fetch(:protocols, [:CS])].flatten - protocols).each do |proto|
|
69
74
|
self.class.include MatrixSdk::Protocols.const_get(proto)
|
70
75
|
end
|
@@ -243,6 +248,17 @@ module MatrixSdk
|
|
243
248
|
@proxy_uri = proxy_uri
|
244
249
|
end
|
245
250
|
|
251
|
+
# @param [Boolean,:multithread] threadsafe What level of thread-safety the API should use
|
252
|
+
# @return [Boolean,:multithread]
|
253
|
+
def threadsafe=(threadsafe)
|
254
|
+
raise ArgumentError, 'Threadsafe must be either a boolean or :multithread' unless [true, false, :multithread].include? threadsafe
|
255
|
+
raise ArugmentError, 'JRuby only support :multithread/false for threadsafe' if RUBY_ENGINE == 'jruby' && threadsafe == true
|
256
|
+
|
257
|
+
@threadsafe = threadsafe
|
258
|
+
@http_lock = nil unless threadsafe == true
|
259
|
+
@threadsafe
|
260
|
+
end
|
261
|
+
|
246
262
|
# Perform a raw Matrix API request
|
247
263
|
#
|
248
264
|
# @example Simple API query
|
@@ -281,15 +297,25 @@ module MatrixSdk
|
|
281
297
|
|
282
298
|
req_obj = construct_request(url: url, method: method, **options)
|
283
299
|
print_http(req_obj, id: req_id)
|
284
|
-
|
300
|
+
response = duration = nil
|
301
|
+
|
302
|
+
loc_http = http
|
303
|
+
perform_request = proc do
|
285
304
|
dur_start = Time.now
|
286
|
-
response =
|
305
|
+
response = loc_http.request req_obj
|
287
306
|
dur_end = Time.now
|
288
307
|
duration = dur_end - dur_start
|
289
308
|
rescue EOFError
|
290
309
|
logger.error 'Socket closed unexpectedly'
|
291
310
|
raise
|
292
311
|
end
|
312
|
+
|
313
|
+
if @threadsafe == true
|
314
|
+
http_lock.synchronize { perform_request.call }
|
315
|
+
else
|
316
|
+
perform_request.call
|
317
|
+
loc_http.finish if @threadsafe == :multithread
|
318
|
+
end
|
293
319
|
print_http(response, duration: duration, id: req_id)
|
294
320
|
|
295
321
|
begin
|
@@ -392,18 +418,26 @@ module MatrixSdk
|
|
392
418
|
|
393
419
|
host = (@connection_address || homeserver.host)
|
394
420
|
port = (@connection_port || homeserver.port)
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
421
|
+
|
422
|
+
connection = @http unless @threadsafe == :multithread
|
423
|
+
connection ||= if proxy_uri
|
424
|
+
Net::HTTP.new(host, port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
|
425
|
+
else
|
426
|
+
Net::HTTP.new(host, port)
|
427
|
+
end
|
428
|
+
|
429
|
+
connection.open_timeout = open_timeout if open_timeout
|
430
|
+
connection.read_timeout = read_timeout if read_timeout
|
431
|
+
connection.use_ssl = homeserver.scheme == 'https'
|
432
|
+
connection.verify_mode = validate_certificate ? ::OpenSSL::SSL::VERIFY_PEER : ::OpenSSL::SSL::VERIFY_NONE
|
433
|
+
connection.start
|
434
|
+
@http = connection unless @threadsafe == :multithread
|
435
|
+
|
436
|
+
connection
|
437
|
+
end
|
438
|
+
|
439
|
+
def http_lock
|
440
|
+
@http_lock ||= Mutex.new if @threadsafe == true
|
407
441
|
end
|
408
442
|
end
|
409
443
|
end
|
data/lib/matrix_sdk/client.rb
CHANGED
@@ -73,6 +73,7 @@ module MatrixSdk
|
|
73
73
|
|
74
74
|
@cache = client_cache
|
75
75
|
@identity_server = nil
|
76
|
+
@mxid = nil
|
76
77
|
|
77
78
|
@sync_token = nil
|
78
79
|
@sync_thread = nil
|
@@ -102,9 +103,8 @@ module MatrixSdk
|
|
102
103
|
#
|
103
104
|
# @return [MXID] The MXID of the current user
|
104
105
|
def mxid
|
105
|
-
@mxid ||=
|
106
|
-
|
107
|
-
end
|
106
|
+
@mxid ||= MXID.new api.whoami?[:user_id] if api&.access_token
|
107
|
+
@mxid
|
108
108
|
end
|
109
109
|
|
110
110
|
alias user_id mxid
|
@@ -161,9 +161,7 @@ module MatrixSdk
|
|
161
161
|
#
|
162
162
|
# @return [Hash[String,Array[String]]] A mapping of MXIDs to a list of direct rooms with that user
|
163
163
|
def direct_rooms
|
164
|
-
|
165
|
-
[mxid.to_s, rooms]
|
166
|
-
end]
|
164
|
+
api.get_account_data(mxid, 'm.direct').transform_keys(&:to_s)
|
167
165
|
end
|
168
166
|
|
169
167
|
# Gets a direct message room for the given user if one exists
|
@@ -194,6 +192,19 @@ module MatrixSdk
|
|
194
192
|
@rooms.values
|
195
193
|
end
|
196
194
|
|
195
|
+
# Get a list of all joined Matrix Spaces
|
196
|
+
#
|
197
|
+
# @return [Array[Room]] All the currently joined Spaces
|
198
|
+
def spaces
|
199
|
+
rooms = if cache == :none
|
200
|
+
api.get_joined_rooms.joined_rooms.map { |id| Room.new(self, id) }
|
201
|
+
else
|
202
|
+
self.rooms
|
203
|
+
end
|
204
|
+
|
205
|
+
rooms.select(&:space?)
|
206
|
+
end
|
207
|
+
|
197
208
|
# Refresh the list of currently handled rooms, replacing it with the user's
|
198
209
|
# currently joined rooms.
|
199
210
|
#
|
@@ -211,6 +222,7 @@ module MatrixSdk
|
|
211
222
|
true
|
212
223
|
end
|
213
224
|
alias refresh_rooms! reload_rooms!
|
225
|
+
alias reload_spaces! reload_rooms!
|
214
226
|
|
215
227
|
# Register - and log in - on the connected HS as a guest
|
216
228
|
#
|
@@ -383,15 +395,16 @@ module MatrixSdk
|
|
383
395
|
# @param only_canonical [Boolean] Only match alias against the canonical alias
|
384
396
|
# @return [Room] The found room
|
385
397
|
# @return [nil] If no room was found
|
386
|
-
def find_room(room_id_or_alias, only_canonical:
|
398
|
+
def find_room(room_id_or_alias, only_canonical: true)
|
387
399
|
room_id_or_alias = MXID.new(room_id_or_alias.to_s) unless room_id_or_alias.is_a? MXID
|
388
400
|
raise ArgumentError, 'Must be a room id or alias' unless room_id_or_alias.room?
|
389
401
|
|
390
402
|
return @rooms.fetch(room_id_or_alias.to_s, nil) if room_id_or_alias.room_id?
|
391
403
|
|
392
|
-
|
404
|
+
room = @rooms.values.find { |r| r.aliases.include? room_id_or_alias.to_s }
|
405
|
+
return room if only_canonical
|
393
406
|
|
394
|
-
@rooms.values.find { |r| r.aliases.include? room_id_or_alias.to_s }
|
407
|
+
room || @rooms.values.find { |r| r.aliases(canonical_only: false).include? room_id_or_alias.to_s }
|
395
408
|
end
|
396
409
|
|
397
410
|
# Get a User instance from a MXID
|
@@ -429,13 +442,13 @@ module MatrixSdk
|
|
429
442
|
|
430
443
|
# Upload a piece of data to the media repo
|
431
444
|
#
|
432
|
-
# @return [URI::
|
445
|
+
# @return [URI::MXC] A Matrix content (mxc://) URL pointing to the uploaded data
|
433
446
|
# @param content [String] The data to upload
|
434
447
|
# @param content_type [String] The MIME type of the data
|
435
448
|
# @see Protocols::CS#media_upload
|
436
449
|
def upload(content, content_type)
|
437
450
|
data = api.media_upload(content, content_type)
|
438
|
-
return data[:content_uri] if data.key? :content_uri
|
451
|
+
return URI(data[:content_uri]) if data.key? :content_uri
|
439
452
|
|
440
453
|
raise MatrixUnexpectedResponseError, 'Upload succeeded, but no media URI returned'
|
441
454
|
end
|
@@ -518,11 +531,9 @@ module MatrixSdk
|
|
518
531
|
|
519
532
|
attempts = 0
|
520
533
|
data = loop do
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
|
525
|
-
end
|
534
|
+
break api.sync(**extra_params)
|
535
|
+
rescue MatrixSdk::MatrixTimeoutError => e
|
536
|
+
raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
|
526
537
|
end
|
527
538
|
|
528
539
|
@next_batch = data[:next_batch] unless skip_store_batch
|
@@ -542,11 +553,14 @@ module MatrixSdk
|
|
542
553
|
raise ArgumentError, 'Must be a room ID' unless room_id.room_id?
|
543
554
|
|
544
555
|
room_id = room_id.to_s
|
545
|
-
@rooms.fetch(room_id) do
|
556
|
+
ret = @rooms.fetch(room_id) do
|
546
557
|
room = Room.new(self, room_id)
|
547
558
|
@rooms[room_id] = room unless cache == :none
|
548
559
|
room
|
549
560
|
end
|
561
|
+
# Need to figure out a way to handle multiple types
|
562
|
+
ret = @rooms[room_id] = ret.to_space if ret.instance_variable_get :@room_type
|
563
|
+
ret
|
550
564
|
end
|
551
565
|
|
552
566
|
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval: 0, **params)
|
@@ -575,7 +589,7 @@ module MatrixSdk
|
|
575
589
|
private
|
576
590
|
|
577
591
|
def post_authentication(data)
|
578
|
-
@mxid = data[:user_id]
|
592
|
+
@mxid = MXID.new data[:user_id]
|
579
593
|
@api.access_token = data[:access_token]
|
580
594
|
@api.device_id = data[:device_id]
|
581
595
|
@api.homeserver = data[:home_server]
|
@@ -592,35 +606,35 @@ module MatrixSdk
|
|
592
606
|
end
|
593
607
|
|
594
608
|
def handle_sync_response(data)
|
595
|
-
data
|
609
|
+
data.dig(:presence, :events)&.each do |presence_update|
|
596
610
|
fire_presence_event(MatrixEvent.new(self, presence_update))
|
597
611
|
end
|
598
612
|
|
599
|
-
data
|
613
|
+
data.dig(:rooms, :invite)&.each do |room_id, invite|
|
600
614
|
invite[:room_id] = room_id.to_s
|
601
615
|
fire_invite_event(MatrixEvent.new(self, invite), room_id.to_s)
|
602
616
|
end
|
603
617
|
|
604
|
-
data
|
618
|
+
data.dig(:rooms, :leave)&.each do |room_id, left|
|
605
619
|
left[:room_id] = room_id.to_s
|
606
620
|
fire_leave_event(MatrixEvent.new(self, left), room_id.to_s)
|
607
621
|
end
|
608
622
|
|
609
|
-
data
|
623
|
+
data.dig(:rooms, :join)&.each do |room_id, join|
|
610
624
|
room = ensure_room(room_id)
|
611
|
-
room.instance_variable_set '@prev_batch', join
|
625
|
+
room.instance_variable_set '@prev_batch', join.dig(:timeline, :prev_batch)
|
612
626
|
room.instance_variable_set :@members_loaded, true unless sync_filter.fetch(:room, {}).fetch(:state, {}).fetch(:lazy_load_members, false)
|
613
627
|
|
614
|
-
join
|
628
|
+
join.dig(:state, :events)&.each do |event|
|
615
629
|
event[:room_id] = room_id.to_s
|
616
630
|
handle_state(room_id, event)
|
617
631
|
end
|
618
632
|
|
619
|
-
join
|
633
|
+
join.dig(:timeline, :events)&.each do |event|
|
620
634
|
event[:room_id] = room_id.to_s
|
621
635
|
# Avoid sending two identical state events if it's both in state and timeline
|
622
636
|
if event.key?(:state_key)
|
623
|
-
state_event = join.dig(:state, :events)
|
637
|
+
state_event = join.dig(:state, :events)&.find { |ev| ev[:event_id] == event[:event_id] }
|
624
638
|
|
625
639
|
handle_state(room_id, event) unless event == state_event
|
626
640
|
end
|
@@ -629,7 +643,7 @@ module MatrixSdk
|
|
629
643
|
fire_event(MatrixEvent.new(self, event), event[:type])
|
630
644
|
end
|
631
645
|
|
632
|
-
join
|
646
|
+
join.dig(:ephemeral, :events)&.each do |event|
|
633
647
|
event[:room_id] = room_id.to_s
|
634
648
|
room.send :put_ephemeral_event, event
|
635
649
|
|
data/lib/matrix_sdk/mxid.rb
CHANGED
@@ -12,7 +12,7 @@ module MatrixSdk
|
|
12
12
|
|
13
13
|
# TODO: Community-as-a-Room / Profile-as-a-Room, in case they're going for room aliases
|
14
14
|
@sigil = identifier[0]
|
15
|
-
@localpart, @domain, @port = identifier[1..-1].split(':')
|
15
|
+
@localpart, @domain, @port = identifier[1..-1].split(':') # rubocop:disable Style/SlicingWithRange # Keep support for slightly older Rubies
|
16
16
|
@port = @port.to_i if @port
|
17
17
|
|
18
18
|
raise ArgumentError, 'Identifier is not a valid MXID' unless valid?
|
@@ -100,5 +100,45 @@ module MatrixSdk
|
|
100
100
|
def room_alias?
|
101
101
|
type == :room_alias
|
102
102
|
end
|
103
|
+
|
104
|
+
# Converts the MXID to a matrix: URI according to MSC2312
|
105
|
+
# @param event_id [String,MXID] An event ID to append to the URI (only valid for rooms)
|
106
|
+
# @param action [String,Symbol] The action that should be requested
|
107
|
+
# @param via [Array[String]] The list of servers to use for a join
|
108
|
+
# @see https://github.com/matrix-org/matrix-doc/blob/master/proposals/2312-matrix-uri.md
|
109
|
+
def to_uri(event_id: nil, action: nil, via: nil)
|
110
|
+
uri = ''
|
111
|
+
|
112
|
+
case sigil
|
113
|
+
when '@'
|
114
|
+
raise ArgumentError, "can't provide via for user URIs" if via
|
115
|
+
raise ArgumentError, "can't provide event_id for user URIs" if event_id
|
116
|
+
|
117
|
+
uri += 'u'
|
118
|
+
when '#'
|
119
|
+
uri += 'r'
|
120
|
+
when '!'
|
121
|
+
uri += 'roomid'
|
122
|
+
else
|
123
|
+
raise ArgumentError, "this MXID can't be converted to a URI"
|
124
|
+
end
|
125
|
+
|
126
|
+
uri = "matrix:#{uri}/#{localpart}#{homeserver_suffix}"
|
127
|
+
|
128
|
+
uri += "/e/#{event_id.to_s.delete_prefix('$')}" if event_id
|
129
|
+
query = []
|
130
|
+
query << "action=#{action}" if action
|
131
|
+
[via].flatten.compact.each { |v| query << "via=#{v}" }
|
132
|
+
|
133
|
+
uri += "?#{query.join('&')}" unless query.empty?
|
134
|
+
|
135
|
+
URI(uri)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Check if two MXIDs are equal
|
139
|
+
# @return [Boolean]
|
140
|
+
def ==(other)
|
141
|
+
to_s == other.to_s
|
142
|
+
end
|
103
143
|
end
|
104
144
|
end
|