Class: MatrixSdk::Api

Inherits:
Object
  • Object
show all
Defined in:
lib/matrix_sdk/api.rb

Constant Summary collapse

USER_AGENT =
"Ruby Matrix SDK v#{MatrixSdk::VERSION}".freeze
DEFAULT_HEADERS =
{
  'accept' => 'application/json',
  'user-agent' => USER_AGENT
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(homeserver, params = {}) ⇒ Api

Returns a new instance of Api.

Parameters:

  • homeserver (String, URI)

    The URL to the Matrix homeserver, without the /_matrix/ part

  • params (Hash) (defaults to: {})

    Additional parameters on creation

Options Hash (params):

  • :address (String)

    The connection address to the homeserver, if different to the HS URL

  • :port (Integer)

    The connection port to the homeserver, if different to the HS URL

  • :access_token (String)

    The access token to use for the connection

  • :device_id (String)

    The ID of the logged in decide to use

  • :autoretry (Boolean) — default: true

    Should requests automatically be retried in case of rate limits

  • :validate_certificate (Boolean) — default: false

    Should the connection require valid SSL certificates

  • :transaction_id (Integer) — default: 0

    The starting ID for transactions

  • :backoff_time (Numeric) — default: 5000

    The request backoff time in milliseconds

  • :read_timeout (Numeric) — default: 240

    The timeout in seconds for reading responses

  • :global_headers (Hash)

    Additional headers to set for all requests

  • :skip_login (Boolean)

    Should the API skip logging in if the HS URL contains user information



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/matrix_sdk/api.rb', line 35

def initialize(homeserver, params = {})
  @homeserver = homeserver
  @homeserver = URI.parse("#{'https://' unless @homeserver.start_with? 'http'}#{@homeserver}") unless @homeserver.is_a? URI
  @homeserver.path.gsub!(/\/?_matrix\/?/, '') if @homeserver.path =~ /_matrix\/?$/
  raise 'Please use the base URL for your HS (without /_matrix/)' if @homeserver.path.include? '/_matrix/'

  @connection_address = params.fetch(:address, nil)
  @connection_port = params.fetch(:port, nil)
  @access_token = params.fetch(:access_token, nil)
  @device_id = params.fetch(:device_id, nil)
  @autoretry = params.fetch(:autoretry, true)
  @validate_certificate = params.fetch(:validate_certificate, false)
  @transaction_id = params.fetch(:transaction_id, 0)
  @backoff_time = params.fetch(:backoff_time, 5000)
  @read_timeout = params.fetch(:read_timeout, 240)
  @global_headers = DEFAULT_HEADERS.dup
  @global_headers.merge!(params.fetch(:global_headers)) if params.key? :global_headers

  (user: @homeserver.user, password: @homeserver.password) if @homeserver.user && @homeserver.password && !@access_token && !params[:skip_login]
  @homeserver.userinfo = '' unless params[:skip_login]
end

Instance Attribute Details

#access_tokenObject

Returns the value of attribute access_token.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def access_token
  @access_token
end

#autoretryObject

Returns the value of attribute autoretry.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def autoretry
  @autoretry
end

#connection_addressObject

Returns the value of attribute connection_address.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def connection_address
  @connection_address
end

#connection_portObject

Returns the value of attribute connection_port.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def connection_port
  @connection_port
end

#device_idObject

Returns the value of attribute device_id.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def device_id
  @device_id
end

#global_headersObject

Returns the value of attribute global_headers.



17
18
19
# File 'lib/matrix_sdk/api.rb', line 17

def global_headers
  @global_headers
end

#homeserverObject

Returns the value of attribute homeserver.



18
19
20
# File 'lib/matrix_sdk/api.rb', line 18

def homeserver
  @homeserver
end

#read_timeoutObject

Returns the value of attribute read_timeout.



18
19
20
# File 'lib/matrix_sdk/api.rb', line 18

def read_timeout
  @read_timeout
end

#validate_certificateObject

Returns the value of attribute validate_certificate.



18
19
20
# File 'lib/matrix_sdk/api.rb', line 18

def validate_certificate
  @validate_certificate
end

Class Method Details

.new_for_domain(domain, params = {}) ⇒ API

Create an API connection to a domain entry

This will follow the server discovery spec for client-server and federation

Examples:

Opening a Matrix API connection to a homeserver

hs = MatrixSdk::API.new_for_domain 'example.com'
hs.connection_address
# => 'matrix.example.com'
hs.connection_port
# => 443

Parameters:

  • domain (String)

    The domain to set up the API connection for, can contain a ‘:’ to denote a port

  • params (Hash) (defaults to: {})

    Additional options to pass to .new

Returns:

  • (API)

    The API connection



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/matrix_sdk/api.rb', line 71

def self.new_for_domain(domain, params = {})
  # Attempt SRV record discovery
  srv = if domain.include? ':'
          addr, port = domain.split ':'
          Resolv::DNS::Resource::IN::SRV.new 10, 1, port.to_i, addr
        else
          require 'resolv'
          resolver = Resolv::DNS.new
          begin
            resolver.getresource("_matrix._tcp.#{domain}")
          rescue Resolv::ResolvError
            nil
          end
        end

  # Attempt .well-known discovery
  if srv.nil?
    well_known = begin
                   data = Net::HTTP.get("https://#{domain}/.well-known/matrix/client")
                   JSON.parse(data)
                 rescue StandardError
                   nil
                 end

    return new(well_known['m.homeserver']['base_url']) if well_known &&
                                                          well_known.key?('m.homeserver') &&
                                                          well_known['m.homerserver'].key?('base_url')
  end

  # Fall back to A record on domain
  srv ||= Resolv::DNS::Resource::IN::SRV.new 10, 1, 8448, domain

  domain = domain.split(':').first if domain.include? ':'
  new("https://#{domain}",
      params.merge(
        address: srv.target.to_s,
        port: srv.port
      ))
end

Instance Method Details

#add_user_tag(user_id, room_id, tag, params = {}) ⇒ Object



674
675
676
677
678
679
680
681
682
683
684
685
686
687
# File 'lib/matrix_sdk/api.rb', line 674

def add_user_tag(user_id, room_id, tag, params = {})
  if params[:body]
    content = params[:body]
  else
    content = {}
    content[:order] = params[:order] if params.key? :order
  end

  room_id = CGI.escape room_id.to_s
  user_id = CGI.escape user_id.to_s
  tag = CGI.escape tag.to_s

  request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags/#{tag}", body: content)
end

#ban_user(room_id, user_id, params = {}) ⇒ Object



638
639
640
641
642
643
644
645
646
647
# File 'lib/matrix_sdk/api.rb', line 638

def ban_user(room_id, user_id, params = {})
  content = {
    user_id: user_id,
    reason: params[:reason] || ''
  }

  room_id = CGI.escape room_id.to_s

  request(:post, :client_r0, "/rooms/#{room_id}/ban", body: content)
end

#client_api_unstable_featuresArray

Gets the list of available unstable client API features

Returns:

  • (Array)


156
157
158
159
160
161
162
163
164
# File 'lib/matrix_sdk/api.rb', line 156

def client_api_unstable_features
  @client_api_unstable_features ||= request(:get, :client, '/versions').unstable_features.tap do |vers|
    vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
      def has?(feature)
        fetch(feature, nil)
      end
    CODE
  end
end

#client_api_versionsArray

Gets the available client API versions

Returns:

  • (Array)


144
145
146
147
148
149
150
151
152
# File 'lib/matrix_sdk/api.rb', line 144

def client_api_versions
  @client_api_versions ||= request(:get, :client, '/versions').versions.tap do |vers|
    vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
      def latest
        latest
      end
    CODE
  end
end

#create_filter(user_id, filter_params) ⇒ Object



726
727
728
729
730
# File 'lib/matrix_sdk/api.rb', line 726

def create_filter(user_id, filter_params)
  user_id = CGI.escape user_id.to_s

  request(:post, :client_r0, "/user/#{user_id}/filter", body: filter_params)
end

#create_room(params = {}) ⇒ Response

Creates a new room

Parameters:

  • params (Hash) (defaults to: {})

    The room creation details

Options Hash (params):

  • :visibility (Symbol) — default: :public

    The room visibility

  • :room_alias (String)

    A room alias to apply on creation

  • :invite (Boolean)

    Should the room be created invite-only

Returns:

  • (Response)

    A response hash with …

See Also:



285
286
287
288
289
290
291
292
293
# File 'lib/matrix_sdk/api.rb', line 285

def create_room(params = {})
  content = {
    visibility: params.fetch(:visibility, :public)
  }
  content[:room_alias_name] = params[:room_alias] if params[:room_alias]
  content[:invite] = [params[:invite]].flatten if params[:invite]

  request(:post, :client_r0, '/createRoom', content)
end

#forget_room(room_id) ⇒ Object



600
601
602
603
604
# File 'lib/matrix_sdk/api.rb', line 600

def forget_room(room_id)
  room_id = CGI.escape room_id.to_s

  request(:post, :client_r0, "/rooms/#{room_id}/forget")
end

#get_account_data(user_id, type_key) ⇒ Object



689
690
691
692
693
694
# File 'lib/matrix_sdk/api.rb', line 689

def (user_id, type_key)
  user_id = CGI.escape user_id.to_s
  type_key = CGI.escape type_key.to_s

  request(:get, :client_r0, "/user/#{user_id}/account_data/#{type_key}")
end

#get_avatar_url(user_id) ⇒ Object



752
753
754
755
756
# File 'lib/matrix_sdk/api.rb', line 752

def get_avatar_url(user_id)
  user_id = CGI.escape user_id.to_s

  request(:get, :client_r0, "/profile/#{user_id}/avatar_url")
end

#get_display_name(user_id) ⇒ Object



736
737
738
739
740
# File 'lib/matrix_sdk/api.rb', line 736

def get_display_name(user_id)
  user_id = CGI.escape user_id.to_s

  request(:get, :client_r0, "/profile/#{user_id}/displayname")
end

#get_download_url(mxcurl) ⇒ Object



768
769
770
771
772
773
774
775
776
# File 'lib/matrix_sdk/api.rb', line 768

def get_download_url(mxcurl)
  mxcurl = URI.parse(mxcurl.to_s) unless mxcurl.is_a? URI
  raise 'Not a mxc:// URL' unless mxcurl.is_a? URI::MATRIX

  homeserver.dup.tap do |u|
    full_path = CGI.escape mxcurl.full_path.to_s
    u.path = "/_matrix/media/r0/download/#{full_path}"
  end
end

#get_filter(user_id, filter_id) ⇒ Object



719
720
721
722
723
724
# File 'lib/matrix_sdk/api.rb', line 719

def get_filter(user_id, filter_id)
  user_id = CGI.escape user_id.to_s
  filter_id = CGI.escape filter_id.to_s

  request(:get, :client_r0, "/user/#{user_id}/filter/#{filter_id}")
end

#get_membership(room_id, user_id) ⇒ Object



620
621
622
623
624
625
# File 'lib/matrix_sdk/api.rb', line 620

def get_membership(room_id, user_id)
  room_id = CGI.escape room_id.to_s
  user_id = CGI.escape user_id.to_s

  request(:get, :client_r0, "/rooms/#{room_id}/state/m.room.member/#{user_id}")
end

#get_power_levels(room_id) ⇒ Object



585
586
587
# File 'lib/matrix_sdk/api.rb', line 585

def get_power_levels(room_id)
  get_room_state(room_id, 'm.room.power_levels')
end

#get_room_account_data(user_id, room_id, type_key) ⇒ Object



703
704
705
706
707
708
709
# File 'lib/matrix_sdk/api.rb', line 703

def (user_id, room_id, type_key)
  user_id = CGI.escape user_id.to_s
  room_id = CGI.escape room_id.to_s
  type_key = CGI.escape type_key.to_s

  request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type_key}")
end

#get_room_id(room_alias) ⇒ Object



778
779
780
781
782
# File 'lib/matrix_sdk/api.rb', line 778

def get_room_id(room_alias)
  room_alias = CGI.escape room_alias.to_s

  request(:get, :client_r0, "/directory/room/#{room_alias}")
end

#get_room_members(room_id) ⇒ Object



800
801
802
803
804
# File 'lib/matrix_sdk/api.rb', line 800

def get_room_members(room_id)
  room_id = CGI.escape room_id.to_s

  request(:get, :client_r0, "/rooms/#{room_id}/members")
end

#get_room_messages(room_id, token, direction, params = {}) ⇒ Response

Retrieve additional messages in a room

Parameters:

  • room_id (MXID, String)

    The room ID to retrieve messages for

  • token (String)

    The token to start retrieving from, can be from a sync or from an earlier get_room_messages call

  • direction (:b, :f)

    The direction to retrieve messages

  • params (Hash) (defaults to: {})

    Additional options for the request

Options Hash (params):

  • :limit (Integer) — default: 10

    The limit of messages to retrieve

  • :to (String)

    A token to limit retrieval to

  • :filter (String)

    A filter to limit the retrieval to

Returns:

  • (Response)

    A response hash with the message information containing :start, :end, and :chunk fields

See Also:



527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'lib/matrix_sdk/api.rb', line 527

def get_room_messages(room_id, token, direction, params = {})
  query = {
    roomId: room_id,
    from: token,
    dir: direction,
    limit: params.fetch(:limit, 10)
  }
  query[:to] = params[:to] if params.key? :to
  query[:filter] = params.fetch(:filter) if params.key? :filter

  room_id = CGI.escape room_id.to_s

  request(:get, :client_r0, "/rooms/#{room_id}/messages", query: query)
end

#get_room_name(room_id) ⇒ Response

Gets the display name of a room

Parameters:

  • room_id (MXID, String)

    The room ID to look up

Returns:

  • (Response)

    A response hash with the parameter :name

See Also:



563
564
565
# File 'lib/matrix_sdk/api.rb', line 563

def get_room_name(room_id)
  get_room_state(room_id, 'm.room.name')
end

#get_room_state(room_id, state_type) ⇒ Response

Reads the latest instance of a room state event

Parameters:

  • room_id (MXID, String)

    The room ID to read from

  • state_type (String)

    The state type to read

Returns:

  • (Response)

    A response hash with the contents of the state event

See Also:



549
550
551
552
553
554
# File 'lib/matrix_sdk/api.rb', line 549

def get_room_state(room_id, state_type)
  room_id = CGI.escape room_id.to_s
  state_type = CGI.escape state_type.to_s

  request(:get, :client_r0, "/rooms/#{room_id}/state/#{state_type}")
end

#get_room_topic(room_id) ⇒ Object



574
575
576
# File 'lib/matrix_sdk/api.rb', line 574

def get_room_topic(room_id)
  get_room_state(room_id, 'm.room.topic')
end

#get_user_tags(user_id, room_id) ⇒ Object



659
660
661
662
663
664
# File 'lib/matrix_sdk/api.rb', line 659

def get_user_tags(user_id, room_id)
  room_id = CGI.escape room_id.to_s
  user_id = CGI.escape user_id.to_s

  request(:get, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags")
end

#invite_user(room_id, user_id) ⇒ Object



606
607
608
609
610
611
612
613
614
# File 'lib/matrix_sdk/api.rb', line 606

def invite_user(room_id, user_id)
  content = {
    user_id: user_id
  }

  room_id = CGI.escape room_id.to_s

  request(:post, :client_r0, "/rooms/#{room_id}/invite", body: content)
end

#join_room(id_or_alias) ⇒ Response

Joins a room

Parameters:

  • id_or_alias (MXID, String)

    The room ID or Alias to join

Returns:

  • (Response)

    A response hash with the parameter :room_id

See Also:



300
301
302
303
304
305
306
307
# File 'lib/matrix_sdk/api.rb', line 300

def join_room(id_or_alias)
  # id_or_alias = MXID.new id_or_alias.to_s unless id_or_alias.is_a? MXID
  # raise ArgumentError, 'Not a room ID or alias' unless id_or_alias.room?

  id_or_alias = CGI.escape id_or_alias.to_s

  request(:post, :client_r0, "/join/#{id_or_alias}")
end

#kick_user(room_id, user_id, params = {}) ⇒ Object



616
617
618
# File 'lib/matrix_sdk/api.rb', line 616

def kick_user(room_id, user_id, params = {})
  set_membership(room_id, user_id, 'leave', params)
end

#leave_room(room_id) ⇒ Object



594
595
596
597
598
# File 'lib/matrix_sdk/api.rb', line 594

def leave_room(room_id)
  room_id = CGI.escape room_id.to_s

  request(:post, :client_r0, "/rooms/#{room_id}/leave")
end

#loggerLogging::Logger

Gets the logger for the API

Returns:

  • (Logging::Logger)

    The API-scope logger



113
114
115
# File 'lib/matrix_sdk/api.rb', line 113

def logger
  @logger ||= Logging.logger[self]
end

#login(params = {}) ⇒ Response

Logs in using the client API /login endpoint, and optionally stores the resulting access for API usage

Examples:

Logging in with username and password

api.(user: 'example', password: 'NotARealPass')
# => { user_id: '@example:matrix.org', access_token: '...', home_server: 'matrix.org', device_id: 'ABCD123' }
api.whoami?
# => { user_id: '@example:matrix.org' }

Advanced login, without storing details

api.whoami?
# => { user_id: '@example:matrix.org' }
api.(medium: 'email', address: '[email protected]', password: '...', store_token: false)
# => { user_id: '@someone:matrix.org', access_token: ...
api.whoami?.user_id
# => '@example:matrix.org'

Parameters:

  • params (Hash) (defaults to: {})

    The login information to use, along with options for said log in

Options Hash (params):

  • :store_token (Boolean) — default: true

    Should the resulting access token be stored for the API

  • :store_device_id (Boolean) — default: store_token value

    Should the resulting device ID be stored for the API

  • :login_type (String) — default: 'm.login.password'

    The type of login to attempt

  • :initial_device_display_name (String) — default: USER_AGENT

    The device display name to specify for this login attempt

  • :device_id (String)

    The device ID to set on the login

Returns:

  • (Response)

    A response hash with the parameters :user_id, :access_token, :home_server, and :device_id.

See Also:



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/matrix_sdk/api.rb', line 252

def (params = {})
  options = {}
  options[:store_token] = params.delete(:store_token) { true }
  options[:store_device_id] = params.delete(:store_device_id) { options[:store_token] }

  data = {
    type: params.delete(:login_type) { 'm.login.password' },
    initial_device_display_name: params.delete(:initial_device_display_name) { USER_AGENT }
  }.merge params
  data[:device_id] = device_id if device_id

  request(:post, :client_r0, '/login', body: data).tap do |resp|
    @access_token = resp.token if resp.key?(:token) && options[:store_token]
    @device_id = resp.device_id if resp.key?(:device_id) && options[:store_device_id]
  end
end

#logoutResponse

Logs out the currently logged in user

Returns:

  • (Response)

    An empty response if the logout was successful

See Also:



273
274
275
# File 'lib/matrix_sdk/api.rb', line 273

def logout
  request(:post, :client_r0, '/logout')
end

#media_upload(content, content_type) ⇒ Object



732
733
734
# File 'lib/matrix_sdk/api.rb', line 732

def media_upload(content, content_type)
  request(:post, :media_r0, '/upload', body: content, headers: { 'content-type' => content_type })
end

#redact_event(room_id, event_id, params = {}) ⇒ Response

Redact an event in a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the message event to

  • event_id (String)

    The event ID of the event to redact

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :timestamp (Integer)

    The timestamp when the event was created, only used for AS events

  • :reason (String)

    The reason for the redaction

  • :txn_id (Integer)

    The ID of the transaction, or automatically generated

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/matrix_sdk/api.rb', line 365

def redact_event(room_id, event_id, params = {})
  query = {}
  query[:ts] = params[:timestamp].to_i if params.key? :timestamp

  content = {}
  content[:reason] = params[:reason] if params[:reason]

  txn_id = transaction_id
  txn_id = params.fetch(:txn_id, "#{txn_id}#{Time.now.to_i}")

  room_id = CGI.escape room_id.to_s
  event_id = CGI.escape event_id.to_s
  txn_id = CGI.escape txn_id.to_s

  request(:put, :client_r0, "/rooms/#{room_id}/redact/#{event_id}/#{txn_id}", body: content, query: query)
end

#register(params = {}) ⇒ Response

Registers a user using the client API /register endpoint

Examples:

Regular user registration and login

api.register(username: 'example', password: 'NotARealPass')
# => { user_id: '@example:matrix.org', access_token: '...', home_server: 'matrix.org', device_id: 'ABCD123' }
api.whoami?
# => { user_id: '@example:matrix.org' }

Parameters:

  • params (Hash) (defaults to: {})

    The registration information, all not handled by Ruby will be passed as JSON in the body

Options Hash (params):

  • :kind (String, Symbol) — default: 'user'

    The kind of registration to use

  • :store_token (Boolean) — default: true

    Should the resulting access token be stored for the API

  • :store_device_id (Boolean) — default: store_token value

    Should the resulting device ID be stored for the API

Returns:

See Also:



216
217
218
219
220
221
222
223
224
225
# File 'lib/matrix_sdk/api.rb', line 216

def register(params = {})
  kind = params.delete(:kind) { 'user' }
  store_token = params.delete(:store_token) { true }
  store_device_id = params.delete(:store_device_id) { store_token }

  request(:post, :client_r0, '/register', body: params, query: { kind: kind }).tap do |resp|
    @access_token = resp.token if resp.key?(:token) && store_token
    @device_id = resp.device_id if resp.key?(:device_id) && store_device_id
  end
end

#remove_room_alias(room_alias) ⇒ Object



794
795
796
797
798
# File 'lib/matrix_sdk/api.rb', line 794

def remove_room_alias(room_alias)
  room_alias = CGI.escape room_alias.to_s

  request(:delete, :client_r0, "/directory/room/#{room_alias}")
end

#remove_user_tag(user_id, room_id, tag) ⇒ Object



666
667
668
669
670
671
672
# File 'lib/matrix_sdk/api.rb', line 666

def remove_user_tag(user_id, room_id, tag)
  room_id = CGI.escape room_id.to_s
  user_id = CGI.escape user_id.to_s
  tag = CGI.escape tag.to_s

  request(:delete, :client_r0, "/user/#{user_id}/rooms/#{room_id}/tags/#{tag}")
end

#request(method, api, path, options = {}) ⇒ Object



826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
# File 'lib/matrix_sdk/api.rb', line 826

def request(method, api, path, options = {})
  url = homeserver.dup.tap do |u|
    u.path = api_to_path(api) + path
    u.query = [u.query, URI.encode_www_form(options.fetch(:query))].flatten.compact.join('&') if options[:query]
    u.query = nil if u.query.nil? || u.query.empty?
  end
  request = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new url.request_uri
  request.body = options[:body] if options.key? :body
  request.body = request.body.to_json if options.key?(:body) && !request.body.is_a?(String)
  request.body_stream = options[:body_stream] if options.key? :body_stream

  global_headers.each { |h, v| request[h] = v }
  if request.body || request.body_stream
    request.content_type = 'application/json'
    request.content_length = (request.body || request.body_stream).size
  end

  request['authorization'] = "Bearer #{access_token}" if access_token
  if options.key? :headers
    options[:headers].each do |h, v|
      request[h.to_s.downcase] = v
    end
  end

  failures = 0
  loop do
    raise MatrixConnectionError, "Server still too busy to handle request after #{failures} attempts, try again later" if failures >= 10

    print_http(request)
    response = http.request request
    print_http(response)
    data = JSON.parse(response.body, symbolize_names: true) rescue nil

    if response.is_a? Net::HTTPTooManyRequests
      raise MatrixRequestError.new(data, response.code) unless autoretry

      failures += 1
      waittime = data[:retry_after_ms] || data[:error][:retry_after_ms] || @backoff_time
      sleep(waittime.to_f / 1000.0)
      next
    end

    return MatrixSdk::Response.new self, data if response.is_a? Net::HTTPSuccess
    raise MatrixRequestError.new(data, response.code) if data

    raise MatrixConnectionError.class_by_code(response.code), response
  end
end

#send_content(room_id, url, name, msg_type, params = {}) ⇒ Response

Send a content message to a room

Examples:

Sending an image to a room

send_content('!abcd123:localhost',
             'mxc://localhost/1234567',
             'An image of a cat',
             'm.image',
             extra_information: {
               h: 128,
               w: 128,
               mimetype: 'image/png',
               size: 1024
             })

Sending a file to a room

send_content('!example:localhost',
             'mxc://localhost/fileurl',
             'Contract.pdf',
             'm.file',
             extra_content: {
               filename: 'contract.pdf'
             },
             extra_information: {
               mimetype: 'application/pdf',
               size: 96674
             })

Parameters:

  • room_id (MXID, String)

    The room ID to send the content to

  • url (URI, String)

    The URL to the content

  • name (String)

    The name of the content

  • msg_type (String)

    The message type of the content

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :extra_information (Hash) — default: {}

    Extra information for the content

  • :extra_content (Hash)

    Extra data to insert into the content hash

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



423
424
425
426
427
428
429
430
431
432
433
# File 'lib/matrix_sdk/api.rb', line 423

def send_content(room_id, url, name, msg_type, params = {})
  content = {
    url: url,
    msgtype: msg_type,
    body: name,
    info: params.delete(:extra_information) { {} }
  }
  content.merge!(params.fetch(:extra_content)) if params.key? :extra_content

  send_message_event(room_id, 'm.room.message', content, params)
end

#send_emote(room_id, emote, params = {}) ⇒ Response

Send a plaintext emote to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the message to

  • emote (String)

    The emote to send

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :msg_type (String) — default: 'm.emote'

    The message type to send

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



489
490
491
492
493
494
495
# File 'lib/matrix_sdk/api.rb', line 489

def send_emote(room_id, emote, params = {})
  content = {
    msgtype: params.delete(:msg_type) { 'm.emote' },
    body: emote
  }
  send_message_event(room_id, 'm.room.message', content, params)
end

#send_location(room_id, geo_uri, name, params = {}) ⇒ Response

Send a geographic location to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the location to

  • geo_uri (URI, String)

    The geographical URI to send

  • name (String)

    The name of the location

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :extra_information (Hash) — default: {}

    Extra information for the location

  • :thumbnail_url (URI, String)

    The URL to a thumbnail of the location

  • :thumbnail_info (Hash)

    Image information about the location thumbnail

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/matrix_sdk/api.rb', line 448

def send_location(room_id, geo_uri, name, params = {})
  content = {
    geo_uri: geo_uri,
    msgtype: 'm.location',
    body: name,
    info: params.delete(:extra_information) { {} }
  }
  content[:info][:thumbnail_url] = params.delete(:thumbnail_url) if params.key? :thumbnail_url
  content[:info][:thumbnail_info] = params.delete(:thumbnail_info) if params.key? :thumbnail_info

  send_message_event(room_id, 'm.room.message', content, params)
end

#send_message(room_id, message, params = {}) ⇒ Response

Send a plaintext message to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the message to

  • message (String)

    The message to send

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :msg_type (String) — default: 'm.text'

    The message type to send

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



471
472
473
474
475
476
477
# File 'lib/matrix_sdk/api.rb', line 471

def send_message(room_id, message, params = {})
  content = {
    msgtype: params.delete(:msg_type) { 'm.text' },
    body: message
  }
  send_message_event(room_id, 'm.room.message', content, params)
end

#send_message_event(room_id, event_type, content, params = {}) ⇒ Response

Sends a message event to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the message event to

  • event_type (String)

    The event type of the message

  • content (Hash)

    The contents of the message

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :timestamp (Integer)

    The timestamp when the event was created, only used for AS events

  • :txn_id (Integer)

    The ID of the transaction, or automatically generated

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/matrix_sdk/api.rb', line 341

def send_message_event(room_id, event_type, content, params = {})
  query = {}
  query[:ts] = params[:timestamp].to_i if params.key? :timestamp

  txn_id = transaction_id
  txn_id = params.fetch(:txn_id, "#{txn_id}#{Time.now.to_i}")

  room_id = CGI.escape room_id.to_s
  event_type = CGI.escape event_type.to_s
  txn_id = CGI.escape txn_id.to_s

  request(:put, :client_r0, "/rooms/#{room_id}/send/#{event_type}/#{txn_id}", body: content, query: query)
end

#send_notice(room_id, notice, params = {}) ⇒ Response

Send a plaintext notice to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the message to

  • notice (String)

    The notice to send

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :msg_type (String) — default: 'm.notice'

    The message type to send

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



507
508
509
510
511
512
513
# File 'lib/matrix_sdk/api.rb', line 507

def send_notice(room_id, notice, params = {})
  content = {
    msgtype: params.delete(:msg_type) { 'm.notice' },
    body: notice
  }
  send_message_event(room_id, 'm.room.message', content, params)
end

#send_state_event(room_id, event_type, content, params = {}) ⇒ Response

Sends a state event to a room

Parameters:

  • room_id (MXID, String)

    The room ID to send the state event to

  • event_type (String)

    The event type to send

  • content (Hash)

    The contents of the state event

  • params (Hash) (defaults to: {})

    Options for the request

Options Hash (params):

  • :timestamp (Integer)

    The timestamp when the event was created, only used for AS events

  • :state_key (String)

    The state key of the event, if there is one

Returns:

  • (Response)

    A response hash with the parameter :event_id

See Also:



320
321
322
323
324
325
326
327
328
329
# File 'lib/matrix_sdk/api.rb', line 320

def send_state_event(room_id, event_type, content, params = {})
  query = {}
  query[:ts] = params[:timestamp].to_i if params.key? :timestamp

  room_id = CGI.escape room_id.to_s
  event_type = CGI.escape event_type.to_s
  state_key = CGI.escape params[:state_key].to_s if params.key? :state_key

  request(:put, :client_r0, "/rooms/#{room_id}/state/#{event_type}#{"/#{state_key}" unless state_key.nil?}", body: content, query: query)
end

#server_versionObject

Note:

This uses the unstable federation/v1 API

Gets the server version



168
169
170
171
172
173
174
175
176
# File 'lib/matrix_sdk/api.rb', line 168

def server_version
  Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
    resp.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
      def to_s
        "#{name} #{version}"
      end
    CODE
  end
end

#set_account_data(user_id, type_key, account_data) ⇒ Object



696
697
698
699
700
701
# File 'lib/matrix_sdk/api.rb', line 696

def (user_id, type_key, )
  user_id = CGI.escape user_id.to_s
  type_key = CGI.escape type_key.to_s

  request(:put, :client_r0, "/user/#{user_id}/account_data/#{type_key}", body: )
end

#set_avatar_url(user_id, url) ⇒ Object



758
759
760
761
762
763
764
765
766
# File 'lib/matrix_sdk/api.rb', line 758

def set_avatar_url(user_id, url)
  content = {
    avatar_url: url
  }

  user_id = CGI.escape user_id.to_s

  request(:put, :client_r0, "/profile/#{user_id}/avatar_url", body: content)
end

#set_display_name(user_id, display_name) ⇒ Object



742
743
744
745
746
747
748
749
750
# File 'lib/matrix_sdk/api.rb', line 742

def set_display_name(user_id, display_name)
  content = {
    displayname: display_name
  }

  user_id = CGI.escape user_id.to_s

  request(:put, :client_r0, "/profile/#{user_id}/displayname", body: content)
end

#set_guest_access(room_id, guest_access) ⇒ Object



814
815
816
817
818
819
820
# File 'lib/matrix_sdk/api.rb', line 814

def set_guest_access(room_id, guest_access)
  # raise ArgumentError, '`guest_access` must be one of [:can_join, :forbidden]' unless %i[can_join forbidden].include? guest_access
  content = {
    guest_access: guest_access
  }
  send_state_event(room_id, 'm.room.guest_access', content)
end

#set_join_rule(room_id, join_rule) ⇒ Object



806
807
808
809
810
811
812
# File 'lib/matrix_sdk/api.rb', line 806

def set_join_rule(room_id, join_rule)
  content = {
    join_rule: join_rule
  }

  send_state_event(room_id, 'm.room.join_rules', content)
end

#set_membership(room_id, user_id, membership, params = {}) ⇒ Object



627
628
629
630
631
632
633
634
635
636
# File 'lib/matrix_sdk/api.rb', line 627

def set_membership(room_id, user_id, membership, params = {})
  content = {
    membership: membership,
    reason: params.delete(:reason) { '' }
  }
  content[:displayname] = params.delete(:displayname) if params.key? :displayname
  content[:avatar_url] = params.delete(:avatar_url) if params.key? :avatar_url

  send_state_event(room_id, 'm.room.member', content, params.merge(state_key: user_id))
end

#set_power_levels(room_id, content) ⇒ Object



589
590
591
592
# File 'lib/matrix_sdk/api.rb', line 589

def set_power_levels(room_id, content)
  content[:events] = {} unless content.key? :events
  send_state_event(room_id, 'm.room.power_levels', content)
end

#set_room_account_data(user_id, room_id, type_key, account_data) ⇒ Object



711
712
713
714
715
716
717
# File 'lib/matrix_sdk/api.rb', line 711

def (user_id, room_id, type_key, )
  user_id = CGI.escape user_id.to_s
  room_id = CGI.escape room_id.to_s
  type_key = CGI.escape type_key.to_s

  request(:put, :client_r0, "/user/#{user_id}/rooms/#{room_id}/account_data/#{type_key}", body: )
end

#set_room_alias(room_id, room_alias) ⇒ Object



784
785
786
787
788
789
790
791
792
# File 'lib/matrix_sdk/api.rb', line 784

def set_room_alias(room_id, room_alias)
  content = {
    room_id: room_id
  }

  room_alias = CGI.escape room_alias.to_s

  request(:put, :client_r0, "/directory/room/#{room_alias}", body: content)
end

#set_room_name(room_id, name, params = {}) ⇒ Object



567
568
569
570
571
572
# File 'lib/matrix_sdk/api.rb', line 567

def set_room_name(room_id, name, params = {})
  content = {
    name: name
  }
  send_state_event(room_id, 'm.room.name', content, params)
end

#set_room_topic(room_id, topic, params = {}) ⇒ Object



578
579
580
581
582
583
# File 'lib/matrix_sdk/api.rb', line 578

def set_room_topic(room_id, topic, params = {})
  content = {
    topic: topic
  }
  send_state_event(room_id, 'm.room.topic', content, params)
end

#sync(params = {}) ⇒ Response

Runs the client API /sync method

Parameters:

  • params (Hash) (defaults to: {})

    The sync options to use

Options Hash (params):

  • :timeout (Numeric) — default: 30.0

    The timeout in seconds for the sync

  • :since (Object)

    The value of the batch token to base the sync from

  • :filter (String, Hash)

    The filter to use on the sync

  • :full_state (Boolean)

    Should the sync include the full state

  • :set_presence (Boolean)

    Should the sync set the user status to online

Returns:

See Also:



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/matrix_sdk/api.rb', line 188

def sync(params = {})
  query = {
    timeout: 30.0
  }.merge(params).select do |k, _v|
    %i[since timeout filter full_state set_presence].include? k
  end

  query[:timeout] = ((query[:timeout] || 30) * 1000).to_i
  query[:timeout] = params.delete(:timeout_ms).to_i if params.key? :timeout_ms

  request(:get, :client_r0, '/sync', query: query)
end

#unban_user(room_id, user_id) ⇒ Object



649
650
651
652
653
654
655
656
657
# File 'lib/matrix_sdk/api.rb', line 649

def unban_user(room_id, user_id)
  content = {
    user_id: user_id
  }

  room_id = CGI.escape room_id.to_s

  request(:post, :client_r0, "/rooms/#{room_id}/unban", body: content)
end

#whoami?Boolean

Returns:

  • (Boolean)


822
823
824
# File 'lib/matrix_sdk/api.rb', line 822

def whoami?
  request(:get, :client_r0, '/account/whoami')
end