matrix_sdk 2.1.2 → 2.4.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 +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
|