Class: MatrixSdk::Client

Inherits:
Object show all
Extended by:
Forwardable, Extensions
Includes:
Logging
Defined in:
lib/matrix_sdk/client.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Extensions

events, ignore_inspect

Methods included from Logging

#logger, #logger=

Constructor Details

#initialize(hs_url, client_cache: :all, **params) ⇒ Client

Returns a new instance of Client.

Parameters:

  • hs_url (String, URI, Api)

    The URL to the Matrix homeserver, without the /_matrix/ part, or an existing Api instance

  • client_cache (:all, :some, :none) (defaults to: :all)

    (:all) How much data should be cached in the client

  • params (Hash)

    Additional parameters on creation

Options Hash (**params):

  • :user_id (String, MXID)

    The user ID of the logged-in user

  • :sync_filter_limit (Integer) — default: 20

    Limit of timeline entries in syncs

Raises:

  • (ArgumentError)

See Also:

  • for additional usable params


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/matrix_sdk/client.rb', line 39

def initialize(hs_url, client_cache: :all, **params)
  event_initialize

  params[:user_id] ||= params[:mxid] if params[:mxid]

  if hs_url.is_a? Api
    @api = hs_url
    params.each do |k, v|
      api.instance_variable_set("@#{k}", v) if api.instance_variable_defined? "@#{k}"
    end
  else
    @api = Api.new hs_url, params
  end

  @rooms = {}
  @users = {}
  @cache = client_cache
  @identity_server = params.fetch(:identity_server, nil)

  @sync_token = nil
  @sync_thread = nil
  @sync_filter = { room: { timeline: { limit: params.fetch(:sync_filter_limit, 20) }, state: { lazy_load_members: true } } }

  @should_listen = false
  @next_batch = nil

  @bad_sync_timeout_limit = 60 * 60

  params.each do |k, v|
    instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
  end

  raise ArgumentError, 'Cache value must be one of of [:all, :some, :none]' unless %i[all some none].include? @cache

  return unless params[:user_id]

  @mxid = params[:user_id]
end

Instance Attribute Details

#apiObject (readonly)

Returns the value of attribute api.



14
15
16
# File 'lib/matrix_sdk/client.rb', line 14

def api
  @api
end

#cacheObject

Returns the value of attribute cache.



15
16
17
# File 'lib/matrix_sdk/client.rb', line 15

def cache
  @cache
end

#sync_filterObject

Returns the value of attribute sync_filter.



15
16
17
# File 'lib/matrix_sdk/client.rb', line 15

def sync_filter
  @sync_filter
end

Class Method Details

.new_for_domain(domain, **params) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/matrix_sdk/client.rb', line 25

def self.new_for_domain(domain, **params)
  api = MatrixSdk::Api.new_for_domain(domain, keep_wellknown: true)
  return new(api, params) unless api.well_known.key? 'm.identity_server'

  identity_server = MatrixSdk::Api.new(api.well_known['m.identity_server']['base_url'], protocols: %i[IS])
  new(api, params.merge(identity_server: identity_server))
end

Instance Method Details

#create_room(room_alias = nil, **params) ⇒ Object



205
206
207
208
# File 'lib/matrix_sdk/client.rb', line 205

def create_room(room_alias = nil, **params)
  data = api.create_room(params.merge(room_alias: room_alias))
  ensure_room(data.room_id)
end

#find_room(room_id_or_alias, only_canonical: false) ⇒ Object

Raises:

  • (ArgumentError)


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

def find_room(room_id_or_alias, only_canonical: false)
  room_id_or_alias = MXID.new(room_id_or_alias.to_s) unless room_id_or_alias.is_a? MXID
  raise ArgumentError, 'Must be a room id or alias' unless %i[room_id room_alias].include? room_id_or_alias.type

  return @rooms.fetch(room_id_or_alias.to_s, nil) if room_id_or_alias.room_id?

  return @rooms.values.find { |r| r.canonical_alias == room_id_or_alias.to_s } if only_canonical

  @rooms.values.find { |r| r.aliases.include? room_id_or_alias.to_s }
end

#get_user(user_id) ⇒ Object



227
228
229
230
231
232
233
# File 'lib/matrix_sdk/client.rb', line 227

def get_user(user_id)
  if cache == :all
    @users[user_id] ||= User.new(self, user_id)
  else
    User.new(self, user_id)
  end
end

#join_room(room_id_or_alias, server_name: []) ⇒ Object



210
211
212
213
214
# File 'lib/matrix_sdk/client.rb', line 210

def join_room(room_id_or_alias, server_name: [])
  server_name = [server_name] unless server_name.is_a? Array
  data = api.join_room(room_id_or_alias, server_name: server_name)
  ensure_room(data.fetch(:room_id, room_id_or_alias))
end

#listening?Boolean

Returns:

  • (Boolean)


261
262
263
# File 'lib/matrix_sdk/client.rb', line 261

def listening?
  @sync_thread&.alive? == true
end

#logged_in?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/matrix_sdk/client.rb', line 201

def logged_in?
  !(mxid.nil? || @api.access_token.nil?)
end

#login(username, password, sync_timeout: 15, full_state: false, **params) ⇒ Object

Raises:

  • (ArgumentError)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/matrix_sdk/client.rb', line 161

def (username, password, sync_timeout: 15, full_state: false, **params)
  username = username.to_s unless username.is_a?(String)
  password = password.to_s unless password.is_a?(String)

  raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
  raise ArgumentError, "Password can't be nil or empty" if password.nil? || password.empty?

  data = api.(user: username, password: password)
  post_authentication(data)

  return if params[:no_sync]

  sync timeout: sync_timeout,
       full_state: full_state,
       allow_sync_retry: params.fetch(:allow_sync_retry, nil)
end

#login_with_token(username, token, sync_timeout: 15, full_state: false, **params) ⇒ Object

Raises:

  • (ArgumentError)


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/matrix_sdk/client.rb', line 178

def (username, token, sync_timeout: 15, full_state: false, **params)
  username = username.to_s unless username.is_a?(String)
  token = token.to_s unless token.is_a?(String)

  raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
  raise ArgumentError, "Token can't be nil or empty" if token.nil? || token.empty?

  data = api.(user: username, token: token, type: 'm.login.token')
  post_authentication(data)

  return if params[:no_sync]

  sync timeout: sync_timeout,
       full_state: full_state,
       allow_sync_retry: params.fetch(:allow_sync_retry, nil)
end

#logoutObject



195
196
197
198
199
# File 'lib/matrix_sdk/client.rb', line 195

def logout
  api.logout
  @api.access_token = nil
  @mxid = nil
end

#mxidObject Also known as: user_id



78
79
80
81
82
# File 'lib/matrix_sdk/client.rb', line 78

def mxid
  @mxid ||= begin
    api.whoami?[:user_id] if api&.access_token
  end
end

#mxid=(id) ⇒ Object Also known as: user_id=

Raises:

  • (ArgumentError)


84
85
86
87
88
89
# File 'lib/matrix_sdk/client.rb', line 84

def mxid=(id)
  id = MXID.new id.to_s unless id.is_a? MXID
  raise ArgumentError, 'Must be a User ID' unless id.user?

  @mxid = id
end

#public_roomsObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/matrix_sdk/client.rb', line 94

def public_rooms
  rooms = []
  since = nil
  loop do
    data = api.get_public_rooms since: since

    data[:chunk].each do |chunk|
      rooms << Room.new(self, chunk[:room_id],
                        name: chunk[:name], topic: chunk[:topic], aliases: chunk[:aliases],
                        canonical_alias: chunk[:canonical_alias], avatar_url: chunk[:avatar_url],
                        join_rule: :public, world_readable: chunk[:world_readable]).tap do |r|
        r.instance_variable_set :@guest_access, chunk[:guest_can_join] ? :can_join : :forbidden
      end
    end

    break if data[:next_batch].nil?

    since = data.next_batch
  end

  rooms
end

#register_as_guestObject



140
141
142
143
# File 'lib/matrix_sdk/client.rb', line 140

def register_as_guest
  data = api.register(kind: :guest)
  post_authentication(data)
end

#register_with_password(username, password, full_state: true, **params) ⇒ Object

Raises:

  • (ArgumentError)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/matrix_sdk/client.rb', line 145

def register_with_password(username, password, full_state: true, **params)
  username = username.to_s unless username.is_a?(String)
  password = password.to_s unless password.is_a?(String)

  raise ArgumentError, "Username can't be nil or empty" if username.nil? || username.empty?
  raise ArgumentError, "Password can't be nil or empty" if password.nil? || username.empty?

  data = api.register(auth: { type: 'm.login.dummy' }, username: username, password: password)
  post_authentication(data)

  return if params[:no_sync]

  sync full_state: full_state,
       allow_sync_retry: params.fetch(:allow_sync_retry, nil)
end

#reload_rooms!Object Also known as: refresh_rooms!



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/matrix_sdk/client.rb', line 127

def reload_rooms!
  return true if cache == :none

  @rooms.clear
  api.get_joined_rooms.joined_rooms.each do |id|
    r = ensure_room(id)
    r.reload!
  end

  true
end

#remove_room_alias(room_alias) ⇒ Object



235
236
237
# File 'lib/matrix_sdk/client.rb', line 235

def remove_room_alias(room_alias)
  api.remove_room_alias(room_alias)
end

#roomsObject



117
118
119
120
121
122
123
124
125
# File 'lib/matrix_sdk/client.rb', line 117

def rooms
  if @rooms.empty? && cache != :none
    api.get_joined_rooms.joined_rooms.each do |id|
      ensure_room(id)
    end
  end

  @rooms.values
end

#start_listener_thread(**params) ⇒ Object



246
247
248
249
250
251
# File 'lib/matrix_sdk/client.rb', line 246

def start_listener_thread(**params)
  @should_listen = true
  thread = Thread.new { listen_forever(params) }
  @sync_thread = thread
  thread.run
end

#stop_listener_threadObject



253
254
255
256
257
258
259
# File 'lib/matrix_sdk/client.rb', line 253

def stop_listener_thread
  return unless @sync_thread

  @should_listen = false
  @sync_thread.join if @sync_thread.alive?
  @sync_thread = nil
end

#sync(skip_store_batch: false, **params) ⇒ Object Also known as: listen_for_events



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/matrix_sdk/client.rb', line 265

def sync(skip_store_batch: false, **params)
  extra_params = {
    filter: sync_filter,
    timeout: 30
  }
  extra_params[:since] = @next_batch unless @next_batch.nil?
  extra_params.merge!(params)
  extra_params[:filter] = extra_params[:filter].to_json unless extra_params[:filter].is_a? String

  attempts = 0
  data = loop do
    begin
      break api.sync extra_params
    rescue MatrixSdk::MatrixTimeoutError => e
      raise e if (attempts += 1) >= params.fetch(:allow_sync_retry, 0)
    end
  end

  @next_batch = data[:next_batch] unless skip_store_batch

  handle_sync_response(data)
end

#upload(content, content_type) ⇒ Object



239
240
241
242
243
244
# File 'lib/matrix_sdk/client.rb', line 239

def upload(content, content_type)
  data = api.media_upload(content, content_type)
  return data[:content_uri] if data.key? :content_uri

  raise MatrixUnexpectedResponseError, 'Upload succeeded, but no media URI returned'
end