matrix_sdk 2.0.0 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e0e5819346e56fd4eac1564434e88399500adefe0def16bc706a25ec7a254b2
4
- data.tar.gz: 2d74cd2d5203f5431396b03717c4302f9a0c7816c47eaa969e2395ab2eb46586
3
+ metadata.gz: e1de46ea35a8763e17d834c9395dc95a12c3084557085a0eb6b8e5f1fa25979a
4
+ data.tar.gz: 13a55698bf72695e8e690d4d5f6618d7efe595f06c32c65580b10e9bf550724e
5
5
  SHA512:
6
- metadata.gz: 7eb8ef8277b0bda1191915e5be4dcf93856cd876f611b77974b8dc88e5e230ba5c3300995157f9717a4b00d1a7cba7f7a618844cc436ad0b6a3ea5865367049d
7
- data.tar.gz: bd888c36cf3a082360dbecc408c0a67e16ddb337a721105be7abf3a9662d81bfa564a1093a64d1f934d484af6a22a36e5b91bafde70f02a882e6d092e81d5459
6
+ metadata.gz: 919a27ee7fd758c382eafe3f8aad89c13da2a6cc6542ccd8bfe52d09186d93453b12406dfe6b03b6aa63d1898dbacfb6dbced4f4e9606722ad04df4f237cf600
7
+ data.tar.gz: a8f5c0bc4fb07a089e0d1daebeb8996c6d36157550e73e3869a8bb55f25cc2c405a064654fc49c8bdb323f9d8c168b3c785e52b9f88fbc168ee29c152f7472a5
@@ -1,3 +1,8 @@
1
+ ## 2.0.1 - 2020-03-13
2
+
3
+ - Add code for handling non-final MSC's in protocols
4
+ - Currently implementing clients parts of MSC2018 for Sync over Server Sent Events
5
+
1
6
  ## 2.0.0 - 2020-02-14
2
7
 
3
8
  **NB**, this release includes backwards-incompatible changes;
@@ -27,6 +27,9 @@ module MatrixSdk
27
27
  autoload :CS, 'matrix_sdk/protocols/cs'
28
28
  autoload :IS, 'matrix_sdk/protocols/is'
29
29
  autoload :SS, 'matrix_sdk/protocols/ss'
30
+
31
+ # Non-final protocol extensions
32
+ autoload :MSC, 'matrix_sdk/protocols/msc'
30
33
  end
31
34
 
32
35
  def self.debug!
@@ -11,10 +11,6 @@ module MatrixSdk
11
11
  class Api
12
12
  extend MatrixSdk::Extensions
13
13
  include MatrixSdk::Logging
14
- include MatrixSdk::Protocols::AS
15
- include MatrixSdk::Protocols::CS
16
- include MatrixSdk::Protocols::IS
17
- include MatrixSdk::Protocols::SS
18
14
 
19
15
  USER_AGENT = "Ruby Matrix SDK v#{MatrixSdk::VERSION}"
20
16
  DEFAULT_HEADERS = {
@@ -23,7 +19,7 @@ module MatrixSdk
23
19
  }.freeze
24
20
 
25
21
  attr_accessor :access_token, :connection_address, :connection_port, :device_id, :autoretry, :global_headers
26
- attr_reader :homeserver, :validate_certificate, :open_timeout, :read_timeout, :protocols, :well_known, :proxy_uri
22
+ attr_reader :homeserver, :validate_certificate, :open_timeout, :read_timeout, :well_known, :proxy_uri
27
23
 
28
24
  ignore_inspect :access_token, :logger
29
25
 
@@ -51,10 +47,6 @@ module MatrixSdk
51
47
  @homeserver.path.gsub!(/\/?_matrix\/?/, '') if @homeserver.path =~ /_matrix\/?$/
52
48
  raise ArgumentError, 'Please use the base URL for your HS (without /_matrix/)' if @homeserver.path.include? '/_matrix/'
53
49
 
54
- @protocols = params.fetch(:protocols, %i[CS])
55
- @protocols = [@protocols] unless @protocols.is_a? Array
56
- @protocols << :CS if @protocols.include?(:AS) && !@protocols.include?(:CS)
57
-
58
50
  @proxy_uri = params.fetch(:proxy_uri, nil)
59
51
  @connection_address = params.fetch(:address, nil)
60
52
  @connection_port = params.fetch(:port, nil)
@@ -71,6 +63,10 @@ module MatrixSdk
71
63
  @global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers
72
64
  @http = nil
73
65
 
66
+ ([params.fetch(:protocols, [:CS])].flatten - protocols).each do |proto|
67
+ self.class.include MatrixSdk::Protocols.const_get(proto)
68
+ end
69
+
74
70
  login(user: @homeserver.user, password: @homeserver.password) if @homeserver.user && @homeserver.password && !@access_token && !params[:skip_login] && protocol?(:CS)
75
71
  @homeserver.userinfo = '' unless params[:skip_login]
76
72
  end
@@ -155,6 +151,20 @@ module MatrixSdk
155
151
  ))
156
152
  end
157
153
 
154
+ # Get a list of enabled protocols on the API client
155
+ #
156
+ # @example
157
+ # MatrixSdk::Api.new_for_domain('matrix.org').protocols
158
+ # # => [:IS, :CS]
159
+ #
160
+ # @return [Symbol[]] An array of enabled APIs
161
+ def protocols
162
+ self
163
+ .class.included_modules
164
+ .select { |m| m.name.start_with? 'MatrixSdk::Protocols::' }
165
+ .map { |m| m.name.split('::').last.to_sym }
166
+ end
167
+
158
168
  # Check if a protocol is enabled on the API connection
159
169
  #
160
170
  # @example Checking for identity server API support
@@ -233,6 +243,7 @@ module MatrixSdk
233
243
  # @option options [Hash,String] :body The body to attach to the request, will be JSON-encoded if sent as a hash
234
244
  # @option options [IO] :body_stream A body stream to attach to the request
235
245
  # @option options [Hash] :headers Additional headers to set on the request
246
+ # @option options [Boolean] :skip_auth (false) Skip authentication
236
247
  def request(method, api, path, **options)
237
248
  url = homeserver.dup.tap do |u|
238
249
  u.path = api_to_path(api) + path
@@ -250,7 +261,7 @@ module MatrixSdk
250
261
  request.content_length = (request.body || request.body_stream).size
251
262
  end
252
263
 
253
- request['authorization'] = "Bearer #{access_token}" if access_token
264
+ request['authorization'] = "Bearer #{access_token}" if access_token && !options.fetch(:skip_auth, false)
254
265
  if options.key? :headers
255
266
  options[:headers].each do |h, v|
256
267
  request[h.to_s.downcase] = v
@@ -289,7 +300,7 @@ module MatrixSdk
289
300
 
290
301
  private
291
302
 
292
- def print_http(http)
303
+ def print_http(http, body: true)
293
304
  return unless logger.debug?
294
305
 
295
306
  if http.is_a? Net::HTTPRequest
@@ -303,10 +314,12 @@ module MatrixSdk
303
314
  logger.debug "#{dir} #{h}"
304
315
  end
305
316
  logger.debug dir
306
- clean_body = JSON.parse(http.body) rescue nil if http.body
307
- clean_body.keys.each { |k| clean_body[k] = '[ REDACTED ]' if %w[password access_token].include?(k) }.to_json if clean_body.is_a? Hash
308
- clean_body = clean_body.to_s if clean_body
309
- logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
317
+ if body
318
+ clean_body = JSON.parse(http.body) rescue nil if http.body
319
+ clean_body.keys.each { |k| clean_body[k] = '[ REDACTED ]' if %w[password access_token].include?(k) }.to_json if clean_body.is_a? Hash
320
+ clean_body = clean_body.to_s if clean_body
321
+ logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
322
+ end
310
323
  rescue StandardError => e
311
324
  logger.warn "#{e.class} occured while printing request debug; #{e.message}\n#{e.backtrace.join "\n"}"
312
325
  end
@@ -423,7 +423,16 @@ module MatrixSdk
423
423
  return if listening?
424
424
 
425
425
  @should_listen = true
426
- thread = Thread.new { listen_forever(params) }
426
+ if api.protocol?(:MSC) && api.msc2108?
427
+ params[:since] = @next_batch if @next_batch
428
+ thread = api.msc2108_sync_sse(params) do |data, event:, id:|
429
+ logger.debug "Handling SSE event '#{event}' from '#{id}'"
430
+ @next_batch = id if id
431
+ handle_sync_response(data) if event.to_sym == :sync
432
+ end
433
+ else
434
+ thread = Thread.new { listen_forever(params) }
435
+ end
427
436
  @sync_thread = thread
428
437
  thread.run
429
438
  end
@@ -10,6 +10,7 @@ module MatrixSdk
10
10
  raise ArgumentError, 'Identifier is too long' if identifier.size > 255
11
11
  raise ArgumentError, 'Identifier lacks required data' unless identifier =~ %r{^([@!$+#][^:]+:[^:]+(?::\d+)?)|(\$[A-Za-z0-9+/]+)$}
12
12
 
13
+ # TODO: Community-as-a-Room / Profile-as-a-Room, in case they're going for room aliases
13
14
  @sigil = identifier[0]
14
15
  @localpart, @domain, @port = identifier[1..-1].split(':')
15
16
  @port = @port.to_i if @port
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Preliminary support for unmerged MSCs (Matrix Spec Changes)
4
+ module MatrixSdk::Protocols::MSC
5
+ def self.included(_)
6
+ @msc = {}
7
+ end
8
+
9
+ def refresh_mscs
10
+ @msc = {}
11
+ end
12
+
13
+ # Check if there's support for MSC2108 - Sync over Server Sent Events
14
+ def msc2108?
15
+ @msc[2108] ||= \
16
+ begin
17
+ request(:get, :client_r0, '/sync/sse', skip_auth: true, headers: { accept: 'text/event-stream' })
18
+ rescue MatrixSdk::MatrixNotAuthorizedError # Returns 401 if implemented
19
+ true
20
+ rescue MatrixSdk::MatrixRequestError
21
+ false
22
+ end
23
+ end
24
+
25
+ # Sync over Server Sent Events - MSC2108
26
+ #
27
+ # @note With the default Ruby Net::HTTP server, body fragments are cached up to 16kB,
28
+ # which will result in large batches and delays if your filters trim a lot of data.
29
+ #
30
+ # @example Syncing over SSE
31
+ # @since = 'some token'
32
+ # api.msc2108_sync_sse(since: @since) do |data, event:, id:|
33
+ # if event == 'sync'
34
+ # handle(data) # data is the same as a normal sync response
35
+ # @since = id
36
+ # end
37
+ # end
38
+ #
39
+ # @see Protocols::CS#sync
40
+ # @see https://github.com/matrix-org/matrix-doc/pull/2108/
41
+ def msc2108_sync_sse(since: nil, **params, &on_data)
42
+ raise ArgumentError, 'Must be given a block accepting two args - data and { event:, id: }' \
43
+ unless on_data.is_a?(Proc) && on_data.arity == 2
44
+ raise MatrixNotAuthorizedError unless access_token
45
+
46
+ query = params.select do |k, _v|
47
+ %i[filter full_state set_presence].include? k
48
+ end
49
+ query[:user_id] = params.delete(:user_id) if protocol?(:AS) && params.key?(:user_id)
50
+
51
+ req = Net::HTTP::Get.new(homeserver.dup.tap do |u|
52
+ u.path = api_to_path(:client_r0) + '/sync/sse'
53
+ u.query = URI.encode_www_form(query)
54
+ end)
55
+ req['accept'] = 'text/event-stream'
56
+ req['authorization'] = "Bearer #{access_token}"
57
+ req['last-event-id'] = since if since
58
+
59
+ # rubocop:disable Metrics/BlockLength
60
+ thread = Thread.new do
61
+ print_http(req)
62
+ http.request req do |response|
63
+ print_http(response, body: false)
64
+ raise MatrixRequestError.new_by_code(JSON.parse(response.body, symbolize_names: true), response.code) unless response.is_a? Net::HTTPSuccess
65
+
66
+ buffer = ''
67
+ response.read_body do |chunk|
68
+ buffer += chunk
69
+ logger.debug "< MSC2108: Received #{chunk.length}B of data."
70
+
71
+ while (index = buffer.index(/\r\n\r\n|\n\n/))
72
+ stream = buffer.slice!(0..index)
73
+
74
+ data = ''
75
+ event = nil
76
+ id = nil
77
+
78
+ stream.split(/\r?\n/).each do |part|
79
+ /^data:(.+)$/.match(part) do |m_data|
80
+ data += "\n" unless data.empty?
81
+ data += m_data[1].strip
82
+ end
83
+ /^event:(.+)$/.match(part) do |m_event|
84
+ event = m_event[1].strip
85
+ end
86
+ /^id:(.+)$/.match(part) do |m_id|
87
+ id = m_id[1].strip
88
+ end
89
+ end
90
+
91
+ data = JSON.parse(data, symbolize_names: true)
92
+
93
+ yield((MatrixSdk::Response.new self, data), event: event, id: id)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ # rubocop:enable Metrics/BlockLength
99
+
100
+ thread.abort_on_exception = true
101
+ thread.run
102
+
103
+ thread
104
+ end
105
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MatrixSdk
4
- VERSION = '2.0.0'
4
+ VERSION = '2.0.1'
5
5
  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: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Olofsson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-14 00:00:00.000000000 Z
11
+ date: 2020-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mocha
@@ -103,6 +103,7 @@ files:
103
103
  - lib/matrix_sdk/protocols/as.rb
104
104
  - lib/matrix_sdk/protocols/cs.rb
105
105
  - lib/matrix_sdk/protocols/is.rb
106
+ - lib/matrix_sdk/protocols/msc.rb
106
107
  - lib/matrix_sdk/protocols/ss.rb
107
108
  - lib/matrix_sdk/response.rb
108
109
  - lib/matrix_sdk/room.rb