matrix_sdk 2.4.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)