activematrix 0.0.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.
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk::Protocols::IS
4
+ def identity_status
5
+ request(:get, :identity_api_v1, '/')
6
+ end
7
+
8
+ def identity_get_pubkey(id)
9
+ id = ERB::Util.url_encode id.to_s
10
+
11
+ request(:get, :identity_api_v1, "/pubkey/#{id}")
12
+ end
13
+
14
+ def identity_pubkey_isvalid(key, ephemeral: false)
15
+ if ephemeral
16
+ request(:get, :identity_api_v1, '/pubkey/ephemeral/isvalid', query: { public_key: key })
17
+ else
18
+ request(:get, :identity_api_v1, '/pubkey/isvalid', query: { public_key: key })
19
+ end
20
+ end
21
+
22
+ def identity_pubkey_ephemeral_isvalid(key)
23
+ identity_pubkey_isvalid(key, ephemeral: true)
24
+ end
25
+
26
+ def identity_lookup(medium:, address:)
27
+ request(:get, :identity_api_v1, '/lookup', query: { medium: medium, address: address })
28
+ end
29
+
30
+ def identity_bulk_lookup(threepids)
31
+ request(:post, :identity_api_v1, '/bulk_lookup', body: { threepids: threepids })
32
+ end
33
+
34
+ # XXX
35
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Preliminary support for unmerged MSCs (Matrix Spec Changes)
4
+ module MatrixSdk::Protocols::MSC
5
+ def refresh_mscs
6
+ @msc = {}
7
+ end
8
+
9
+ # Check if there's support for MSC2108 - Sync over Server Sent Events
10
+ def msc2108?
11
+ @msc ||= {}
12
+ @msc[2108] ||= \
13
+ begin
14
+ request(:get, :client_r0, '/sync/sse', skip_auth: true, headers: { accept: 'text/event-stream' })
15
+ rescue MatrixSdk::MatrixNotAuthorizedError # Returns 401 if implemented
16
+ true
17
+ rescue MatrixSdk::MatrixRequestError
18
+ false
19
+ end
20
+ rescue StandardError => e
21
+ logger.debug "Failed to check MSC2108 status;\n#{e.inspect}"
22
+ false
23
+ end
24
+
25
+ # Sync over Server Sent Events - MSC2108
26
+ #
27
+ # @example Syncing over SSE
28
+ # @since = 'some token'
29
+ # api.msc2108_sync_sse(since: @since) do |data, event:, id:|
30
+ # if event == 'sync'
31
+ # handle(data) # data is the same as a normal sync response
32
+ # @since = id
33
+ # end
34
+ # end
35
+ #
36
+ # @see Protocols::CS#sync
37
+ # @see https://github.com/matrix-org/matrix-doc/pull/2108/
38
+ # rubocop:disable Metrics/MethodLength
39
+ def msc2108_sync_sse(since: nil, **params, &on_data)
40
+ raise ArgumentError, 'Must be given a block accepting two args - data and { event:, id: }' \
41
+ unless on_data.is_a?(Proc) && on_data.arity == 2
42
+ raise 'Needs to be logged in' unless access_token # TODO: Better error
43
+
44
+ query = params.select do |k, _v|
45
+ %i[filter full_state set_presence].include? k
46
+ end
47
+ query[:user_id] = params.delete(:user_id) if protocol?(:AS) && params.key?(:user_id)
48
+
49
+ req = Net::HTTP::Get.new(homeserver.dup.tap do |u|
50
+ u.path = "#{api_to_path :client_r0}/sync/sse"
51
+ u.query = URI.encode_www_form(query)
52
+ end)
53
+ req['accept'] = 'text/event-stream'
54
+ req['accept-encoding'] = 'identity' # Disable compression on the SSE stream
55
+ req['authorization'] = "Bearer #{access_token}"
56
+ req['last-event-id'] = since if since
57
+
58
+ cancellation_token = { run: true }
59
+
60
+ # rubocop:disable Metrics/BlockLength
61
+ thread = Thread.new(cancellation_token) do |ctx|
62
+ print_http(req)
63
+ @http_lock&.lock
64
+ http.request req do |response|
65
+ @http_lock&.unlock
66
+ break unless ctx[:run]
67
+
68
+ print_http(response, body: false)
69
+ raise MatrixRequestError.new_by_code(JSON.parse(response.body, symbolize_names: true), response.code) unless response.is_a? Net::HTTPSuccess
70
+
71
+ # Override buffer size for BufferedIO
72
+ socket = response.instance_variable_get :@socket
73
+ if socket.is_a? Net::BufferedIO
74
+ socket.instance_eval do
75
+ def rbuf_fill
76
+ bufsize_override = 1024
77
+ loop do
78
+ case rv = @io.read_nonblock(bufsize_override, exception: false)
79
+ when String
80
+ @rbuf << rv
81
+ rv.clear
82
+ return
83
+ when :wait_readable
84
+ @io.to_io.wait_readable(@read_timeout) || raise(Net::ReadTimeout)
85
+ when :wait_writable
86
+ @io.to_io.wait_writable(@read_timeout) || raise(Net::ReadTimeout)
87
+ when nil
88
+ raise EOFError, 'end of file reached'
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ stream_id = ('A'..'Z').to_a.sample(4).join
96
+
97
+ logger.debug "MSC2108 : #{stream_id} : Starting SSE stream."
98
+
99
+ buffer = ''
100
+ response.read_body do |chunk|
101
+ buffer += chunk
102
+
103
+ while (index = buffer.index(/\r\n\r\n|\n\n/))
104
+ stream = buffer.slice!(0..index)
105
+
106
+ data = ''
107
+ event = nil
108
+ id = nil
109
+
110
+ stream.split(/\r?\n/).each do |part|
111
+ /^data:(.+)$/.match(part) do |m_data|
112
+ data += "\n" unless data.empty?
113
+ data += m_data[1].strip
114
+ end
115
+ /^event:(.+)$/.match(part) do |m_event|
116
+ event = m_event[1].strip
117
+ end
118
+ /^id:(.+)$/.match(part) do |m_id|
119
+ id = m_id[1].strip
120
+ end
121
+ /^:(.+)$/.match(part) do |m_comment|
122
+ logger.debug "MSC2108 : #{stream_id} : Received comment '#{m_comment[1].strip}'"
123
+ end
124
+ end
125
+
126
+ if %w[sync sync_error].include? event
127
+ data = JSON.parse(data, symbolize_names: true)
128
+ yield((MatrixSdk::Response.new self, data), event: event, id: id)
129
+ elsif event
130
+ logger.info "MSC2108 : #{stream_id} : Received unknown event '#{event}'; #{data}"
131
+ end
132
+ end
133
+
134
+ unless ctx[:run]
135
+ socket.close
136
+ break
137
+ end
138
+ end
139
+
140
+ break unless ctx[:run]
141
+ end
142
+ ensure
143
+ @http_lock.unlock if @http_lock&.owned?
144
+ end
145
+ # rubocop:enable Metrics/BlockLength
146
+
147
+ thread.run
148
+
149
+ [thread, cancellation_token]
150
+ end
151
+ # rubocop:enable Metrics/MethodLength
152
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk::Protocols::SS
4
+ # Gets the server version
5
+ def server_version
6
+ MatrixSdk::Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
7
+ resp.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
8
+ def to_s
9
+ "#{name} #{version}"
10
+ end
11
+ CODE
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk
4
+ # An usability wrapper for API responses as an extended [Hash]
5
+ # All results can be read as both hash keys and as read-only methods on the key
6
+ #
7
+ # @example Simple usage of the response wrapper to get the avatar URL
8
+ # resp = api.get_avatar_url(api.whoami?.user_id)
9
+ # # => { avatar_url: 'mxc://matrix.org/SDGdghriugerRg' }
10
+ # resp.is_a? Hash
11
+ # # => true
12
+ # resp.key? :avatar_url
13
+ # # => true
14
+ # resp.avatar_url
15
+ # # => 'mxc://matrix.org/SDGdghriugerRg'
16
+ # resp.api.set_avatar_url(...)
17
+ # # => {}
18
+ #
19
+ # @since 0.0.3
20
+ # @see Hash
21
+ # @!attribute [r] api
22
+ # @return [Api] The API connection that returned the response
23
+ module Response
24
+ def self.new(api, data)
25
+ if data.is_a? Array
26
+ raise ArgumentError, 'Input data was not an array of hashes' unless data.all? { |v| v.is_a? Hash }
27
+
28
+ data.each do |value|
29
+ Response.new api, value
30
+ end
31
+ return data
32
+ end
33
+
34
+ return data if data.instance_variables.include? :@api
35
+
36
+ raise ArgumentError, 'Input data was not a hash' unless data.is_a? Hash
37
+
38
+ data.extend(Extensions)
39
+ data.instance_variable_set(:@api, api)
40
+
41
+ data.select { |_k, v| v.is_a? Hash }
42
+ .each { |_v, v| Response.new api, v }
43
+
44
+ data
45
+ end
46
+
47
+ module Extensions
48
+ attr_reader :api
49
+
50
+ def respond_to_missing?(name, *_args)
51
+ return true if key? name
52
+
53
+ super
54
+ end
55
+
56
+ def method_missing(name, *args)
57
+ return fetch(name) if key?(name) && args.empty?
58
+
59
+ super
60
+ end
61
+ end
62
+ end
63
+ end