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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +17 -2
- data/lib/matrix_sdk/api.rb +60 -18
- data/lib/matrix_sdk/bot/base.rb +843 -0
- data/lib/matrix_sdk/bot/main.rb +79 -0
- data/lib/matrix_sdk/bot.rb +4 -0
- data/lib/matrix_sdk/client.rb +44 -12
- data/lib/matrix_sdk/mxid.rb +3 -1
- data/lib/matrix_sdk/protocols/cs.rb +132 -106
- data/lib/matrix_sdk/protocols/msc.rb +5 -0
- data/lib/matrix_sdk/response.rb +2 -0
- data/lib/matrix_sdk/room.rb +140 -40
- data/lib/matrix_sdk/rooms/space.rb +3 -3
- data/lib/matrix_sdk/user.rb +25 -3
- data/lib/matrix_sdk/util/account_data_cache.rb +91 -0
- data/lib/matrix_sdk/util/extensions.rb +16 -6
- data/lib/matrix_sdk/util/tinycache.rb +20 -4
- data/lib/matrix_sdk/util/tinycache_adapter.rb +5 -1
- data/lib/matrix_sdk/util/uri.rb +16 -4
- data/lib/matrix_sdk/version.rb +1 -1
- data/lib/matrix_sdk.rb +11 -1
- metadata +7 -3
@@ -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
|
data/lib/matrix_sdk/client.rb
CHANGED
@@ -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
|
-
|
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:
|
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
|
-
|
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(
|
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
|
|
data/lib/matrix_sdk/mxid.rb
CHANGED
@@ -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
|
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)
|