matrix_sdk 2.4.0 → 2.7.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,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk::Bot
4
+ PARAMS_CONFIG = {} # rubocop:disable Style/MutableConstant Intended
5
+
6
+ require 'optparse'
7
+ parser = OptionParser.new do |op|
8
+ op.on('-s homeserver', 'Specify homeserver') { |val| PARAMS_CONFIG[:homeserver] = val }
9
+
10
+ op.on('-T token', 'Token') { |val| PARAMS_CONFIG[:access_token] = val }
11
+ op.on('-U username', 'Username') { |val| PARAMS_CONFIG[:username] = val }
12
+ op.on('-P password', 'Password') { |val| PARAMS_CONFIG[:password] = val }
13
+
14
+ op.on('-q', 'Disable logging') { PARAMS_CONFIG[:logging] = false }
15
+ op.on('-v', 'Enable verbose output') { PARAMS_CONFIG[:logging] = !(PARAMS_CONFIG[:log_level] = :debug).nil? }
16
+ end
17
+
18
+ begin
19
+ parser.parse!(ARGV.dup)
20
+ rescue StandardError => e
21
+ PARAMS_CONFIG[:optparse_error] = e
22
+ end
23
+
24
+ MatrixSdk.logger.appenders.each do |log|
25
+ log.layout = Logging::Layouts.pattern(
26
+ pattern: "%d|%.1l %c : %m\n"
27
+ )
28
+ end
29
+ MatrixSdk.debug! if ENV['MATRIX_DEBUG'] == '1'
30
+
31
+ require 'matrix_sdk/bot/base'
32
+ class Instance < Base
33
+ set :logging, true
34
+ set :log_level, :info
35
+
36
+ set :app_file, caller_files.first || $PROGRAM_NAME
37
+ set(:run) { File.expand_path($PROGRAM_NAME) == File.expand_path(app_file) }
38
+
39
+ if run? && ARGV.any?
40
+ error = PARAMS_CONFIG.delete(:optparse_error)
41
+ raise error if error
42
+
43
+ PARAMS_CONFIG.each { |k, v| set k, v }
44
+ end
45
+ end
46
+
47
+ module Delegator
48
+ def self.delegate(*methods)
49
+ methods.each do |method_name|
50
+ define_method(method_name) do |*args, &block|
51
+ return super(*args, &block) if respond_to? method_name
52
+
53
+ Delegator.target.send(method_name, *args, &block)
54
+ end
55
+ # ensure keyword argument passing is compatible with ruby >= 2.7
56
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
57
+ private method_name
58
+ end
59
+ end
60
+
61
+ delegate :command, :client, :event,
62
+ :settings,
63
+ :set, :enable, :disable
64
+
65
+ class << self
66
+ attr_accessor :target
67
+ end
68
+
69
+ self.target = Instance
70
+ end
71
+
72
+ # Trigger the global instance to run once the main class finishes
73
+ at_exit do
74
+ remove_const(:PARAMS_CONFIG)
75
+ Instance.run! if $!.nil? && Instance.run? # rubocop:disable Style/SpecialGlobalVars Don't want to require into global scope
76
+ end
77
+ end
78
+
79
+ extend MatrixSdk::Bot::Delegator # rubocop:disable Style/MixinUsage Intended
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'matrix_sdk'
4
+ require 'matrix_sdk/bot/main'
@@ -22,11 +22,11 @@ module MatrixSdk
22
22
  # @return [Hash,String] A filter definition, either as defined by the
23
23
  # Matrix spec, or as an identifier returned by a filter creation request
24
24
  attr_reader :api, :next_batch
25
- attr_accessor :cache, :sync_filter
25
+ attr_accessor :cache, :sync_filter, :sync_token
26
26
 
27
- events :error, :event, :presence_event, :invite_event, :leave_event, :ephemeral_event, :state_event
27
+ events :error, :event, :account_data, :presence_event, :invite_event, :leave_event, :ephemeral_event, :state_event
28
28
  ignore_inspect :api,
29
- :on_event, :on_presence_event, :on_invite_event, :on_leave_event, :on_ephemeral_event
29
+ :on_event, :on_account_data, :on_presence_event, :on_invite_event, :on_leave_event, :on_ephemeral_event
30
30
 
31
31
  def_delegators :@api,
32
32
  :access_token, :access_token=, :device_id, :device_id=, :homeserver, :homeserver=,
@@ -45,10 +45,10 @@ module MatrixSdk
45
45
  # @see #initialize
46
46
  def self.new_for_domain(domain, **params)
47
47
  api = MatrixSdk::Api.new_for_domain(domain, keep_wellknown: true)
48
- return new(api, params) unless api.well_known&.key?('m.identity_server')
48
+ return new(api, **params) unless api.well_known&.key?('m.identity_server')
49
49
 
50
50
  identity_server = MatrixSdk::Api.new(api.well_known['m.identity_server']['base_url'], protocols: %i[IS])
51
- new(api, params.merge(identity_server: identity_server))
51
+ new(api, **params.merge(identity_server: identity_server))
52
52
  end
53
53
 
54
54
  # @param hs_url [String,URI,Api] The URL to the Matrix homeserver, without the /_matrix/ part, or an existing Api instance
@@ -161,7 +161,14 @@ module MatrixSdk
161
161
  #
162
162
  # @return [Hash[String,Array[String]]] A mapping of MXIDs to a list of direct rooms with that user
163
163
  def direct_rooms
164
- api.get_account_data(mxid, 'm.direct').transform_keys(&:to_s)
164
+ account_data['m.direct'].transform_keys(&:to_s)
165
+ end
166
+
167
+ # Retrieve an account data helper
168
+ def account_data
169
+ return MatrixSdk::Util::AccountDataCache.new self if cache == :none
170
+
171
+ @account_data ||= MatrixSdk::Util::AccountDataCache.new self
165
172
  end
166
173
 
167
174
  # Gets a direct message room for the given user if one exists
@@ -395,15 +402,16 @@ module MatrixSdk
395
402
  # @param only_canonical [Boolean] Only match alias against the canonical alias
396
403
  # @return [Room] The found room
397
404
  # @return [nil] If no room was found
398
- def find_room(room_id_or_alias, only_canonical: false)
405
+ def find_room(room_id_or_alias, only_canonical: true)
399
406
  room_id_or_alias = MXID.new(room_id_or_alias.to_s) unless room_id_or_alias.is_a? MXID
400
407
  raise ArgumentError, 'Must be a room id or alias' unless room_id_or_alias.room?
401
408
 
402
409
  return @rooms.fetch(room_id_or_alias.to_s, nil) if room_id_or_alias.room_id?
403
410
 
404
- return @rooms.values.find { |r| r.canonical_alias == room_id_or_alias.to_s } if only_canonical
411
+ room = @rooms.values.find { |r| r.aliases.include? room_id_or_alias.to_s }
412
+ return room if only_canonical
405
413
 
406
- @rooms.values.find { |r| r.aliases.include? room_id_or_alias.to_s }
414
+ room || @rooms.values.find { |r| r.aliases(canonical_only: false).include? room_id_or_alias.to_s }
407
415
  end
408
416
 
409
417
  # Get a User instance from a MXID
@@ -497,8 +505,9 @@ module MatrixSdk
497
505
  else
498
506
  @should_listen = false
499
507
  end
508
+
500
509
  if @sync_thread.alive?
501
- ret = @sync_thread.join(2)
510
+ ret = @sync_thread.join(0.1)
502
511
  @sync_thread.kill unless ret
503
512
  end
504
513
  @sync_thread = nil
@@ -552,11 +561,14 @@ module MatrixSdk
552
561
  raise ArgumentError, 'Must be a room ID' unless room_id.room_id?
553
562
 
554
563
  room_id = room_id.to_s
555
- @rooms.fetch(room_id) do
564
+ ret = @rooms.fetch(room_id) do
556
565
  room = Room.new(self, room_id)
557
566
  @rooms[room_id] = room unless cache == :none
558
567
  room
559
568
  end
569
+ # Need to figure out a way to handle multiple types
570
+ ret = @rooms[room_id] = ret.to_space if ret.instance_variable_get :@room_type
571
+ ret
560
572
  end
561
573
 
562
574
  def listen_forever(timeout: 30, bad_sync_timeout: 5, sync_interval: 0, **params)
@@ -564,10 +576,13 @@ module MatrixSdk
564
576
  while @should_listen
565
577
  begin
566
578
  sync(**params.merge(timeout: timeout))
579
+ return unless @should_listen
567
580
 
568
581
  bad_sync_timeout = orig_bad_sync_timeout
569
582
  sleep(sync_interval) if sync_interval.positive?
570
583
  rescue MatrixRequestError => e
584
+ return unless @should_listen
585
+
571
586
  logger.warn("A #{e.class} occurred during sync")
572
587
  if e.httpstatus >= 500
573
588
  logger.warn("Serverside error, retrying in #{bad_sync_timeout} seconds...")
@@ -585,7 +600,7 @@ module MatrixSdk
585
600
  private
586
601
 
587
602
  def post_authentication(data)
588
- @mxid = data[:user_id]
603
+ @mxid = MXID.new data[:user_id]
589
604
  @api.access_token = data[:access_token]
590
605
  @api.device_id = data[:device_id]
591
606
  @api.homeserver = data[:home_server]
@@ -602,6 +617,14 @@ module MatrixSdk
602
617
  end
603
618
 
604
619
  def handle_sync_response(data)
620
+ data.dig(:account_data, :events)&.each do |account_data|
621
+ if cache != :none
622
+ adapter = self.account_data.tinycache_adapter
623
+ adapter.write(account_data[:type], account_data[:content], expires_in: self.account_data.cache_time)
624
+ end
625
+ fire_account_data(MatrixEvent.new(self, account_data))
626
+ end
627
+
605
628
  data.dig(:presence, :events)&.each do |presence_update|
606
629
  fire_presence_event(MatrixEvent.new(self, presence_update))
607
630
  end
@@ -621,6 +644,13 @@ module MatrixSdk
621
644
  room.instance_variable_set '@prev_batch', join.dig(:timeline, :prev_batch)
622
645
  room.instance_variable_set :@members_loaded, true unless sync_filter.fetch(:room, {}).fetch(:state, {}).fetch(:lazy_load_members, false)
623
646
 
647
+ join.dig(:account_data, :events)&.each do |account_data|
648
+ account_data[:room_id] = room_id.to_s
649
+ room.send :put_account_data, account_data
650
+
651
+ fire_account_data(MatrixEvent.new(self, account_data))
652
+ end
653
+
624
654
  join.dig(:state, :events)&.each do |event|
625
655
  event[:room_id] = room_id.to_s
626
656
  handle_state(room_id, event)
@@ -648,10 +678,12 @@ module MatrixSdk
648
678
  end
649
679
 
650
680
  unless cache == :none
681
+ account_data.tinycache_adapter.cleanup if instance_variable_defined?(:@account_data) && @account_data
651
682
  @rooms.each do |_id, room|
652
683
  # Clean up old cache data after every sync
653
684
  # TODO Run this in a thread?
654
685
  room.tinycache_adapter.cleanup
686
+ room.account_data.tinycache_adapter.cleanup
655
687
  end
656
688
  end
657
689
 
@@ -12,7 +12,7 @@ module MatrixSdk
12
12
 
13
13
  # TODO: Community-as-a-Room / Profile-as-a-Room, in case they're going for room aliases
14
14
  @sigil = identifier[0]
15
- @localpart, @domain, @port = identifier[1..].split(':')
15
+ @localpart, @domain, @port = identifier[1..-1].split(':') # rubocop:disable Style/SlicingWithRange # Keep support for slightly older Rubies
16
16
  @port = @port.to_i if @port
17
17
 
18
18
  raise ArgumentError, 'Identifier is not a valid MXID' unless valid?
@@ -45,6 +45,8 @@ module MatrixSdk
45
45
  "#{sigil}#{localpart}#{homeserver_suffix}"
46
46
  end
47
47
 
48
+ alias to_str to_s
49
+
48
50
  # Returns the type of the ID
49
51
  #
50
52
  # @return [Symbol] The MXID type, one of (:user_id, :room_id, :event_id, :group_id, or :room_alias)