matrix_sdk 2.1.0 → 2.3.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 +37 -0
- data/README.md +1 -1
- data/lib/matrix_sdk.rb +6 -1
- data/lib/matrix_sdk/api.rb +87 -45
- data/lib/matrix_sdk/client.rb +56 -42
- data/lib/matrix_sdk/errors.rb +4 -0
- data/lib/matrix_sdk/mxid.rb +9 -14
- 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 +312 -109
- data/lib/matrix_sdk/user.rb +8 -0
- data/lib/matrix_sdk/{extensions.rb → util/events.rb} +4 -86
- data/lib/matrix_sdk/util/extensions.rb +90 -0
- data/lib/matrix_sdk/util/tinycache.rb +122 -0
- data/lib/matrix_sdk/util/tinycache_adapter.rb +72 -0
- data/lib/matrix_sdk/version.rb +1 -1
- metadata +10 -8
- data/lib/matrix_sdk/application_service.rb +0 -212
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb2cd8492e977a8c63d80d3a250841111f872b45ef48a06ac610dd6c871c5704
|
4
|
+
data.tar.gz: b5932dc63938f86a4bec522f2d5736871f3a5461ad5d25581c2ba1cd79b20ab2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ed57a7d4b3296a15c244c88ca88777d6ed3f9b67a6c4cdaae017f56c6e15cf94ba0781c6831a70f7adf9c55605073c84c451b0c1b0b8bffe323015330294f19
|
7
|
+
data.tar.gz: f77aaa05a45917b80aa296b7ff73f37d60ba5fb36f29a3e753cec1a730681a428c33ccdae9f4c26648952d6a7b05f9636e7d7ffbbe8757d23d2c435378d3466b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
## 2.3.0 - 2021-03-26
|
2
|
+
|
3
|
+
- Adds support for Ruby 3.0 (#15)
|
4
|
+
- Adds support for requests against the Synapse admin API
|
5
|
+
- Adds helper methods for checking and changing user power levels
|
6
|
+
- Adds a proper caching system for room data
|
7
|
+
- Fixes argument error in `#get_room_messages`
|
8
|
+
- Removes unfinished and broken AS abstraction
|
9
|
+
|
10
|
+
## 2.2.0 - 2020-11-20
|
11
|
+
|
12
|
+
- Adds direct message (1:1) room mapping to client abstraction
|
13
|
+
- Adds Api#get_room_event_context (#13)
|
14
|
+
- Improves support for JRuby
|
15
|
+
|
16
|
+
## 2.1.3 - 2020-09-18
|
17
|
+
|
18
|
+
- Adds separate state event handler as Client#on_state_event
|
19
|
+
- Changes Client sync interval to by-default run at full speed
|
20
|
+
- Fixes state events being sent twice if included in both timeline and state of a sync
|
21
|
+
- Improves error reporting of broken 200 responses
|
22
|
+
- Improves event handlers for rooms, to not depend on a specific room object instance anymore
|
23
|
+
|
24
|
+
## 2.1.2 - 2020-09-10
|
25
|
+
|
26
|
+
- Adds method for reading complete member lists for rooms, improves the CS spec adherence
|
27
|
+
- Adds test for state events
|
28
|
+
- Fixes state event handler for rooms not actually passing events
|
29
|
+
- Fixes Api#new_for_domain using a faulty URI in certain cases
|
30
|
+
|
31
|
+
## 2.1.1 - 2020-08-21
|
32
|
+
|
33
|
+
- Fixes crash if state event content is null (#11)
|
34
|
+
- Fixes an uninitialized URI constant exception when requiring only the main library file
|
35
|
+
- Fixes the Api#get_pushrules method missing an ending slash in the request URI
|
36
|
+
- Fixes discovery code for client/server connections based on domain
|
37
|
+
|
1
38
|
## 2.1.0 - 2020-05-22
|
2
39
|
|
3
40
|
- Adds unique query IDs as well as duration in API debug output, to make it easier to track long requests
|
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,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'matrix_sdk/extensions'
|
3
|
+
require 'matrix_sdk/util/extensions'
|
4
4
|
require 'matrix_sdk/version'
|
5
5
|
|
6
6
|
require 'json'
|
@@ -22,6 +22,11 @@ module MatrixSdk
|
|
22
22
|
autoload :MatrixTimeoutError, 'matrix_sdk/errors'
|
23
23
|
autoload :MatrixUnexpectedResponseError, 'matrix_sdk/errors'
|
24
24
|
|
25
|
+
module Util
|
26
|
+
autoload :Tinycache, 'matrix_sdk/util/tinycache'
|
27
|
+
autoload :TinycacheAdapter, 'matrix_sdk/util/tinycache_adapter'
|
28
|
+
end
|
29
|
+
|
25
30
|
module Protocols
|
26
31
|
autoload :AS, 'matrix_sdk/protocols/as'
|
27
32
|
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|
|
@@ -92,6 +94,8 @@ module MatrixSdk
|
|
92
94
|
uri = URI("http#{ssl ? 's' : ''}://#{domain}")
|
93
95
|
well_known = nil
|
94
96
|
target_uri = nil
|
97
|
+
logger = ::Logging.logger[self]
|
98
|
+
logger.debug "Resolving #{domain}"
|
95
99
|
|
96
100
|
if !port.nil? && !port.empty?
|
97
101
|
# If the domain is fully qualified according to Matrix (FQDN and port) then skip discovery
|
@@ -99,21 +103,30 @@ module MatrixSdk
|
|
99
103
|
elsif target == :server
|
100
104
|
# Attempt SRV record discovery
|
101
105
|
target_uri = begin
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
108
116
|
|
109
117
|
if target_uri.nil?
|
110
118
|
# Attempt .well-known discovery for server-to-server
|
111
119
|
well_known = begin
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
117
130
|
|
118
131
|
target_uri = well_known['m.server'] if well_known&.key?('m.server')
|
119
132
|
else
|
@@ -122,11 +135,16 @@ module MatrixSdk
|
|
122
135
|
elsif %i[client identity].include? target
|
123
136
|
# Attempt .well-known discovery
|
124
137
|
well_known = begin
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
130
148
|
|
131
149
|
if well_known
|
132
150
|
key = 'm.homeserver'
|
@@ -138,17 +156,20 @@ module MatrixSdk
|
|
138
156
|
end
|
139
157
|
end
|
140
158
|
end
|
159
|
+
logger.debug "Using #{target_uri.inspect}"
|
141
160
|
|
142
161
|
# Fall back to direct domain connection
|
143
162
|
target_uri ||= URI("https://#{domain}:8448")
|
144
163
|
|
145
164
|
params[:well_known] = well_known if keep_wellknown
|
146
165
|
|
147
|
-
new(
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
166
|
+
new(
|
167
|
+
uri,
|
168
|
+
**params.merge(
|
169
|
+
address: target_uri.host,
|
170
|
+
port: target_uri.port
|
171
|
+
)
|
172
|
+
)
|
152
173
|
end
|
153
174
|
|
154
175
|
# Get a list of enabled protocols on the API client
|
@@ -251,23 +272,6 @@ module MatrixSdk
|
|
251
272
|
u.query = [u.query, URI.encode_www_form(options.fetch(:query))].flatten.compact.join('&') if options[:query]
|
252
273
|
u.query = nil if u.query.nil? || u.query.empty?
|
253
274
|
end
|
254
|
-
request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
|
255
|
-
request.body = options[:body] if options.key? :body
|
256
|
-
request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
|
257
|
-
request.body_stream = options[:body_stream] if options.key? :body_stream
|
258
|
-
|
259
|
-
global_headers.each { |h, v| request[h] = v }
|
260
|
-
if request.body || request.body_stream
|
261
|
-
request.content_type = 'application/json'
|
262
|
-
request.content_length = (request.body || request.body_stream).size
|
263
|
-
end
|
264
|
-
|
265
|
-
request['authorization'] = "Bearer #{access_token}" if access_token && !options.fetch(:skip_auth, false)
|
266
|
-
if options.key? :headers
|
267
|
-
options[:headers].each do |h, v|
|
268
|
-
request[h.to_s.downcase] = v
|
269
|
-
end
|
270
|
-
end
|
271
275
|
|
272
276
|
failures = 0
|
273
277
|
loop do
|
@@ -275,10 +279,11 @@ module MatrixSdk
|
|
275
279
|
|
276
280
|
req_id = ('A'..'Z').to_a.sample(4).join
|
277
281
|
|
278
|
-
|
282
|
+
req_obj = construct_request(url: url, method: method, **options)
|
283
|
+
print_http(req_obj, id: req_id)
|
279
284
|
begin
|
280
285
|
dur_start = Time.now
|
281
|
-
response = http.request
|
286
|
+
response = http.request req_obj
|
282
287
|
dur_end = Time.now
|
283
288
|
duration = dur_end - dur_start
|
284
289
|
rescue EOFError
|
@@ -287,7 +292,12 @@ module MatrixSdk
|
|
287
292
|
end
|
288
293
|
print_http(response, duration: duration, id: req_id)
|
289
294
|
|
290
|
-
|
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
|
291
301
|
|
292
302
|
if response.is_a? Net::HTTPTooManyRequests
|
293
303
|
raise MatrixRequestError.new_by_code(data, response.code) unless autoretry
|
@@ -298,7 +308,13 @@ module MatrixSdk
|
|
298
308
|
next
|
299
309
|
end
|
300
310
|
|
301
|
-
|
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
|
302
318
|
raise MatrixRequestError.new_by_code(data, response.code) if data
|
303
319
|
|
304
320
|
raise MatrixConnectionError.class_by_code(response.code), response
|
@@ -316,14 +332,38 @@ module MatrixSdk
|
|
316
332
|
|
317
333
|
private
|
318
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
|
+
|
319
359
|
def print_http(http, body: true, duration: nil, id: nil)
|
320
360
|
return unless logger.debug?
|
321
361
|
|
322
362
|
if http.is_a? Net::HTTPRequest
|
323
|
-
dir = "#{id ? id
|
363
|
+
dir = "#{id ? "#{id} : " : nil}>"
|
324
364
|
logger.debug "#{dir} Sending a #{http.method} request to `#{http.path}`:"
|
325
365
|
else
|
326
|
-
dir = "#{id ? id
|
366
|
+
dir = "#{id ? "#{id} : " : nil}<"
|
327
367
|
logger.debug "#{dir} Received a #{http.code} #{http.message} response:#{duration ? " [#{(duration * 1000).to_i}ms]" : nil}"
|
328
368
|
end
|
329
369
|
http.to_hash.map { |k, v| "#{k}: #{k == 'authorization' ? '[ REDACTED ]' : v.join(', ')}" }.each do |h|
|
@@ -332,7 +372,7 @@ module MatrixSdk
|
|
332
372
|
logger.debug dir
|
333
373
|
if body
|
334
374
|
clean_body = JSON.parse(http.body) rescue nil if http.body
|
335
|
-
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
|
336
376
|
clean_body = clean_body.to_s if clean_body
|
337
377
|
logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
|
338
378
|
end
|
@@ -341,6 +381,8 @@ module MatrixSdk
|
|
341
381
|
end
|
342
382
|
|
343
383
|
def api_to_path(api)
|
384
|
+
return "/_synapse/#{api.to_s.split('_').join('/')}" if @synapse && api.to_s.start_with?('admin_')
|
385
|
+
|
344
386
|
# TODO: <api>_current / <api>_latest
|
345
387
|
"/_matrix/#{api.to_s.split('_').join('/')}"
|
346
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
|
|
@@ -44,7 +45,7 @@ module MatrixSdk
|
|
44
45
|
# @see #initialize
|
45
46
|
def self.new_for_domain(domain, **params)
|
46
47
|
api = MatrixSdk::Api.new_for_domain(domain, keep_wellknown: true)
|
47
|
-
return new(api, params) unless api.well_known
|
48
|
+
return new(api, params) unless api.well_known&.key?('m.identity_server')
|
48
49
|
|
49
50
|
identity_server = MatrixSdk::Api.new(api.well_known['m.identity_server']['base_url'], protocols: %i[IS])
|
50
51
|
new(api, params.merge(identity_server: identity_server))
|
@@ -67,11 +68,9 @@ 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
|
77
76
|
|
@@ -79,7 +78,6 @@ module MatrixSdk
|
|
79
78
|
@sync_thread = nil
|
80
79
|
@sync_filter = { room: { timeline: { limit: params.fetch(:sync_filter_limit, 20) }, state: { lazy_load_members: true } } }
|
81
80
|
|
82
|
-
@should_listen = false
|
83
81
|
@next_batch = nil
|
84
82
|
|
85
83
|
@bad_sync_timeout_limit = 60 * 60
|
@@ -88,6 +86,11 @@ module MatrixSdk
|
|
88
86
|
instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
|
89
87
|
end
|
90
88
|
|
89
|
+
@rooms = {}
|
90
|
+
@room_handlers = {}
|
91
|
+
@users = {}
|
92
|
+
@should_listen = false
|
93
|
+
|
91
94
|
raise ArgumentError, 'Cache value must be one of of [:all, :some, :none]' unless %i[all some none].include? @cache
|
92
95
|
|
93
96
|
return unless params[:user_id]
|
@@ -154,6 +157,27 @@ 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
|
+
Hash[api.get_account_data(mxid, 'm.direct').map do |mxid, rooms|
|
165
|
+
[mxid.to_s, rooms]
|
166
|
+
end]
|
167
|
+
end
|
168
|
+
|
169
|
+
# Gets a direct message room for the given user if one exists
|
170
|
+
#
|
171
|
+
# @note Will return the oldest room if multiple exist
|
172
|
+
# @return [Room,nil] A direct message room if one exists
|
173
|
+
def direct_room(mxid)
|
174
|
+
mxid = MatrixSdk::MXID.new mxid.to_s unless mxid.is_a? MatrixSdk::MXID
|
175
|
+
raise ArgumentError, 'Must be a valid user ID' unless mxid.user?
|
176
|
+
|
177
|
+
room_id = direct_rooms[mxid.to_s]&.first
|
178
|
+
ensure_room room_id if room_id
|
179
|
+
end
|
180
|
+
|
157
181
|
# Gets a list of all relevant rooms, either the ones currently handled by
|
158
182
|
# the client, or the list of currently joined ones if no rooms are handled
|
159
183
|
#
|
@@ -337,13 +361,13 @@ module MatrixSdk
|
|
337
361
|
# @return [Room] The resulting room
|
338
362
|
# @see Protocols::CS#create_room
|
339
363
|
def create_room(room_alias = nil, **params)
|
340
|
-
data = api.create_room(params.merge(room_alias: room_alias))
|
364
|
+
data = api.create_room(**params.merge(room_alias: room_alias))
|
341
365
|
ensure_room(data.room_id)
|
342
366
|
end
|
343
367
|
|
344
368
|
# Joins an already created room
|
345
369
|
#
|
346
|
-
# @param room_id_or_alias [String,MXID] A room alias (#room:
|
370
|
+
# @param room_id_or_alias [String,MXID] A room alias (#room:example.com) or a room ID (!id:example.com)
|
347
371
|
# @param server_name [Array[String]] A list of servers to attempt the join through, required for IDs
|
348
372
|
# @return [Room] The resulting room
|
349
373
|
# @see Protocols::CS#join_room
|
@@ -431,10 +455,11 @@ module MatrixSdk
|
|
431
455
|
errors = 0
|
432
456
|
thread, cancel_token = api.msc2108_sync_sse(params) do |data, event:, id:|
|
433
457
|
@next_batch = id if id
|
434
|
-
|
458
|
+
case event.to_sym
|
459
|
+
when :sync
|
435
460
|
handle_sync_response(data)
|
436
461
|
errors = 0
|
437
|
-
|
462
|
+
when :sync_error
|
438
463
|
logger.error "SSE Sync error received; #{data.type}: #{data.message}"
|
439
464
|
errors += 1
|
440
465
|
|
@@ -445,7 +470,7 @@ module MatrixSdk
|
|
445
470
|
|
446
471
|
@should_listen = cancel_token
|
447
472
|
else
|
448
|
-
thread = Thread.new { listen_forever(params) }
|
473
|
+
thread = Thread.new { listen_forever(**params) }
|
449
474
|
end
|
450
475
|
@sync_thread = thread
|
451
476
|
thread.run
|
@@ -494,7 +519,7 @@ module MatrixSdk
|
|
494
519
|
attempts = 0
|
495
520
|
data = loop do
|
496
521
|
begin
|
497
|
-
break api.sync extra_params
|
522
|
+
break api.sync **extra_params
|
498
523
|
rescue MatrixSdk::MatrixTimeoutError => e
|
499
524
|
raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
|
500
525
|
end
|
@@ -524,11 +549,11 @@ module MatrixSdk
|
|
524
549
|
end
|
525
550
|
end
|
526
551
|
|
527
|
-
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval:
|
552
|
+
def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval: 0, **params)
|
528
553
|
orig_bad_sync_timeout = bad_sync_timeout + 0
|
529
554
|
while @should_listen
|
530
555
|
begin
|
531
|
-
sync(params.merge(timeout: timeout))
|
556
|
+
sync(**params.merge(timeout: timeout))
|
532
557
|
|
533
558
|
bad_sync_timeout = orig_bad_sync_timeout
|
534
559
|
sleep(sync_interval) if sync_interval.positive?
|
@@ -560,34 +585,10 @@ module MatrixSdk
|
|
560
585
|
def handle_state(room_id, state_event)
|
561
586
|
return unless state_event.key? :type
|
562
587
|
|
588
|
+
on_state_event.fire(MatrixEvent.new(self, state_event), state_event[:type])
|
589
|
+
|
563
590
|
room = ensure_room(room_id)
|
564
|
-
|
565
|
-
case state_event[:type]
|
566
|
-
when 'm.room.name'
|
567
|
-
room.instance_variable_set '@name', content[:name]
|
568
|
-
when 'm.room.canonical_alias'
|
569
|
-
room.instance_variable_set '@canonical_alias', content[:alias]
|
570
|
-
# Also add as a regular alias
|
571
|
-
room.instance_variable_get('@aliases').concat [content[:alias]]
|
572
|
-
when 'm.room.topic'
|
573
|
-
room.instance_variable_set '@topic', content[:topic]
|
574
|
-
when 'm.room.aliases'
|
575
|
-
room.instance_variable_get('@aliases').concat content[:aliases]
|
576
|
-
when 'm.room.join_rules'
|
577
|
-
room.instance_variable_set '@join_rule', content[:join_rule].to_sym
|
578
|
-
when 'm.room.guest_access'
|
579
|
-
room.instance_variable_set '@guest_access', content[:guest_access].to_sym
|
580
|
-
when 'm.room.member'
|
581
|
-
return unless cache == :all
|
582
|
-
|
583
|
-
if content[:membership] == 'join'
|
584
|
-
room.send(:ensure_member, get_user(state_event[:state_key]).dup.tap do |u|
|
585
|
-
u.instance_variable_set :@display_name, content[:displayname]
|
586
|
-
end)
|
587
|
-
elsif %w[leave kick invite].include? content[:membership]
|
588
|
-
room.members.delete_if { |m| m.id == state_event[:state_key] }
|
589
|
-
end
|
590
|
-
end
|
591
|
+
room.send :put_state_event, state_event
|
591
592
|
end
|
592
593
|
|
593
594
|
def handle_sync_response(data)
|
@@ -617,7 +618,12 @@ module MatrixSdk
|
|
617
618
|
|
618
619
|
join[:timeline][:events].each do |event|
|
619
620
|
event[:room_id] = room_id.to_s
|
620
|
-
|
621
|
+
# Avoid sending two identical state events if it's both in state and timeline
|
622
|
+
if event.key?(:state_key)
|
623
|
+
state_event = join.dig(:state, :events).find { |ev| ev[:event_id] == event[:event_id] }
|
624
|
+
|
625
|
+
handle_state(room_id, event) unless event == state_event
|
626
|
+
end
|
621
627
|
room.send :put_event, event
|
622
628
|
|
623
629
|
fire_event(MatrixEvent.new(self, event), event[:type])
|
@@ -631,6 +637,14 @@ module MatrixSdk
|
|
631
637
|
end
|
632
638
|
end
|
633
639
|
|
640
|
+
unless cache == :none
|
641
|
+
@rooms.each do |_id, room|
|
642
|
+
# Clean up old cache data after every sync
|
643
|
+
# TODO Run this in a thread?
|
644
|
+
room.tinycache_adapter.cleanup
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
634
648
|
nil
|
635
649
|
end
|
636
650
|
end
|