matrix_sdk 2.1.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +1 -1
- data/lib/matrix_sdk.rb +11 -1
- data/lib/matrix_sdk/api.rb +84 -59
- data/lib/matrix_sdk/client.rb +80 -57
- data/lib/matrix_sdk/errors.rb +4 -0
- data/lib/matrix_sdk/mxid.rb +50 -15
- data/lib/matrix_sdk/protocols/cs.rb +61 -37
- data/lib/matrix_sdk/protocols/msc.rb +1 -1
- data/lib/matrix_sdk/response.rb +3 -1
- data/lib/matrix_sdk/room.rb +361 -112
- data/lib/matrix_sdk/rooms/space.rb +79 -0
- data/lib/matrix_sdk/user.rb +9 -1
- data/lib/matrix_sdk/util/events.rb +111 -0
- data/lib/matrix_sdk/util/extensions.rb +75 -0
- data/lib/matrix_sdk/util/tinycache.rb +130 -0
- data/lib/matrix_sdk/util/tinycache_adapter.rb +77 -0
- data/lib/matrix_sdk/util/uri.rb +89 -0
- data/lib/matrix_sdk/version.rb +1 -1
- metadata +12 -8
- data/lib/matrix_sdk/application_service.rb +0 -212
- data/lib/matrix_sdk/extensions.rb +0 -197
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8fabc9c9f840753916f52925807e2b6282a9fd17fbeedd63f284bd60a1aab86
|
4
|
+
data.tar.gz: d0c2330e13f85036bbc0cecf1cde73fc2b960906c497b0cb7fdfe89b49499fd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 709c402251e87cd3cb650a7081d121eda551fec86f46dde8c92f2799491810ddb16bd8e44280ced09c0a5daa343385958d8ab19640348cffc2f97eafcb14bcaf
|
7
|
+
data.tar.gz: 979fc101ef76e21023b9a6ce41649c0d144a2376429ff3ff6572b0384298d598a30f05ac64e0b2e98013180e7e4b0356a26da214df28ada4c5808e8ae02af331
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## 2.4.0 - 2021-07-19
|
2
|
+
|
3
|
+
- Adds support for matrix: URI's according to MSC2312
|
4
|
+
- Adds some basic support for detecting Spaces (MSC1772)
|
5
|
+
- Fixes sync against Synapse 1.38.0 missing empty fields
|
6
|
+
|
7
|
+
## 2.3.0 - 2021-03-26
|
8
|
+
|
9
|
+
- Adds support for Ruby 3.0 (#15)
|
10
|
+
- Adds support for requests against the Synapse admin API
|
11
|
+
- Adds helper methods for checking and changing user power levels
|
12
|
+
- Adds a proper caching system for room data
|
13
|
+
- Fixes argument error in `#get_room_messages`
|
14
|
+
- Removes unfinished and broken AS abstraction
|
15
|
+
|
16
|
+
## 2.2.0 - 2020-11-20
|
17
|
+
|
18
|
+
- Adds direct message (1:1) room mapping to client abstraction
|
19
|
+
- Adds Api#get_room_event_context (#13)
|
20
|
+
- Improves support for JRuby
|
21
|
+
|
22
|
+
## 2.1.3 - 2020-09-18
|
23
|
+
|
24
|
+
- Adds separate state event handler as Client#on_state_event
|
25
|
+
- Changes Client sync interval to by-default run at full speed
|
26
|
+
- Fixes state events being sent twice if included in both timeline and state of a sync
|
27
|
+
- Improves error reporting of broken 200 responses
|
28
|
+
- Improves event handlers for rooms, to not depend on a specific room object instance anymore
|
29
|
+
|
1
30
|
## 2.1.2 - 2020-09-10
|
2
31
|
|
3
32
|
- Adds method for reading complete member lists for rooms, improves the CS spec adherence
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ A Ruby gem for easing the development of software that communicates with servers
|
|
4
4
|
|
5
5
|
There is a Matrix room for the discussion about usage and development at [#ruby-matrix-sdk:kittenface.studio](https://matrix.to/#/#ruby-matrix-sdk:kittenface.studio).
|
6
6
|
|
7
|
-
Live YARD documentation can be found at;
|
7
|
+
Live YARD documentation can be found at; https://ruby-sdk.ananace.dev
|
8
8
|
|
9
9
|
## Example usage
|
10
10
|
|
data/lib/matrix_sdk.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'matrix_sdk/extensions'
|
3
|
+
require 'matrix_sdk/util/extensions'
|
4
|
+
require 'matrix_sdk/util/uri'
|
4
5
|
require 'matrix_sdk/version'
|
5
6
|
|
6
7
|
require 'json'
|
@@ -22,6 +23,15 @@ module MatrixSdk
|
|
22
23
|
autoload :MatrixTimeoutError, 'matrix_sdk/errors'
|
23
24
|
autoload :MatrixUnexpectedResponseError, 'matrix_sdk/errors'
|
24
25
|
|
26
|
+
module Rooms
|
27
|
+
autoload :Space, 'matrix_sdk/rooms/space'
|
28
|
+
end
|
29
|
+
|
30
|
+
module Util
|
31
|
+
autoload :Tinycache, 'matrix_sdk/util/tinycache'
|
32
|
+
autoload :TinycacheAdapter, 'matrix_sdk/util/tinycache_adapter'
|
33
|
+
end
|
34
|
+
|
25
35
|
module Protocols
|
26
36
|
autoload :AS, 'matrix_sdk/protocols/as'
|
27
37
|
autoload :CS, 'matrix_sdk/protocols/cs'
|
data/lib/matrix_sdk/api.rb
CHANGED
@@ -38,6 +38,7 @@ module MatrixSdk
|
|
38
38
|
# @option params [Numeric] :read_timeout (240) The timeout in seconds for reading responses
|
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
|
+
# @option params [Boolean] :synapse (true) Is the API connecting to a Synapse instance
|
41
42
|
# @option params [Hash] :well_known The .well-known object that the server was discovered through, should not be set manually
|
42
43
|
def initialize(homeserver, **params)
|
43
44
|
@homeserver = homeserver
|
@@ -61,6 +62,7 @@ module MatrixSdk
|
|
61
62
|
@well_known = params.fetch(:well_known, {})
|
62
63
|
@global_headers = DEFAULT_HEADERS.dup
|
63
64
|
@global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers
|
65
|
+
@synapse = params.fetch(:synapse, true)
|
64
66
|
@http = nil
|
65
67
|
|
66
68
|
([params.fetch(:protocols, [:CS])].flatten - protocols).each do |proto|
|
@@ -101,30 +103,30 @@ module MatrixSdk
|
|
101
103
|
elsif target == :server
|
102
104
|
# Attempt SRV record discovery
|
103
105
|
target_uri = begin
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
106
|
+
require 'resolv'
|
107
|
+
resolver = Resolv::DNS.new
|
108
|
+
srv = "_matrix._tcp.#{domain}"
|
109
|
+
logger.debug "Trying DNS #{srv}..."
|
110
|
+
d = resolver.getresource(srv, Resolv::DNS::Resource::IN::SRV)
|
111
|
+
d
|
112
|
+
rescue StandardError => e
|
113
|
+
logger.debug "DNS lookup failed with #{e.class}: #{e.message}"
|
114
|
+
nil
|
115
|
+
end
|
114
116
|
|
115
117
|
if target_uri.nil?
|
116
118
|
# Attempt .well-known discovery for server-to-server
|
117
119
|
well_known = begin
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
120
|
+
wk_uri = URI("https://#{domain}/.well-known/matrix/server")
|
121
|
+
logger.debug "Trying #{wk_uri}..."
|
122
|
+
data = Net::HTTP.start(wk_uri.host, wk_uri.port, use_ssl: true, open_timeout: 5, read_timeout: 5, write_timeout: 5) do |http|
|
123
|
+
http.get(wk_uri.path).body
|
124
|
+
end
|
125
|
+
JSON.parse(data)
|
126
|
+
rescue StandardError => e
|
127
|
+
logger.debug "Well-known failed with #{e.class}: #{e.message}"
|
128
|
+
nil
|
129
|
+
end
|
128
130
|
|
129
131
|
target_uri = well_known['m.server'] if well_known&.key?('m.server')
|
130
132
|
else
|
@@ -133,16 +135,16 @@ module MatrixSdk
|
|
133
135
|
elsif %i[client identity].include? target
|
134
136
|
# Attempt .well-known discovery
|
135
137
|
well_known = begin
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
138
|
+
wk_uri = URI("https://#{domain}/.well-known/matrix/client")
|
139
|
+
logger.debug "Trying #{wk_uri}..."
|
140
|
+
data = Net::HTTP.start(wk_uri.host, wk_uri.port, use_ssl: true, open_timeout: 5, read_timeout: 5, write_timeout: 5) do |http|
|
141
|
+
http.get(wk_uri.path).body
|
142
|
+
end
|
143
|
+
JSON.parse(data)
|
144
|
+
rescue StandardError => e
|
145
|
+
logger.debug "Well-known failed with #{e.class}: #{e.message}"
|
146
|
+
nil
|
147
|
+
end
|
146
148
|
|
147
149
|
if well_known
|
148
150
|
key = 'm.homeserver'
|
@@ -161,11 +163,13 @@ module MatrixSdk
|
|
161
163
|
|
162
164
|
params[:well_known] = well_known if keep_wellknown
|
163
165
|
|
164
|
-
new(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
166
|
+
new(
|
167
|
+
uri,
|
168
|
+
**params.merge(
|
169
|
+
address: target_uri.host,
|
170
|
+
port: target_uri.port
|
171
|
+
)
|
172
|
+
)
|
169
173
|
end
|
170
174
|
|
171
175
|
# Get a list of enabled protocols on the API client
|
@@ -268,23 +272,6 @@ module MatrixSdk
|
|
268
272
|
u.query = [u.query, URI.encode_www_form(options.fetch(:query))].flatten.compact.join('&') if options[:query]
|
269
273
|
u.query = nil if u.query.nil? || u.query.empty?
|
270
274
|
end
|
271
|
-
request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
|
272
|
-
request.body = options[:body] if options.key? :body
|
273
|
-
request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
|
274
|
-
request.body_stream = options[:body_stream] if options.key? :body_stream
|
275
|
-
|
276
|
-
global_headers.each { |h, v| request[h] = v }
|
277
|
-
if request.body || request.body_stream
|
278
|
-
request.content_type = 'application/json'
|
279
|
-
request.content_length = (request.body || request.body_stream).size
|
280
|
-
end
|
281
|
-
|
282
|
-
request['authorization'] = "Bearer #{access_token}" if access_token && !options.fetch(:skip_auth, false)
|
283
|
-
if options.key? :headers
|
284
|
-
options[:headers].each do |h, v|
|
285
|
-
request[h.to_s.downcase] = v
|
286
|
-
end
|
287
|
-
end
|
288
275
|
|
289
276
|
failures = 0
|
290
277
|
loop do
|
@@ -292,10 +279,11 @@ module MatrixSdk
|
|
292
279
|
|
293
280
|
req_id = ('A'..'Z').to_a.sample(4).join
|
294
281
|
|
295
|
-
|
282
|
+
req_obj = construct_request(url: url, method: method, **options)
|
283
|
+
print_http(req_obj, id: req_id)
|
296
284
|
begin
|
297
285
|
dur_start = Time.now
|
298
|
-
response = http.request
|
286
|
+
response = http.request req_obj
|
299
287
|
dur_end = Time.now
|
300
288
|
duration = dur_end - dur_start
|
301
289
|
rescue EOFError
|
@@ -304,7 +292,12 @@ module MatrixSdk
|
|
304
292
|
end
|
305
293
|
print_http(response, duration: duration, id: req_id)
|
306
294
|
|
307
|
-
|
295
|
+
begin
|
296
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
297
|
+
rescue JSON::JSONError => e
|
298
|
+
logger.debug "#{e.class} error when parsing response. #{e}"
|
299
|
+
data = nil
|
300
|
+
end
|
308
301
|
|
309
302
|
if response.is_a? Net::HTTPTooManyRequests
|
310
303
|
raise MatrixRequestError.new_by_code(data, response.code) unless autoretry
|
@@ -315,7 +308,13 @@ module MatrixSdk
|
|
315
308
|
next
|
316
309
|
end
|
317
310
|
|
318
|
-
|
311
|
+
if response.is_a? Net::HTTPSuccess
|
312
|
+
unless data
|
313
|
+
logger.error "Received non-parsable data in 200 response; #{response.body.inspect}"
|
314
|
+
raise MatrixConnectionError, response
|
315
|
+
end
|
316
|
+
return MatrixSdk::Response.new self, data
|
317
|
+
end
|
319
318
|
raise MatrixRequestError.new_by_code(data, response.code) if data
|
320
319
|
|
321
320
|
raise MatrixConnectionError.class_by_code(response.code), response
|
@@ -333,14 +332,38 @@ module MatrixSdk
|
|
333
332
|
|
334
333
|
private
|
335
334
|
|
335
|
+
def construct_request(method:, url:, **options)
|
336
|
+
request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
|
337
|
+
|
338
|
+
# FIXME: Handle bodies better, avoid duplicating work
|
339
|
+
request.body = options[:body] if options.key? :body
|
340
|
+
request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
|
341
|
+
request.body_stream = options[:body_stream] if options.key? :body_stream
|
342
|
+
|
343
|
+
global_headers.each { |h, v| request[h] = v }
|
344
|
+
if request.body || request.body_stream
|
345
|
+
request.content_type = 'application/json'
|
346
|
+
request.content_length = (request.body || request.body_stream).size
|
347
|
+
end
|
348
|
+
|
349
|
+
request['authorization'] = "Bearer #{access_token}" if access_token && !options.fetch(:skip_auth, false)
|
350
|
+
if options.key? :headers
|
351
|
+
options[:headers].each do |h, v|
|
352
|
+
request[h.to_s.downcase] = v
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
request
|
357
|
+
end
|
358
|
+
|
336
359
|
def print_http(http, body: true, duration: nil, id: nil)
|
337
360
|
return unless logger.debug?
|
338
361
|
|
339
362
|
if http.is_a? Net::HTTPRequest
|
340
|
-
dir = "#{id ? id
|
363
|
+
dir = "#{id ? "#{id} : " : nil}>"
|
341
364
|
logger.debug "#{dir} Sending a #{http.method} request to `#{http.path}`:"
|
342
365
|
else
|
343
|
-
dir = "#{id ? id
|
366
|
+
dir = "#{id ? "#{id} : " : nil}<"
|
344
367
|
logger.debug "#{dir} Received a #{http.code} #{http.message} response:#{duration ? " [#{(duration * 1000).to_i}ms]" : nil}"
|
345
368
|
end
|
346
369
|
http.to_hash.map { |k, v| "#{k}: #{k == 'authorization' ? '[ REDACTED ]' : v.join(', ')}" }.each do |h|
|
@@ -349,7 +372,7 @@ module MatrixSdk
|
|
349
372
|
logger.debug dir
|
350
373
|
if body
|
351
374
|
clean_body = JSON.parse(http.body) rescue nil if http.body
|
352
|
-
clean_body.
|
375
|
+
clean_body.each_key { |k| clean_body[k] = '[ REDACTED ]' if %w[password access_token].include?(k) }.to_json if clean_body.is_a? Hash
|
353
376
|
clean_body = clean_body.to_s if clean_body
|
354
377
|
logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
|
355
378
|
end
|
@@ -358,6 +381,8 @@ module MatrixSdk
|
|
358
381
|
end
|
359
382
|
|
360
383
|
def api_to_path(api)
|
384
|
+
return "/_synapse/#{api.to_s.split('_').join('/')}" if @synapse && api.to_s.start_with?('admin_')
|
385
|
+
|
361
386
|
# TODO: <api>_current / <api>_latest
|
362
387
|
"/_matrix/#{api.to_s.split('_').join('/')}"
|
363
388
|
end
|
data/lib/matrix_sdk/client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'matrix_sdk'
|
4
|
+
require 'matrix_sdk/util/events'
|
4
5
|
|
5
6
|
require 'English'
|
6
7
|
require 'forwardable'
|
@@ -23,7 +24,7 @@ module MatrixSdk
|
|
23
24
|
attr_reader :api, :next_batch
|
24
25
|
attr_accessor :cache, :sync_filter
|
25
26
|
|
26
|
-
events :error, :event, :presence_event, :invite_event, :leave_event, :ephemeral_event
|
27
|
+
events :error, :event, :presence_event, :invite_event, :leave_event, :ephemeral_event, :state_event
|
27
28
|
ignore_inspect :api,
|
28
29
|
:on_event, :on_presence_event, :on_invite_event, :on_leave_event, :on_ephemeral_event
|
29
30
|
|
@@ -67,19 +68,17 @@ module MatrixSdk
|
|
67
68
|
api.instance_variable_set("@#{k}", v) if api.instance_variable_defined? "@#{k}"
|
68
69
|
end
|
69
70
|
else
|
70
|
-
@api = Api.new hs_url, params
|
71
|
+
@api = Api.new hs_url, **params
|
71
72
|
end
|
72
73
|
|
73
|
-
@rooms = {}
|
74
|
-
@users = {}
|
75
74
|
@cache = client_cache
|
76
75
|
@identity_server = nil
|
76
|
+
@mxid = nil
|
77
77
|
|
78
78
|
@sync_token = nil
|
79
79
|
@sync_thread = nil
|
80
80
|
@sync_filter = { room: { timeline: { limit: params.fetch(:sync_filter_limit, 20) }, state: { lazy_load_members: true } } }
|
81
81
|
|
82
|
-
@should_listen = false
|
83
82
|
@next_batch = nil
|
84
83
|
|
85
84
|
@bad_sync_timeout_limit = 60 * 60
|
@@ -88,6 +87,11 @@ module MatrixSdk
|
|
88
87
|
instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
|
89
88
|
end
|
90
89
|
|
90
|
+
@rooms = {}
|
91
|
+
@room_handlers = {}
|
92
|
+
@users = {}
|
93
|
+
@should_listen = false
|
94
|
+
|
91
95
|
raise ArgumentError, 'Cache value must be one of of [:all, :some, :none]' unless %i[all some none].include? @cache
|
92
96
|
|
93
97
|
return unless params[:user_id]
|
@@ -99,9 +103,8 @@ module MatrixSdk
|
|
99
103
|
#
|
100
104
|
# @return [MXID] The MXID of the current user
|
101
105
|
def mxid
|
102
|
-
@mxid ||=
|
103
|
-
|
104
|
-
end
|
106
|
+
@mxid ||= MXID.new api.whoami?[:user_id] if api&.access_token
|
107
|
+
@mxid
|
105
108
|
end
|
106
109
|
|
107
110
|
alias user_id mxid
|
@@ -154,6 +157,25 @@ module MatrixSdk
|
|
154
157
|
rooms
|
155
158
|
end
|
156
159
|
|
160
|
+
# Gets a list of all direct chat rooms (1:1 chats / direct message chats) for the currenct user
|
161
|
+
#
|
162
|
+
# @return [Hash[String,Array[String]]] A mapping of MXIDs to a list of direct rooms with that user
|
163
|
+
def direct_rooms
|
164
|
+
api.get_account_data(mxid, 'm.direct').transform_keys(&:to_s)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Gets a direct message room for the given user if one exists
|
168
|
+
#
|
169
|
+
# @note Will return the oldest room if multiple exist
|
170
|
+
# @return [Room,nil] A direct message room if one exists
|
171
|
+
def direct_room(mxid)
|
172
|
+
mxid = MatrixSdk::MXID.new mxid.to_s unless mxid.is_a? MatrixSdk::MXID
|
173
|
+
raise ArgumentError, 'Must be a valid user ID' unless mxid.user?
|
174
|
+
|
175
|
+
room_id = direct_rooms[mxid.to_s]&.first
|
176
|
+
ensure_room room_id if room_id
|
177
|
+
end
|
178
|
+
|
157
179
|
# Gets a list of all relevant rooms, either the ones currently handled by
|
158
180
|
# the client, or the list of currently joined ones if no rooms are handled
|
159
181
|
#
|
@@ -170,6 +192,19 @@ module MatrixSdk
|
|
170
192
|
@rooms.values
|
171
193
|
end
|
172
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
|
+
|
173
208
|
# Refresh the list of currently handled rooms, replacing it with the user's
|
174
209
|
# currently joined rooms.
|
175
210
|
#
|
@@ -187,6 +222,7 @@ module MatrixSdk
|
|
187
222
|
true
|
188
223
|
end
|
189
224
|
alias refresh_rooms! reload_rooms!
|
225
|
+
alias reload_spaces! reload_rooms!
|
190
226
|
|
191
227
|
# Register - and log in - on the connected HS as a guest
|
192
228
|
#
|
@@ -337,7 +373,7 @@ module MatrixSdk
|
|
337
373
|
# @return [Room] The resulting room
|
338
374
|
# @see Protocols::CS#create_room
|
339
375
|
def create_room(room_alias = nil, **params)
|
340
|
-
data = api.create_room(params.merge(room_alias: room_alias))
|
376
|
+
data = api.create_room(**params.merge(room_alias: room_alias))
|
341
377
|
ensure_room(data.room_id)
|
342
378
|
end
|
343
379
|
|
@@ -405,13 +441,13 @@ module MatrixSdk
|
|
405
441
|
|
406
442
|
# Upload a piece of data to the media repo
|
407
443
|
#
|
408
|
-
# @return [URI::
|
444
|
+
# @return [URI::MXC] A Matrix content (mxc://) URL pointing to the uploaded data
|
409
445
|
# @param content [String] The data to upload
|
410
446
|
# @param content_type [String] The MIME type of the data
|
411
447
|
# @see Protocols::CS#media_upload
|
412
448
|
def upload(content, content_type)
|
413
449
|
data = api.media_upload(content, content_type)
|
414
|
-
return data[:content_uri] if data.key? :content_uri
|
450
|
+
return URI(data[:content_uri]) if data.key? :content_uri
|
415
451
|
|
416
452
|
raise MatrixUnexpectedResponseError, 'Upload succeeded, but no media URI returned'
|
417
453
|
end
|
@@ -431,10 +467,11 @@ module MatrixSdk
|
|
431
467
|
errors = 0
|
432
468
|
thread, cancel_token = api.msc2108_sync_sse(params) do |data, event:, id:|
|
433
469
|
@next_batch = id if id
|
434
|
-
|
470
|
+
case event.to_sym
|
471
|
+
when :sync
|
435
472
|
handle_sync_response(data)
|
436
473
|
errors = 0
|
437
|
-
|
474
|
+
when :sync_error
|
438
475
|
logger.error "SSE Sync error received; #{data.type}: #{data.message}"
|
439
476
|
errors += 1
|
440
477
|
|
@@ -445,7 +482,7 @@ module MatrixSdk
|
|
445
482
|
|
446
483
|
@should_listen = cancel_token
|
447
484
|
else
|
448
|
-
thread = Thread.new { listen_forever(params) }
|
485
|
+
thread = Thread.new { listen_forever(**params) }
|
449
486
|
end
|
450
487
|
@sync_thread = thread
|
451
488
|
thread.run
|
@@ -493,11 +530,9 @@ module MatrixSdk
|
|
493
530
|
|
494
531
|
attempts = 0
|
495
532
|
data = loop do
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
|
500
|
-
end
|
533
|
+
break api.sync(**extra_params)
|
534
|
+
rescue MatrixSdk::MatrixTimeoutError => e
|
535
|
+
raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
|
501
536
|
end
|
502
537
|
|
503
538
|
@next_batch = data[:next_batch] unless skip_store_batch
|
@@ -524,11 +559,11 @@ module MatrixSdk
|
|
524
559
|
end
|
525
560
|
end
|
526
561
|
|
527
|
-
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval:
|
562
|
+
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval: 0, **params)
|
528
563
|
orig_bad_sync_timeout = bad_sync_timeout + 0
|
529
564
|
while @should_listen
|
530
565
|
begin
|
531
|
-
sync(params.merge(timeout: timeout))
|
566
|
+
sync(**params.merge(timeout: timeout))
|
532
567
|
|
533
568
|
bad_sync_timeout = orig_bad_sync_timeout
|
534
569
|
sleep(sync_interval) if sync_interval.positive?
|
@@ -560,71 +595,51 @@ module MatrixSdk
|
|
560
595
|
def handle_state(room_id, state_event)
|
561
596
|
return unless state_event.key? :type
|
562
597
|
|
598
|
+
on_state_event.fire(MatrixEvent.new(self, state_event), state_event[:type])
|
599
|
+
|
563
600
|
room = ensure_room(room_id)
|
564
601
|
room.send :put_state_event, state_event
|
565
|
-
content = state_event[:content]
|
566
|
-
case state_event[:type]
|
567
|
-
when 'm.room.name'
|
568
|
-
room.instance_variable_set '@name', content[:name]
|
569
|
-
when 'm.room.canonical_alias'
|
570
|
-
room.instance_variable_set '@canonical_alias', content[:alias]
|
571
|
-
# Also add as a regular alias
|
572
|
-
room.instance_variable_get('@aliases').concat [content[:alias]]
|
573
|
-
when 'm.room.topic'
|
574
|
-
room.instance_variable_set '@topic', content[:topic]
|
575
|
-
when 'm.room.aliases'
|
576
|
-
room.instance_variable_get('@aliases').concat content[:aliases]
|
577
|
-
when 'm.room.join_rules'
|
578
|
-
room.instance_variable_set '@join_rule', content[:join_rule].nil? ? nil : content[:join_rule].to_sym
|
579
|
-
when 'm.room.guest_access'
|
580
|
-
room.instance_variable_set '@guest_access', content[:guest_access].nil? ? nil : content[:guest_access].to_sym
|
581
|
-
when 'm.room.member'
|
582
|
-
return unless cache == :all
|
583
|
-
|
584
|
-
if content[:membership] == 'join'
|
585
|
-
room.send(:ensure_member, get_user(state_event[:state_key]).dup.tap do |u|
|
586
|
-
u.instance_variable_set :@display_name, content[:displayname]
|
587
|
-
end)
|
588
|
-
elsif %w[leave kick invite].include? content[:membership]
|
589
|
-
room.members.delete_if { |m| m.id == state_event[:state_key] }
|
590
|
-
end
|
591
|
-
end
|
592
602
|
end
|
593
603
|
|
594
604
|
def handle_sync_response(data)
|
595
|
-
data
|
605
|
+
data.dig(:presence, :events)&.each do |presence_update|
|
596
606
|
fire_presence_event(MatrixEvent.new(self, presence_update))
|
597
607
|
end
|
598
608
|
|
599
|
-
data
|
609
|
+
data.dig(:rooms, :invite)&.each do |room_id, invite|
|
600
610
|
invite[:room_id] = room_id.to_s
|
601
611
|
fire_invite_event(MatrixEvent.new(self, invite), room_id.to_s)
|
602
612
|
end
|
603
613
|
|
604
|
-
data
|
614
|
+
data.dig(:rooms, :leave)&.each do |room_id, left|
|
605
615
|
left[:room_id] = room_id.to_s
|
606
616
|
fire_leave_event(MatrixEvent.new(self, left), room_id.to_s)
|
607
617
|
end
|
608
618
|
|
609
|
-
data
|
619
|
+
data.dig(:rooms, :join)&.each do |room_id, join|
|
610
620
|
room = ensure_room(room_id)
|
611
|
-
room.instance_variable_set '@prev_batch', join
|
621
|
+
room.instance_variable_set '@prev_batch', join.dig(:timeline, :prev_batch)
|
612
622
|
room.instance_variable_set :@members_loaded, true unless sync_filter.fetch(:room, {}).fetch(:state, {}).fetch(:lazy_load_members, false)
|
613
623
|
|
614
|
-
join
|
624
|
+
join.dig(:state, :events)&.each do |event|
|
615
625
|
event[:room_id] = room_id.to_s
|
616
626
|
handle_state(room_id, event)
|
617
627
|
end
|
618
628
|
|
619
|
-
join
|
629
|
+
join.dig(:timeline, :events)&.each do |event|
|
620
630
|
event[:room_id] = room_id.to_s
|
621
|
-
|
631
|
+
# Avoid sending two identical state events if it's both in state and timeline
|
632
|
+
if event.key?(:state_key)
|
633
|
+
state_event = join.dig(:state, :events)&.find { |ev| ev[:event_id] == event[:event_id] }
|
634
|
+
|
635
|
+
handle_state(room_id, event) unless event == state_event
|
636
|
+
end
|
622
637
|
room.send :put_event, event
|
623
638
|
|
624
639
|
fire_event(MatrixEvent.new(self, event), event[:type])
|
625
640
|
end
|
626
641
|
|
627
|
-
join
|
642
|
+
join.dig(:ephemeral, :events)&.each do |event|
|
628
643
|
event[:room_id] = room_id.to_s
|
629
644
|
room.send :put_ephemeral_event, event
|
630
645
|
|
@@ -632,6 +647,14 @@ module MatrixSdk
|
|
632
647
|
end
|
633
648
|
end
|
634
649
|
|
650
|
+
unless cache == :none
|
651
|
+
@rooms.each do |_id, room|
|
652
|
+
# Clean up old cache data after every sync
|
653
|
+
# TODO Run this in a thread?
|
654
|
+
room.tinycache_adapter.cleanup
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
635
658
|
nil
|
636
659
|
end
|
637
660
|
end
|