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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +219 -0
- data/LICENSE.txt +21 -0
- data/README.md +82 -0
- data/lib/matrix_sdk/api.rb +451 -0
- data/lib/matrix_sdk/bot/base.rb +847 -0
- data/lib/matrix_sdk/bot/main.rb +79 -0
- data/lib/matrix_sdk/bot.rb +4 -0
- data/lib/matrix_sdk/client.rb +696 -0
- data/lib/matrix_sdk/errors.rb +68 -0
- data/lib/matrix_sdk/mxid.rb +146 -0
- data/lib/matrix_sdk/protocols/as.rb +7 -0
- data/lib/matrix_sdk/protocols/cs.rb +1982 -0
- data/lib/matrix_sdk/protocols/is.rb +35 -0
- data/lib/matrix_sdk/protocols/msc.rb +152 -0
- data/lib/matrix_sdk/protocols/ss.rb +14 -0
- data/lib/matrix_sdk/response.rb +63 -0
- data/lib/matrix_sdk/room.rb +1044 -0
- data/lib/matrix_sdk/rooms/space.rb +79 -0
- data/lib/matrix_sdk/user.rb +168 -0
- data/lib/matrix_sdk/util/account_data_cache.rb +91 -0
- data/lib/matrix_sdk/util/events.rb +111 -0
- data/lib/matrix_sdk/util/extensions.rb +85 -0
- data/lib/matrix_sdk/util/state_event_cache.rb +92 -0
- data/lib/matrix_sdk/util/tinycache.rb +140 -0
- data/lib/matrix_sdk/util/tinycache_adapter.rb +87 -0
- data/lib/matrix_sdk/util/uri.rb +101 -0
- data/lib/matrix_sdk/version.rb +5 -0
- data/lib/matrix_sdk.rb +75 -0
- metadata +172 -0
@@ -0,0 +1,451 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'matrix_sdk'
|
4
|
+
|
5
|
+
require 'erb'
|
6
|
+
require 'net/http'
|
7
|
+
require 'openssl'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module MatrixSdk
|
11
|
+
class Api
|
12
|
+
extend MatrixSdk::Extensions
|
13
|
+
include MatrixSdk::Logging
|
14
|
+
|
15
|
+
USER_AGENT = "Ruby Matrix SDK v#{MatrixSdk::VERSION}"
|
16
|
+
DEFAULT_HEADERS = {
|
17
|
+
'accept' => 'application/json',
|
18
|
+
'user-agent' => USER_AGENT
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
attr_accessor :access_token, :connection_address, :connection_port, :device_id, :autoretry, :global_headers
|
22
|
+
attr_reader :homeserver, :validate_certificate, :open_timeout, :read_timeout, :well_known, :proxy_uri, :threadsafe
|
23
|
+
|
24
|
+
ignore_inspect :access_token, :logger
|
25
|
+
|
26
|
+
# @param homeserver [String,URI] The URL to the Matrix homeserver, without the /_matrix/ part
|
27
|
+
# @param params [Hash] Additional parameters on creation
|
28
|
+
# @option params [Symbol[]] :protocols The protocols to include (:AS, :CS, :IS, :SS), defaults to :CS
|
29
|
+
# @option params [String] :address The connection address to the homeserver, if different to the HS URL
|
30
|
+
# @option params [Integer] :port The connection port to the homeserver, if different to the HS URL
|
31
|
+
# @option params [String] :access_token The access token to use for the connection
|
32
|
+
# @option params [String] :device_id The ID of the logged in decide to use
|
33
|
+
# @option params [Boolean] :autoretry (true) Should requests automatically be retried in case of rate limits
|
34
|
+
# @option params [Boolean] :validate_certificate (false) Should the connection require valid SSL certificates
|
35
|
+
# @option params [Integer] :transaction_id (0) The starting ID for transactions
|
36
|
+
# @option params [Numeric] :backoff_time (5000) The request backoff time in milliseconds
|
37
|
+
# @option params [Numeric] :open_timeout (60) The timeout in seconds to wait for a TCP session to open
|
38
|
+
# @option params [Numeric] :read_timeout (240) The timeout in seconds for reading responses
|
39
|
+
# @option params [Hash] :global_headers Additional headers to set for all requests
|
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
|
42
|
+
# @option params [Boolean,:multithread] :threadsafe (:multithread) Should the connection be threadsafe/mutexed - or
|
43
|
+
# safe for simultaneous multi-thread usage. Will default to +:multithread+ - a.k.a. per-thread HTTP connections
|
44
|
+
# and requests
|
45
|
+
# @note Using threadsafe +:multithread+ currently doesn't support connection re-use
|
46
|
+
def initialize(homeserver, **params)
|
47
|
+
@homeserver = homeserver
|
48
|
+
raise ArgumentError, 'Homeserver URL must be String or URI' unless @homeserver.is_a?(String) || @homeserver.is_a?(URI)
|
49
|
+
|
50
|
+
@homeserver = URI.parse("#{'https://' unless @homeserver.start_with? 'http'}#{@homeserver}") unless @homeserver.is_a? URI
|
51
|
+
@homeserver.path.gsub!(/\/?_matrix\/?/, '') if @homeserver.path =~ /_matrix\/?$/
|
52
|
+
raise ArgumentError, 'Please use the base URL for your HS (without /_matrix/)' if @homeserver.path.include? '/_matrix/'
|
53
|
+
|
54
|
+
@proxy_uri = params.fetch(:proxy_uri, nil)
|
55
|
+
@connection_address = params.fetch(:address, nil)
|
56
|
+
@connection_port = params.fetch(:port, nil)
|
57
|
+
@access_token = params.fetch(:access_token, nil)
|
58
|
+
@device_id = params.fetch(:device_id, nil)
|
59
|
+
@autoretry = params.fetch(:autoretry, true)
|
60
|
+
@validate_certificate = params.fetch(:validate_certificate, false)
|
61
|
+
@transaction_id = params.fetch(:transaction_id, 0)
|
62
|
+
@backoff_time = params.fetch(:backoff_time, 5000)
|
63
|
+
@open_timeout = params.fetch(:open_timeout, nil)
|
64
|
+
@read_timeout = params.fetch(:read_timeout, nil)
|
65
|
+
@well_known = params.fetch(:well_known, {})
|
66
|
+
@global_headers = DEFAULT_HEADERS.dup
|
67
|
+
@global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers
|
68
|
+
@synapse = params.fetch(:synapse, true)
|
69
|
+
@http = nil
|
70
|
+
@inflight = []
|
71
|
+
|
72
|
+
self.threadsafe = params.fetch(:threadsafe, :multithread)
|
73
|
+
|
74
|
+
([params.fetch(:protocols, [:CS])].flatten - protocols).each do |proto|
|
75
|
+
self.class.include MatrixSdk::Protocols.const_get(proto)
|
76
|
+
end
|
77
|
+
|
78
|
+
login(user: @homeserver.user, password: @homeserver.password) if @homeserver.user && @homeserver.password && !@access_token && !params[:skip_login] && protocol?(:CS)
|
79
|
+
@homeserver.userinfo = '' unless params[:skip_login]
|
80
|
+
end
|
81
|
+
|
82
|
+
# Create an API connection to a domain entry
|
83
|
+
#
|
84
|
+
# This will follow the server discovery spec for client-server and federation
|
85
|
+
#
|
86
|
+
# @example Opening a Matrix API connection to a homeserver
|
87
|
+
# hs = MatrixSdk::API.new_for_domain 'example.com'
|
88
|
+
# hs.connection_address
|
89
|
+
# # => 'matrix.example.com'
|
90
|
+
# hs.connection_port
|
91
|
+
# # => 443
|
92
|
+
#
|
93
|
+
# @param domain [String] The domain to set up the API connection for, can contain a ':' to denote a port
|
94
|
+
# @param target [:client,:identity,:server] The target for the domain lookup
|
95
|
+
# @param keep_wellknown [Boolean] Should the .well-known response be kept for further handling
|
96
|
+
# @param params [Hash] Additional options to pass to .new
|
97
|
+
# @return [API] The API connection
|
98
|
+
def self.new_for_domain(domain, target: :client, keep_wellknown: false, ssl: true, **params)
|
99
|
+
domain, port = domain.split(':')
|
100
|
+
uri = URI("http#{ssl ? 's' : ''}://#{domain}")
|
101
|
+
well_known = nil
|
102
|
+
target_uri = nil
|
103
|
+
logger = ::Logging.logger[self]
|
104
|
+
logger.debug "Resolving #{domain}"
|
105
|
+
|
106
|
+
if !port.nil? && !port.empty?
|
107
|
+
# If the domain is fully qualified according to Matrix (FQDN and port) then skip discovery
|
108
|
+
target_uri = URI("https://#{domain}:#{port}")
|
109
|
+
elsif target == :server
|
110
|
+
# Attempt SRV record discovery
|
111
|
+
target_uri = begin
|
112
|
+
require 'resolv'
|
113
|
+
resolver = Resolv::DNS.new
|
114
|
+
srv = "_matrix._tcp.#{domain}"
|
115
|
+
logger.debug "Trying DNS #{srv}..."
|
116
|
+
d = resolver.getresource(srv, Resolv::DNS::Resource::IN::SRV)
|
117
|
+
d
|
118
|
+
rescue StandardError => e
|
119
|
+
logger.debug "DNS lookup failed with #{e.class}: #{e.message}"
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
if target_uri.nil?
|
124
|
+
# Attempt .well-known discovery for server-to-server
|
125
|
+
well_known = begin
|
126
|
+
wk_uri = URI("https://#{domain}/.well-known/matrix/server")
|
127
|
+
logger.debug "Trying #{wk_uri}..."
|
128
|
+
data = Net::HTTP.start(wk_uri.host, wk_uri.port, use_ssl: true, open_timeout: 5, read_timeout: 5, write_timeout: 5) do |http|
|
129
|
+
http.get(wk_uri.path).body
|
130
|
+
end
|
131
|
+
JSON.parse(data)
|
132
|
+
rescue StandardError => e
|
133
|
+
logger.debug "Well-known failed with #{e.class}: #{e.message}"
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
target_uri = well_known['m.server'] if well_known&.key?('m.server')
|
138
|
+
else
|
139
|
+
target_uri = URI("https://#{target_uri.target}:#{target_uri.port}")
|
140
|
+
end
|
141
|
+
elsif %i[client identity].include? target
|
142
|
+
# Attempt .well-known discovery
|
143
|
+
well_known = begin
|
144
|
+
wk_uri = URI("https://#{domain}/.well-known/matrix/client")
|
145
|
+
logger.debug "Trying #{wk_uri}..."
|
146
|
+
data = Net::HTTP.start(wk_uri.host, wk_uri.port, use_ssl: true, open_timeout: 5, read_timeout: 5, write_timeout: 5) do |http|
|
147
|
+
http.get(wk_uri.path).body
|
148
|
+
end
|
149
|
+
JSON.parse(data)
|
150
|
+
rescue StandardError => e
|
151
|
+
logger.debug "Well-known failed with #{e.class}: #{e.message}"
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
|
155
|
+
if well_known
|
156
|
+
key = 'm.homeserver'
|
157
|
+
key = 'm.identity_server' if target == :identity
|
158
|
+
|
159
|
+
if well_known.key?(key) && well_known[key].key?('base_url')
|
160
|
+
uri = URI(well_known[key]['base_url'])
|
161
|
+
target_uri = uri
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
logger.debug "Using #{target_uri.inspect}"
|
166
|
+
|
167
|
+
# Fall back to direct domain connection
|
168
|
+
target_uri ||= URI("https://#{domain}:8448")
|
169
|
+
|
170
|
+
params[:well_known] = well_known if keep_wellknown
|
171
|
+
|
172
|
+
new(
|
173
|
+
uri,
|
174
|
+
**params.merge(
|
175
|
+
address: target_uri.host,
|
176
|
+
port: target_uri.port
|
177
|
+
)
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Get a list of enabled protocols on the API client
|
182
|
+
#
|
183
|
+
# @example
|
184
|
+
# MatrixSdk::Api.new_for_domain('matrix.org').protocols
|
185
|
+
# # => [:IS, :CS]
|
186
|
+
#
|
187
|
+
# @return [Symbol[]] An array of enabled APIs
|
188
|
+
def protocols
|
189
|
+
self
|
190
|
+
.class.included_modules
|
191
|
+
.reject { |m| m&.name.nil? }
|
192
|
+
.select { |m| m.name.start_with? 'MatrixSdk::Protocols::' }
|
193
|
+
.map { |m| m.name.split('::').last.to_sym }
|
194
|
+
end
|
195
|
+
|
196
|
+
# Check if a protocol is enabled on the API connection
|
197
|
+
#
|
198
|
+
# @example Checking for identity server API support
|
199
|
+
# api.protocol? :IS
|
200
|
+
# # => false
|
201
|
+
#
|
202
|
+
# @param protocol [Symbol] The protocol to check
|
203
|
+
# @return [Boolean] Is the protocol enabled
|
204
|
+
def protocol?(protocol)
|
205
|
+
protocols.include? protocol
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param seconds [Numeric]
|
209
|
+
# @return [Numeric]
|
210
|
+
def open_timeout=(seconds)
|
211
|
+
@http.finish if @http && @open_timeout != seconds
|
212
|
+
@open_timeout = seconds
|
213
|
+
end
|
214
|
+
|
215
|
+
# @param seconds [Numeric]
|
216
|
+
# @return [Numeric]
|
217
|
+
def read_timeout=(seconds)
|
218
|
+
@http.finish if @http && @read_timeout != seconds
|
219
|
+
@read_timeout = seconds
|
220
|
+
end
|
221
|
+
|
222
|
+
# @param validate [Boolean]
|
223
|
+
# @return [Boolean]
|
224
|
+
def validate_certificate=(validate)
|
225
|
+
# The HTTP connection needs to be reopened if this changes
|
226
|
+
@http.finish if @http && validate != @validate_certificate
|
227
|
+
@validate_certificate = validate
|
228
|
+
end
|
229
|
+
|
230
|
+
# @param hs_info [URI]
|
231
|
+
# @return [URI]
|
232
|
+
def homeserver=(hs_info)
|
233
|
+
# TODO: DNS query for SRV information about HS?
|
234
|
+
return unless hs_info.is_a? URI
|
235
|
+
|
236
|
+
@http.finish if @http && homeserver != hs_info
|
237
|
+
@homeserver = hs_info
|
238
|
+
end
|
239
|
+
|
240
|
+
# @param [URI] proxy_uri The URI for the proxy to use
|
241
|
+
# @return [URI]
|
242
|
+
def proxy_uri=(proxy_uri)
|
243
|
+
proxy_uri = URI(proxy_uri.to_s) unless proxy_uri.is_a? URI
|
244
|
+
|
245
|
+
if @http && @proxy_uri != proxy_uri
|
246
|
+
@http.finish
|
247
|
+
@http = nil
|
248
|
+
end
|
249
|
+
@proxy_uri = proxy_uri
|
250
|
+
end
|
251
|
+
|
252
|
+
# @param [Boolean,:multithread] threadsafe What level of thread-safety the API should use
|
253
|
+
# @return [Boolean,:multithread]
|
254
|
+
def threadsafe=(threadsafe)
|
255
|
+
raise ArgumentError, 'Threadsafe must be either a boolean or :multithread' unless [true, false, :multithread].include? threadsafe
|
256
|
+
raise ArugmentError, 'JRuby only support :multithread/false for threadsafe' if RUBY_ENGINE == 'jruby' && threadsafe == true
|
257
|
+
|
258
|
+
@threadsafe = threadsafe
|
259
|
+
@http_lock = nil unless threadsafe == true
|
260
|
+
@threadsafe
|
261
|
+
end
|
262
|
+
|
263
|
+
# Perform a raw Matrix API request
|
264
|
+
#
|
265
|
+
# @example Simple API query
|
266
|
+
# api.request(:get, :client_r0, '/account/whoami')
|
267
|
+
# # => { :user_id => "@alice:matrix.org" }
|
268
|
+
#
|
269
|
+
# @example Advanced API request
|
270
|
+
# api.request(:post,
|
271
|
+
# :media_r0,
|
272
|
+
# '/upload',
|
273
|
+
# body_stream: open('./file'),
|
274
|
+
# headers: { 'content-type' => 'image/png' })
|
275
|
+
# # => { :content_uri => "mxc://example.com/AQwafuaFswefuhsfAFAgsw" }
|
276
|
+
#
|
277
|
+
# @param method [Symbol] The method to use, can be any of the ones under Net::HTTP
|
278
|
+
# @param api [Symbol] The API symbol to use, :client_r0 is the current CS one
|
279
|
+
# @param path [String] The API path to call, this is the part that comes after the API definition in the spec
|
280
|
+
# @param options [Hash] Additional options to pass along to the request
|
281
|
+
# @option options [Hash] :query Query parameters to set on the URL
|
282
|
+
# @option options [Hash,String] :body The body to attach to the request, will be JSON-encoded if sent as a hash
|
283
|
+
# @option options [IO] :body_stream A body stream to attach to the request
|
284
|
+
# @option options [Hash] :headers Additional headers to set on the request
|
285
|
+
# @option options [Boolean] :skip_auth (false) Skip authentication
|
286
|
+
def request(method, api, path, **options)
|
287
|
+
url = homeserver.dup.tap do |u|
|
288
|
+
u.path = api_to_path(api) + path
|
289
|
+
u.query = [u.query, URI.encode_www_form(options.fetch(:query))].flatten.compact.join('&') if options[:query]
|
290
|
+
u.query = nil if u.query.nil? || u.query.empty?
|
291
|
+
end
|
292
|
+
|
293
|
+
failures = 0
|
294
|
+
loop do
|
295
|
+
raise MatrixConnectionError, "Server still too busy to handle request after #{failures} attempts, try again later" if failures >= 10
|
296
|
+
|
297
|
+
req_id = ('A'..'Z').to_a.sample(4).join
|
298
|
+
|
299
|
+
req_obj = construct_request(url: url, method: method, **options)
|
300
|
+
print_http(req_obj, id: req_id)
|
301
|
+
response = duration = nil
|
302
|
+
|
303
|
+
loc_http = http
|
304
|
+
perform_request = proc do
|
305
|
+
@inflight << loc_http
|
306
|
+
dur_start = Time.now
|
307
|
+
response = loc_http.request req_obj
|
308
|
+
dur_end = Time.now
|
309
|
+
duration = dur_end - dur_start
|
310
|
+
rescue EOFError
|
311
|
+
logger.error 'Socket closed unexpectedly'
|
312
|
+
raise
|
313
|
+
ensure
|
314
|
+
@inflight.delete loc_http
|
315
|
+
end
|
316
|
+
|
317
|
+
if @threadsafe == true
|
318
|
+
http_lock.synchronize { perform_request.call }
|
319
|
+
else
|
320
|
+
perform_request.call
|
321
|
+
loc_http.finish if @threadsafe == :multithread
|
322
|
+
end
|
323
|
+
print_http(response, duration: duration, id: req_id)
|
324
|
+
|
325
|
+
begin
|
326
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
327
|
+
rescue JSON::JSONError => e
|
328
|
+
logger.debug "#{e.class} error when parsing response. #{e}"
|
329
|
+
data = nil
|
330
|
+
end
|
331
|
+
|
332
|
+
if response.is_a? Net::HTTPTooManyRequests
|
333
|
+
raise MatrixRequestError.new_by_code(data, response.code) unless autoretry
|
334
|
+
|
335
|
+
failures += 1
|
336
|
+
waittime = data[:retry_after_ms] || data[:error][:retry_after_ms] || @backoff_time
|
337
|
+
sleep(waittime.to_f / 1000.0)
|
338
|
+
next
|
339
|
+
end
|
340
|
+
|
341
|
+
if response.is_a? Net::HTTPSuccess
|
342
|
+
unless data
|
343
|
+
logger.error "Received non-parsable data in 200 response; #{response.body.inspect}"
|
344
|
+
raise MatrixConnectionError, response
|
345
|
+
end
|
346
|
+
return MatrixSdk::Response.new self, data
|
347
|
+
end
|
348
|
+
raise MatrixRequestError.new_by_code(data, response.code) if data
|
349
|
+
|
350
|
+
raise MatrixConnectionError.class_by_code(response.code), response
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
# Generate a transaction ID
|
355
|
+
#
|
356
|
+
# @return [String] An arbitrary transaction ID
|
357
|
+
def transaction_id
|
358
|
+
ret = @transaction_id ||= 0
|
359
|
+
@transaction_id = @transaction_id.succ
|
360
|
+
ret
|
361
|
+
end
|
362
|
+
|
363
|
+
def stop_inflight
|
364
|
+
@inflight.each(&:finish)
|
365
|
+
end
|
366
|
+
|
367
|
+
private
|
368
|
+
|
369
|
+
def construct_request(method:, url:, **options)
|
370
|
+
request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
|
371
|
+
|
372
|
+
# FIXME: Handle bodies better, avoid duplicating work
|
373
|
+
request.body = options[:body] if options.key? :body
|
374
|
+
request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
|
375
|
+
request.body_stream = options[:body_stream] if options.key? :body_stream
|
376
|
+
|
377
|
+
global_headers.each { |h, v| request[h] = v }
|
378
|
+
if request.body || request.body_stream
|
379
|
+
request.content_type = 'application/json'
|
380
|
+
request.content_length = (request.body || request.body_stream).size
|
381
|
+
end
|
382
|
+
|
383
|
+
request['authorization'] = "Bearer #{access_token}" if access_token && !options.fetch(:skip_auth, false)
|
384
|
+
if options.key? :headers
|
385
|
+
options[:headers].each do |h, v|
|
386
|
+
request[h.to_s.downcase] = v
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
request
|
391
|
+
end
|
392
|
+
|
393
|
+
def print_http(http, body: true, duration: nil, id: nil)
|
394
|
+
return unless logger.debug?
|
395
|
+
|
396
|
+
if http.is_a? Net::HTTPRequest
|
397
|
+
dir = "#{id ? "#{id} : " : nil}>"
|
398
|
+
logger.debug "#{dir} Sending a #{http.method} request to `#{http.path}`:"
|
399
|
+
else
|
400
|
+
dir = "#{id ? "#{id} : " : nil}<"
|
401
|
+
logger.debug "#{dir} Received a #{http.code} #{http.message} response:#{duration ? " [#{(duration * 1000).to_i}ms]" : nil}"
|
402
|
+
end
|
403
|
+
http.to_hash.map { |k, v| "#{k}: #{k == 'authorization' ? '[ REDACTED ]' : v.join(', ')}" }.each do |h|
|
404
|
+
logger.debug "#{dir} #{h}"
|
405
|
+
end
|
406
|
+
logger.debug dir
|
407
|
+
if body
|
408
|
+
clean_body = JSON.parse(http.body) rescue nil if http.body
|
409
|
+
clean_body.each_key { |k| clean_body[k] = '[ REDACTED ]' if %w[password access_token].include?(k) }.to_json if clean_body.is_a? Hash
|
410
|
+
clean_body = clean_body.to_s if clean_body
|
411
|
+
logger.debug "#{dir} #{clean_body.length < 200 ? clean_body : clean_body.slice(0..200) + "... [truncated, #{clean_body.length} Bytes]"}" if clean_body
|
412
|
+
end
|
413
|
+
rescue StandardError => e
|
414
|
+
logger.warn "#{e.class} occured while printing request debug; #{e.message}\n#{e.backtrace.join "\n"}"
|
415
|
+
end
|
416
|
+
|
417
|
+
def api_to_path(api)
|
418
|
+
return "/_synapse/#{api.to_s.split('_').join('/')}" if @synapse && api.to_s.start_with?('admin_')
|
419
|
+
|
420
|
+
# TODO: <api>_current / <api>_latest
|
421
|
+
"/_matrix/#{api.to_s.split('_').join('/')}"
|
422
|
+
end
|
423
|
+
|
424
|
+
def http
|
425
|
+
return @http if @http&.active?
|
426
|
+
|
427
|
+
host = (@connection_address || homeserver.host)
|
428
|
+
port = (@connection_port || homeserver.port)
|
429
|
+
|
430
|
+
connection = @http unless @threadsafe == :multithread
|
431
|
+
connection ||= if proxy_uri
|
432
|
+
Net::HTTP.new(host, port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
|
433
|
+
else
|
434
|
+
Net::HTTP.new(host, port)
|
435
|
+
end
|
436
|
+
|
437
|
+
connection.open_timeout = open_timeout if open_timeout
|
438
|
+
connection.read_timeout = read_timeout if read_timeout
|
439
|
+
connection.use_ssl = homeserver.scheme == 'https'
|
440
|
+
connection.verify_mode = validate_certificate ? ::OpenSSL::SSL::VERIFY_PEER : ::OpenSSL::SSL::VERIFY_NONE
|
441
|
+
connection.start
|
442
|
+
@http = connection unless @threadsafe == :multithread
|
443
|
+
|
444
|
+
connection
|
445
|
+
end
|
446
|
+
|
447
|
+
def http_lock
|
448
|
+
@http_lock ||= Mutex.new if @threadsafe == true
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|