matrix_sdk 2.3.0 → 2.6.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.
@@ -60,7 +60,9 @@ module MatrixSdk::Protocols::MSC
60
60
  # rubocop:disable Metrics/BlockLength
61
61
  thread = Thread.new(cancellation_token) do |ctx|
62
62
  print_http(req)
63
+ @http_lock&.lock
63
64
  http.request req do |response|
65
+ @http_lock&.unlock
64
66
  break unless ctx[:run]
65
67
 
66
68
  print_http(response, body: false)
@@ -134,8 +136,11 @@ module MatrixSdk::Protocols::MSC
134
136
  break
135
137
  end
136
138
  end
139
+
137
140
  break unless ctx[:run]
138
141
  end
142
+ ensure
143
+ @http_lock.unlock if @http_lock&.owned?
139
144
  end
140
145
  # rubocop:enable Metrics/BlockLength
141
146
 
@@ -28,12 +28,14 @@ module MatrixSdk
28
28
  # An inspect method that skips a handful of instance variables to avoid
29
29
  # flooding the terminal with debug data.
30
30
  # @return [String] a regular inspect string without the data for some variables
31
- ignore_inspect :client, :events, :prev_batch, :logger
31
+ ignore_inspect :client, :events, :prev_batch, :logger, :tinycache_adapter
32
32
 
33
33
  # Requires heavy lookups, so they're cached for an hour
34
- cached :joined_members, :aliases, cache_level: :all, expires_in: 60 * 60
35
- # Only cache unfiltered requests for all members
36
- cached :all_members, unless: proc { |args| args.any? }, cache_level: :all, expires_in: 3600
34
+ cached :joined_members, cache_level: :all, expires_in: 60 * 60
35
+
36
+ # Only cache unfiltered requests for aliases and members
37
+ cached :aliases, unless: proc { |args| args.any? }, cache_level: :all, expires_in: 60 * 60
38
+ cached :all_members, unless: proc { |args| args.any? }, cache_level: :all, expires_in: 60 * 60
37
39
 
38
40
  # Much simpler to look up, and lighter data-wise, so the cache is wider
39
41
  cached :canonical_alias, :name, :avatar_url, :topic, :guest_access, :join_rule, :power_levels, cache_level: :some, expires_in: 15 * 60
@@ -53,7 +55,7 @@ module MatrixSdk
53
55
  # @option data [String] :topic The current topic of the room
54
56
  # @option data [String,MXID] :canonical_alias The canonical alias of the room
55
57
  # @option data [Array(String,MXID)] :aliases All non-canonical aliases of the room
56
- # @option data [:invite,:public] :join_rule The join rule for the room
58
+ # @option data [:invite,:public,:knock] :join_rule The join rule for the room
57
59
  # @option data [:can_join,:forbidden] :guest_access The guest access setting for the room
58
60
  # @option data [Boolean] :world_readable If the room is readable by the entire world
59
61
  # @option data [Array(User)] :members The list of joined members
@@ -63,6 +65,13 @@ module MatrixSdk
63
65
  # @option data [String,URI] :avatar_url The avatar URL for the room
64
66
  # @option data [String] :prev_batch The previous batch token for backfill
65
67
  def initialize(client, room_id, data = {})
68
+ if client.is_a? Room
69
+ copy = client
70
+ client = copy.client
71
+ room_id = copy.id
72
+ # data = copy.attributes
73
+ end
74
+
66
75
  raise ArgumentError, 'Must be given a Client instance' unless client.is_a? Client
67
76
 
68
77
  @client = client
@@ -71,6 +80,7 @@ module MatrixSdk
71
80
 
72
81
  @events = []
73
82
  @event_history_limit = 10
83
+ @room_type = nil
74
84
 
75
85
  @prev_batch = nil
76
86
 
@@ -89,6 +99,24 @@ module MatrixSdk
89
99
  logger.debug "Created room #{room_id}"
90
100
  end
91
101
 
102
+ #
103
+ # Casting operators
104
+ #
105
+
106
+ def to_space
107
+ return nil unless space?
108
+
109
+ Rooms::Space.new self, nil
110
+ end
111
+
112
+ def to_s
113
+ prefix = canonical_alias if canonical_alias_has_value?
114
+ prefix ||= id
115
+ return "#{prefix} | #{name}" if name_has_value?
116
+
117
+ prefix
118
+ end
119
+
92
120
  #
93
121
  # Event handlers
94
122
  #
@@ -204,14 +232,14 @@ module MatrixSdk
204
232
  #
205
233
  # @return [:can_join,:forbidden] The current guest access right
206
234
  def guest_access
207
- client.api.get_room_guest_access(id)[:guest_access].to_sym
235
+ client.api.get_room_guest_access(id)[:guest_access]&.to_sym
208
236
  end
209
237
 
210
238
  # Gets the join rule for the room
211
239
  #
212
240
  # @return [:public,:knock,:invite,:private] The current join rule
213
241
  def join_rule
214
- client.api.get_room_join_rules(id)[:join_rule].to_sym
242
+ client.api.get_room_join_rules(id)[:join_rule]&.to_sym
215
243
  end
216
244
 
217
245
  # Checks if +guest_access+ is set to +:can_join+
@@ -224,11 +252,16 @@ module MatrixSdk
224
252
  join_rule == :invite
225
253
  end
226
254
 
255
+ # Checks if +join_rule+ is set to +:knock+
256
+ def knock_only?
257
+ join_rule == :knock
258
+ end
259
+
227
260
  # Gets the history visibility of the room
228
261
  #
229
262
  # @return [:invited,:joined,:shared,:world_readable] The current history visibility for the room
230
263
  def history_visibility
231
- client.api.get_room_state(id, 'm.room.history_visibility')[:history_visibility].to_sym
264
+ client.api.get_room_state(id, 'm.room.history_visibility')[:history_visibility]&.to_sym
232
265
  end
233
266
 
234
267
  # Checks if the room history is world readable
@@ -241,15 +274,14 @@ module MatrixSdk
241
274
 
242
275
  # Gets the room aliases
243
276
  #
277
+ # @param canonical_only [Boolean] Should the list of aliases only contain the canonical ones
244
278
  # @return [Array[String]] The assigned room aliases
245
- def aliases
246
- client.api.get_room_aliases(id).aliases
247
- rescue MatrixNotFoundError
248
- data = client.api.get_room_state_all(id)
249
- data.select { |chunk| chunk[:type] == 'm.room.aliases' && chunk.key?(:content) && chunk[:content].key?(:aliases) }
250
- .map { |chunk| chunk[:content][:aliases] }
251
- .flatten
252
- .compact
279
+ def aliases(canonical_only: true)
280
+ canonical = client.api.get_room_state(id, 'm.room.canonical_alias') rescue {}
281
+ aliases = ([canonical[:alias]].compact + (canonical[:alt_aliases] || [])).uniq.sort
282
+ return aliases if canonical_only
283
+
284
+ (aliases + client.api.get_room_aliases(id).aliases).uniq.sort
253
285
  end
254
286
 
255
287
  #
@@ -499,6 +531,41 @@ module MatrixSdk
499
531
  true
500
532
  end
501
533
 
534
+ # Gets the room creation information
535
+ #
536
+ # @return [Response] The content of the m.room.create event
537
+ def creation_info
538
+ # Not caching here, easier to cache the important values separately instead
539
+ client.api.get_room_creation_info(id)
540
+ end
541
+
542
+ # Retrieves the type of the room
543
+ #
544
+ # @return ['m.space',String,nil] The type of the room
545
+ def room_type
546
+ # Can't change, so a permanent cache is ok
547
+ return @room_type if @room_type_retrieved || @room_type
548
+
549
+ @room_type_retrieved = true
550
+ @room_type ||= creation_info[:type]
551
+ end
552
+
553
+ # Retrieves the room version
554
+ #
555
+ # @return [String] The version of the room
556
+ def room_version
557
+ @room_version ||= creation_info[:room_version]
558
+ end
559
+
560
+ # Checks if the room is a Matrix Space
561
+ #
562
+ # @return [Boolean,nil] True if the room is a space
563
+ def space?
564
+ room_type == 'm.space'
565
+ rescue MatrixSdk::MatrixForbiddenError, MatrixSdk::MatrixNotFoundError
566
+ nil
567
+ end
568
+
502
569
  # Returns a list of the room tags
503
570
  #
504
571
  # @return [Response] A list of the tags and their data, with add and remove methods implemented
@@ -646,10 +713,10 @@ module MatrixSdk
646
713
 
647
714
  # Sets a new avatar URL for the room
648
715
  #
649
- # @param avatar_url [URI::MATRIX] The mxc:// URL for the new room avatar
716
+ # @param avatar_url [URI::MXC] The mxc:// URL for the new room avatar
650
717
  def avatar_url=(avatar_url)
651
718
  avatar_url = URI(avatar_url) unless avatar_url.is_a? URI
652
- raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MATRIX
719
+ raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MXC
653
720
 
654
721
  client.api.set_room_avatar(id, avatar_url)
655
722
  tinycache_adapter.write(:avatar_url, avatar_url)
@@ -676,7 +743,7 @@ module MatrixSdk
676
743
  user = MXID.new(user.to_s) unless user.is_a? MXID
677
744
  raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
678
745
 
679
- level = power_levels[:users][user.to_s.to_sym]
746
+ level = power_levels.dig(:users, user.to_s.to_sym)
680
747
  level = power_levels[:users_default] || 0 if level.nil? && use_default
681
748
  level
682
749
  end
@@ -751,8 +818,17 @@ module MatrixSdk
751
818
 
752
819
  if users
753
820
  data[:users] = {} unless data.key? :users
754
- data[:users].merge!(users)
755
- data[:users].delete_if { |_k, v| v.nil? }
821
+ users.each do |user, level|
822
+ user = user.id if user.is_a? User
823
+ user = MXID.new(user.to_s) unless user.is_a? MXID
824
+ raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
825
+
826
+ if level.nil?
827
+ data[:users].delete(user.to_s.to_sym)
828
+ else
829
+ data[:users][user.to_s.to_sym] = level
830
+ end
831
+ end
756
832
  end
757
833
 
758
834
  client.api.set_power_levels(id, data)
@@ -796,27 +872,27 @@ module MatrixSdk
796
872
  end
797
873
 
798
874
  def handle_room_name(event)
799
- tinycache_adapter.write(:name, event[:content][:name])
875
+ tinycache_adapter.write(:name, event.dig(*%i[content name]))
800
876
  end
801
877
 
802
878
  def handle_room_topic(event)
803
- tinycache_adapter.write(:topic, event[:content][:topic])
879
+ tinycache_adapter.write(:topic, event.dig(*%i[content topic]))
804
880
  end
805
881
 
806
882
  def handle_room_guest_access(event)
807
- tinycache_adapter.write(:guest_access, event[:content][:guest_access].to_sym)
883
+ tinycache_adapter.write(:guest_access, event.dig(*%i[content guest_access])&.to_sym)
808
884
  end
809
885
 
810
886
  def handle_room_join_rules(event)
811
- tinycache_adapter.write(:join_rule, event[:content][:join_rule].to_sym)
887
+ tinycache_adapter.write(:join_rule, event.dig(*%i[content join_rule])&.to_sym)
812
888
  end
813
889
 
814
890
  def handle_room_member(event)
815
891
  return unless client.cache == :all
816
892
 
817
- if event[:content][:membership] == 'join'
893
+ if event.dig(*%i[content membership]) == 'join'
818
894
  ensure_member(client.get_user(event[:state_key]).dup.tap do |u|
819
- u.instance_variable_set :@display_name, event[:content][:displayname]
895
+ u.instance_variable_set(:@display_name, event.dig(*%i[content displayname]))
820
896
  end)
821
897
  elsif tinycache_adapter.exist? :joined_members
822
898
  members = tinycache_adapter.read(:joined_members)
@@ -825,20 +901,12 @@ module MatrixSdk
825
901
  end
826
902
 
827
903
  def handle_room_canonical_alias(event)
828
- canonical_alias = tinycache_adapter.write :canonical_alias, event[:content][:alias]
904
+ canonical_alias = tinycache_adapter.write(:canonical_alias, event.dig(*%i[content alias]))
829
905
 
830
906
  data = tinycache_adapter.read(:aliases) || []
831
907
  data << canonical_alias
832
- tinycache_adapter.write(:aliases, data)
833
- end
834
-
835
- def handle_room_aliases(event)
836
- tinycache_adapter.write(:aliases, []) unless tinycache_adapter.exist? :aliases
837
-
838
- aliases = tinycache_adapter.read(:aliases) || []
839
- aliases.concat event[:content][:aliases]
840
-
841
- tinycache_adapter.write(:aliases, aliases)
908
+ data += event.dig(*%i[content alt_aliases]) || []
909
+ tinycache_adapter.write(:aliases, data.uniq.sort)
842
910
  end
843
911
 
844
912
  def room_handlers?
@@ -854,7 +922,6 @@ module MatrixSdk
854
922
  end
855
923
 
856
924
  INTERNAL_HANDLERS = {
857
- 'm.room.aliases' => :handle_room_aliases,
858
925
  'm.room.canonical_alias' => :handle_room_canonical_alias,
859
926
  'm.room.guest_access' => :handle_room_guest_access,
860
927
  'm.room.join_rules' => :handle_room_join_rules,
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk::Rooms
4
+ class Space < MatrixSdk::Room
5
+ TYPE = 'm.space'
6
+
7
+ def tree(suggested_only: nil, max_rooms: nil)
8
+ begin
9
+ data = client.api.request :get, :client_r0, "/rooms/#{id}/spaces", query: {
10
+ suggested_only: suggested_only,
11
+ max_rooms_per_space: max_rooms
12
+ }.compact
13
+ rescue MatrixRequestError
14
+ data = client.api.request :get, :client_unstable, "/org.matrix.msc2946/rooms/#{id}/spaces", query: {
15
+ suggested_only: suggested_only,
16
+ max_rooms_per_space: max_rooms
17
+ }.compact
18
+ end
19
+
20
+ rooms = data.rooms.map do |r|
21
+ next if r[:room_id] == id
22
+
23
+ room = client.ensure_room(r[:room_id])
24
+ room.instance_variable_set :@room_type, r[:room_type] if r.key? :room_type
25
+ room = room.to_space if room.space?
26
+
27
+ # Inject available room information
28
+ r.each do |k, v|
29
+ if room.respond_to?("#{k}_cached?".to_sym) && send("#{k}_cached?".to_sym)
30
+ room.send(:tinycache_adapter).write(k, v)
31
+ elsif room.instance_variable_defined? "@#{k}"
32
+ room.instance_variable_set("@#{k}", v)
33
+ end
34
+ end
35
+ room
36
+ end
37
+ rooms.compact!
38
+
39
+ grouping = {}
40
+ data.events.each do |ev|
41
+ next unless ev[:type] == 'm.space.child'
42
+ next unless ev[:content].key? :via
43
+
44
+ d = (grouping[ev[:room_id]] ||= [])
45
+ d << ev[:state_key]
46
+ end
47
+
48
+ build_tree = proc do |entry|
49
+ next if entry.nil?
50
+
51
+ room = self if entry == id
52
+ room ||= rooms.find { |r| r.id == entry }
53
+ puts "Unable to find room for entry #{entry}" unless room
54
+ # next if room.nil?
55
+
56
+ ret = {
57
+ room => []
58
+ }
59
+
60
+ grouping[entry]&.each do |child|
61
+ if grouping.key?(child)
62
+ ret[room] << build_tree.call(child)
63
+ else
64
+ child_r = self if child == id
65
+ child_r ||= rooms.find { |r| r.id == child }
66
+
67
+ ret[room] << child_r
68
+ end
69
+ end
70
+
71
+ ret[room].compact!
72
+
73
+ ret
74
+ end
75
+
76
+ build_tree.call(id)
77
+ end
78
+ end
79
+ end
@@ -59,7 +59,7 @@ module MatrixSdk
59
59
  # Only works for the current user object, as requested by
60
60
  # client.get_user(:self)
61
61
  #
62
- # @param url [String,URI::MATRIX] the new avatar URL
62
+ # @param url [String,URI::MXC] the new avatar URL
63
63
  # @note Requires a mxc:// URL, check example on
64
64
  # {MatrixSdk::Protocols::CS#set_avatar_url} for how this can be done
65
65
  # @see MatrixSdk::Protocols::CS#set_avatar_url
@@ -74,7 +74,7 @@ module MatrixSdk
74
74
  # @see MatrixSdk::Protocols::CS#get_presence_status
75
75
  # @note This information is not cached in the abstraction layer
76
76
  def presence
77
- raw_presence[:presence].to_sym
77
+ raw_presence[:presence]&.to_sym
78
78
  end
79
79
 
80
80
  # Sets the user's current presence status
@@ -132,8 +132,8 @@ module MatrixSdk
132
132
 
133
133
  # Returns all the current device keys for the user, retrieving them if necessary
134
134
  def device_keys
135
- @device_keys ||= client.api.keys_query(device_keys: { id => [] }).yield_self do |resp|
136
- resp[:device_keys][id.to_sym]
135
+ @device_keys ||= client.api.keys_query(device_keys: { id => [] }).yield_self do |resp| # rubocop:disable Style/ObjectThen # Keep Ruby 2.5 support a little longer
136
+ resp.dig(:device_keys, id.to_sym)
137
137
  end
138
138
  end
139
139
 
@@ -22,13 +22,11 @@ module MatrixSdk
22
22
 
23
23
  def fire(event, filter = nil)
24
24
  reverse_each do |_k, h|
25
- begin
26
- h[:block].call(event) if !h[:filter] || event.matches?(h[:filter], filter)
27
- rescue StandardError => e
28
- logger.error "#{e.class.name} occurred when firing event (#{event})\n#{e}"
25
+ h[:block].call(event) if !h[:filter] || event.matches?(h[:filter], filter)
26
+ rescue StandardError => e
27
+ logger.error "#{e.class.name} occurred when firing event (#{event})\n#{e}"
29
28
 
30
- raise e if @reraise_exceptions
31
- end
29
+ raise e if @reraise_exceptions
32
30
  end
33
31
  end
34
32
  end
@@ -1,19 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'uri'
4
-
5
- module URI
6
- # A mxc:// Matrix content URL
7
- class MATRIX < Generic
8
- def full_path
9
- select(:host, :port, :path, :query, :fragment)
10
- .reject(&:nil?)
11
- .join
12
- end
13
- end
14
-
15
- @@schemes['MXC'] = MATRIX
16
- end
3
+ require 'pp'
17
4
 
18
5
  unless Object.respond_to? :yield_self
19
6
  class Object
@@ -66,13 +53,20 @@ module MatrixSdk
66
53
 
67
54
  def ignore_inspect(*symbols)
68
55
  class_eval %*
69
- def inspect
70
- reentrant = caller_locations.any? { |l| l.absolute_path == __FILE__ && l.label == 'inspect' }
71
- "\#{to_s[0..-2]} \#{instance_variables
56
+ include PP::ObjectMixin
57
+
58
+ def pretty_print_instance_variables
59
+ instance_variables
72
60
  .reject { |f| %i[#{symbols.map { |s| "@#{s}" }.join ' '}].include? f }
73
- .map { |f| "\#{f}=\#{reentrant ? instance_variable_get(f) : instance_variable_get(f).inspect}" }.join " " }}>"
61
+ .sort
62
+ end
63
+
64
+ def pretty_print(pp)
65
+ pp.pp_object(self)
74
66
  end
75
- *, __FILE__, __LINE__ - 7
67
+
68
+ alias inspect pretty_print_inspect
69
+ *, __FILE__, __LINE__ - 14
76
70
  end
77
71
  end
78
72
 
@@ -20,7 +20,7 @@ module MatrixSdk::Util
20
20
 
21
21
  def self.extended(base)
22
22
  helper_name = base.send(:cache_helper_module_name)
23
- base.remove_const(helper_name) if base.const_defined?(helper_name)
23
+ base.send :remove_const, helper_name if base.const_defined?(helper_name)
24
24
  base.prepend base.const_set(helper_name, Module.new)
25
25
 
26
26
  base.include InstanceMethods
@@ -62,23 +62,38 @@ module MatrixSdk::Util
62
62
  method_names = build_method_names(method_name)
63
63
  tinycache_adapter_config[method_name] = {
64
64
  level: cache_level,
65
- expires: expires_in || 1 * 365 * 24 * 60 * 60 # 1 year
65
+ expires: expires_in || (1 * 365 * 24 * 60 * 60) # 1 year
66
66
  }
67
67
 
68
- const_get(cache_helper_module_name).class_eval do
68
+ helper = const_get(cache_helper_module_name)
69
+ return if method_names.any? { |k, _| helper.respond_to? k }
70
+
71
+ helper.class_eval do
69
72
  define_method(method_names[:cache_key]) do |*args|
70
73
  cache_key.call(method_name, args)
71
74
  end
72
75
 
73
76
  define_method(method_names[:with_cache]) do |*args|
74
77
  tinycache_adapter.fetch(__send__(method_names[:cache_key], *args), expires_in: expires_in) do
75
- __send__(method_names[:without_cache], *args)
78
+ named = args.delete_at(-1) if args.last.is_a? Hash
79
+
80
+ if named
81
+ __send__(method_names[:without_cache], *args, **named)
82
+ else
83
+ __send__(method_names[:without_cache], *args)
84
+ end
76
85
  end
77
86
  end
78
87
 
79
88
  define_method(method_names[:without_cache]) do |*args|
80
89
  orig = method(method_name).super_method
81
- orig.call(*args)
90
+ named = args.delete_at(-1) if args.last.is_a? Hash
91
+
92
+ if named
93
+ orig.call(*args, **named)
94
+ else
95
+ orig.call(*args)
96
+ end
82
97
  end
83
98
 
84
99
  define_method(method_names[:clear_cache]) do |*args|
@@ -89,11 +104,19 @@ module MatrixSdk::Util
89
104
  true
90
105
  end
91
106
 
107
+ define_method(method_names[:has_value]) do |*args|
108
+ tinycache_adapter.valid?(__send__(method_names[:cache_key], *args))
109
+ end
110
+
92
111
  define_method(method_name) do |*args|
93
112
  unless_proc = opts[:unless].is_a?(Symbol) ? opts[:unless].to_proc : opts[:unless]
94
113
 
114
+ raise ArgumentError, 'Invalid proc provided (must have arity between 1..3)' if unless_proc && !(1..3).include?(unless_proc.arity)
115
+
95
116
  skip_cache = false
96
- skip_cache ||= unless_proc&.call(self, method_name, args)
117
+ skip_cache ||= unless_proc.call(self, method_name, args) if unless_proc&.arity == 3
118
+ skip_cache ||= unless_proc.call(method_name, args) if unless_proc&.arity == 2
119
+ skip_cache ||= unless_proc.call(args) if unless_proc&.arity == 1
97
120
  skip_cache ||= CACHE_LEVELS[client&.cache || :all] < CACHE_LEVELS[cache_level]
98
121
 
99
122
  if skip_cache
@@ -115,7 +138,8 @@ module MatrixSdk::Util
115
138
  with_cache: "#{method_name}_with_cache#{punctuation}",
116
139
  without_cache: "#{method_name}_without_cache#{punctuation}",
117
140
  clear_cache: "clear_#{method_name}_cache#{punctuation}",
118
- cached: "#{method}_cached?"
141
+ cached: "#{method}_cached?",
142
+ has_value: "#{method}_has_value?"
119
143
  }
120
144
  end
121
145
  end
@@ -16,6 +16,7 @@ module MatrixSdk::Util
16
16
 
17
17
  def write(key, value, expires_in: nil, cache_level: nil)
18
18
  expires_in ||= config.dig(key, :expires)
19
+ expires_in ||= 24 * 60 * 60
19
20
  cache_level ||= client&.cache
20
21
  cache_level ||= :all
21
22
  cache_level = Tinycache::CACHE_LEVELS[cache_level] unless cache_level.is_a? Integer
@@ -30,6 +31,10 @@ module MatrixSdk::Util
30
31
  cache.key?(key)
31
32
  end
32
33
 
34
+ def valid?(key)
35
+ exist?(key) && !cache[key].expired?
36
+ end
37
+
33
38
  def fetch(key, expires_in: nil, cache_level: nil, **_opts)
34
39
  expires_in ||= config.dig(key, :expires)
35
40
  cache_level ||= client&.cache
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module URI
6
+ # A mxc:// Matrix content URL
7
+ class MXC < Generic
8
+ def full_path
9
+ select(:host, :port, :path, :query, :fragment)
10
+ .compact
11
+ .join
12
+ end
13
+ end
14
+
15
+ # TODO: Use +register_scheme+ on Ruby >=3.1 and fall back to old behavior
16
+ # for older Rubies. May be removed at EOL of Ruby 3.0.
17
+ if respond_to? :register_scheme
18
+ register_scheme 'MXC', MXC
19
+ else
20
+ @@schemes['MXC'] = MXC
21
+ end
22
+
23
+ unless scheme_list.key? 'MATRIX'
24
+ # A matrix: URI according to MSC2312
25
+ class MATRIX < Generic
26
+ attr_reader :authority, :action, :mxid, :mxid2, :via
27
+
28
+ def initialize(*args)
29
+ super(*args)
30
+
31
+ @action = nil
32
+ @authority = nil
33
+ @mxid = nil
34
+ @mxid2 = nil
35
+ @via = nil
36
+
37
+ raise InvalidComponentError, 'missing opaque part for matrix URL' if !@opaque && !@path
38
+
39
+ if @path
40
+ @authority = @host
41
+ @authority += ":#{@port}" if @port
42
+ else
43
+ @path, @query = @opaque.split('?')
44
+ @query, @fragment = @query.split('#') if @query&.include? '#'
45
+ @path, @fragment = @path.split('#') if @path&.include? '#'
46
+ @path = "/#{path}"
47
+ @opaque = nil
48
+ end
49
+
50
+ components = @path.delete_prefix('/').split('/', -1)
51
+ raise InvalidComponentError, 'component count must be 2 or 4' if components.size != 2 && components.size != 4
52
+
53
+ sigil = case components.shift
54
+ when 'u', 'user'
55
+ '@'
56
+ when 'r', 'room'
57
+ '#'
58
+ when 'roomid'
59
+ '!'
60
+ else
61
+ raise InvalidComponentError, 'invalid component in path'
62
+ end
63
+
64
+ component = components.shift
65
+ raise InvalidComponentError, "component can't be empty" if component.nil? || component.empty?
66
+
67
+ @mxid = MatrixSdk::MXID.new("#{sigil}#{component}")
68
+
69
+ if components.size == 2
70
+ sigil2 = case components.shift
71
+ when 'e', 'event'
72
+ '$'
73
+ else
74
+ raise InvalidComponentError, 'invalid component in path'
75
+ end
76
+ component = components.shift
77
+ raise InvalidComponentError, "component can't be empty" if component.nil? || component.empty?
78
+
79
+ @mxid2 = MatrixSdk::MXID.new("#{sigil2}#{component}")
80
+ end
81
+
82
+ return unless @query
83
+
84
+ @action = @query.match(/action=([^&]+)/)&.captures&.first&.to_sym
85
+ @via = @query.scan(/via=([^&]+)/)&.flatten&.compact
86
+ end
87
+
88
+ def mxid2?
89
+ !@mxid2.nil?
90
+ end
91
+ end
92
+
93
+ # TODO: Use +register_scheme+ on Ruby >=3.1 and fall back to old behavior
94
+ # for older Rubies. May be removed at EOL of Ruby 3.0.
95
+ if respond_to? :register_scheme
96
+ register_scheme 'MATRIX', MATRIX
97
+ else
98
+ @@schemes['MATRIX'] = MATRIX
99
+ end
100
+ end
101
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MatrixSdk
4
- VERSION = '2.3.0'
4
+ VERSION = '2.6.0'
5
5
  end