matrix_sdk 2.5.0 → 2.8.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.
@@ -31,12 +31,11 @@ module MatrixSdk
31
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
37
35
 
38
- # Much simpler to look up, and lighter data-wise, so the cache is wider
39
- cached :canonical_alias, :name, :avatar_url, :topic, :guest_access, :join_rule, :power_levels, cache_level: :some, expires_in: 15 * 60
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
40
39
 
41
40
  alias room_id id
42
41
  alias members joined_members
@@ -82,6 +81,12 @@ module MatrixSdk
82
81
 
83
82
  @prev_batch = nil
84
83
 
84
+ %i[name topic canonical_alias avatar_url].each do |type|
85
+ room_state.tinycache_adapter.write("m.room.#{type}", { type => data.delete(type) }) if data.key? type
86
+ end
87
+ room_state.tinycache_adapter.write('m.room.join_rules', { join_rule: data.delete(:join_rule) }) if data.key? :join_rule
88
+ room_state.tinycache_adapter.write('m.room.history_visibility', { history_visibility: data.delete(:world_readable) ? :world_readable : nil }) if data.key? :world_readable
89
+
85
90
  data.each do |k, v|
86
91
  next if %i[client].include? k
87
92
 
@@ -125,6 +130,12 @@ module MatrixSdk
125
130
  ensure_room_handlers[:event]
126
131
  end
127
132
 
133
+ # @!attribute [r] on_account_data
134
+ # @return [EventHandlerArray] The list of event handlers for account data changes
135
+ def on_account_data
136
+ ensure_room_handlers[:account_data]
137
+ end
138
+
128
139
  # @!attribute [r] on_state_event
129
140
  # @return [EventHandlerArray] The list of event handlers for only state events
130
141
  def on_state_event
@@ -167,7 +178,7 @@ module MatrixSdk
167
178
 
168
179
  # @return [String, nil] the canonical alias of the room
169
180
  def canonical_alias
170
- client.api.get_room_state(id, 'm.room.canonical_alias')[:alias]
181
+ get_state('m.room.canonical_alias')[:alias]
171
182
  rescue MatrixSdk::MatrixNotFoundError
172
183
  nil
173
184
  end
@@ -200,17 +211,43 @@ module MatrixSdk
200
211
  #
201
212
  # @return [String,nil] The room name - if any
202
213
  def name
203
- client.api.get_room_name(id)[:name]
214
+ get_state('m.room.name')[:name]
204
215
  rescue MatrixNotFoundError
205
216
  # No room name has been specified
206
217
  nil
207
218
  end
208
219
 
220
+ # Checks if the room is a direct message / 1:1 room
221
+ #
222
+ # @param members_only [Boolean] Should directness only care about member count?
223
+ # @return [Boolean]
224
+ def dm?(members_only: false)
225
+ return true if !members_only && client.direct_rooms.any? { |_uid, rooms| rooms.include? id.to_s }
226
+
227
+ joined_members.count <= 2
228
+ end
229
+
230
+ # Mark a room as a direct (1:1) message Room
231
+ def dm=(direct)
232
+ rooms = client.direct_rooms
233
+ dirty = false
234
+ list_for_room = (rooms[id.to_s] ||= [])
235
+ if direct && !list_for_room.include?(id.to_s)
236
+ list_for_room << id.to_s
237
+ dirty = true
238
+ elsif !direct && list_for_room.include?(id.to_s)
239
+ list_for_room.delete id.to_s
240
+ rooms.delete id.to_s if list_for_room.empty?
241
+ dirty = true
242
+ end
243
+ client.account_data['m.direct'] = rooms if dirty
244
+ end
245
+
209
246
  # Gets the avatar url of the room - if any
210
247
  #
211
248
  # @return [String,nil] The avatar URL - if any
212
249
  def avatar_url
213
- client.api.get_room_avatar(id)[:url]
250
+ get_state('m.room.avatar_url')[:url]
214
251
  rescue MatrixNotFoundError
215
252
  # No avatar has been set
216
253
  nil
@@ -220,7 +257,7 @@ module MatrixSdk
220
257
  #
221
258
  # @return [String,nil] The topic of the room
222
259
  def topic
223
- client.api.get_room_topic(id)[:topic]
260
+ get_state('m.room.topic')[:topic]
224
261
  rescue MatrixNotFoundError
225
262
  # No room name has been specified
226
263
  nil
@@ -230,14 +267,14 @@ module MatrixSdk
230
267
  #
231
268
  # @return [:can_join,:forbidden] The current guest access right
232
269
  def guest_access
233
- client.api.get_room_guest_access(id)[:guest_access]&.to_sym
270
+ get_state('m.room.guest_access')[:guest_access]&.to_sym
234
271
  end
235
272
 
236
273
  # Gets the join rule for the room
237
274
  #
238
275
  # @return [:public,:knock,:invite,:private] The current join rule
239
276
  def join_rule
240
- client.api.get_room_join_rules(id)[:join_rule]&.to_sym
277
+ get_state('m.room.join_rules')[:join_rule]&.to_sym
241
278
  end
242
279
 
243
280
  # Checks if +guest_access+ is set to +:can_join+
@@ -255,11 +292,27 @@ module MatrixSdk
255
292
  join_rule == :knock
256
293
  end
257
294
 
295
+ def room_state
296
+ return MatrixSdk::Util::StateEventCache.new self if client.cache == :none
297
+
298
+ @room_state ||= MatrixSdk::Util::StateEventCache.new self
299
+ end
300
+
301
+ # Gets a state object in the room
302
+ def get_state(type, state_key: nil)
303
+ room_state[type, state_key]
304
+ end
305
+
306
+ # Sets a state object in the room
307
+ def set_state(type, data, state_key: nil)
308
+ room_state[type, state_key] = data
309
+ end
310
+
258
311
  # Gets the history visibility of the room
259
312
  #
260
313
  # @return [:invited,:joined,:shared,:world_readable] The current history visibility for the room
261
314
  def history_visibility
262
- client.api.get_room_state(id, 'm.room.history_visibility')[:history_visibility]&.to_sym
315
+ get_state('m.room.history_visibility')[:history_visibility]&.to_sym
263
316
  end
264
317
 
265
318
  # Checks if the room history is world readable
@@ -272,15 +325,14 @@ module MatrixSdk
272
325
 
273
326
  # Gets the room aliases
274
327
  #
328
+ # @param canonical_only [Boolean] Should the list of aliases only contain the canonical ones
275
329
  # @return [Array[String]] The assigned room aliases
276
- def aliases
277
- client.api.get_room_aliases(id).aliases
278
- rescue MatrixNotFoundError
279
- data = client.api.get_room_state_all(id)
280
- data.select { |chunk| chunk[:type] == 'm.room.aliases' && !chunk.dig(*%i[content aliases]).nil? }
281
- .map { |chunk| chunk.dig(*%i[content aliases]) }
282
- .flatten
283
- .compact
330
+ def aliases(canonical_only: true)
331
+ canonical = get_state('m.room.canonical_alias') rescue {}
332
+ aliases = ([canonical[:alias]].compact + (canonical[:alt_aliases] || [])).uniq.sort
333
+ return aliases if canonical_only
334
+
335
+ (aliases + client.api.get_room_aliases(id).aliases).uniq.sort
284
336
  end
285
337
 
286
338
  #
@@ -399,6 +451,31 @@ module MatrixSdk
399
451
  client.api.send_content(id, url, name, 'm.audio', extra_information: audio_info)
400
452
  end
401
453
 
454
+ # Sends a customized message to the Room
455
+ #
456
+ # @param body [String] The clear-text body of the message
457
+ # @param content [Hash] The custom content of the message
458
+ # @param msgtype [String] The type of the message, should be one of the known types (m.text, m.notice, m.emote, etc)
459
+ def send_custom_message(body, content = {}, msgtype: nil)
460
+ content.merge!(
461
+ body: body,
462
+ msgtype: msgtype || 'm.text'
463
+ )
464
+
465
+ client.api.send_message_event(id, 'm.room.message', content)
466
+ end
467
+
468
+ # Sends a custom timeline event to the Room
469
+ #
470
+ # @param type [String,Symbol] The type of the Event.
471
+ # For custom events, this should be written in reverse DNS format (e.g. com.example.event)
472
+ # @param content [Hash] The contents of the message, this will be the
473
+ # :content key of the resulting event object
474
+ # @see Protocols::CS#send_message_event
475
+ def send_event(type, content = {})
476
+ client.api.send_message_event(id, type, content)
477
+ end
478
+
402
479
  # Redacts a message from the room
403
480
  #
404
481
  # @param event_id [String] the ID of the event to redact
@@ -495,12 +572,18 @@ module MatrixSdk
495
572
  true
496
573
  end
497
574
 
575
+ def account_data
576
+ return MatrixSdk::Util::AccountDataCache.new client, room: self if client.cache == :none
577
+
578
+ @account_data ||= MatrixSdk::Util::AccountDataCache.new client, room: self
579
+ end
580
+
498
581
  # Retrieves a custom entry from the room-specific account data
499
582
  #
500
583
  # @param type [String] the data type to retrieve
501
584
  # @return [Hash] the data that was stored under the given type
502
585
  def get_account_data(type)
503
- client.api.get_room_account_data(client.mxid, id, type)
586
+ account_data[type]
504
587
  end
505
588
 
506
589
  # Stores a custom entry into the room-specific account data
@@ -508,7 +591,7 @@ module MatrixSdk
508
591
  # @param type [String] the data type to store
509
592
  # @param account_data [Hash] the data to store
510
593
  def set_account_data(type, account_data)
511
- client.api.set_room_account_data(client.mxid, id, type, account_data)
594
+ self.account_data[type] = account_data
512
595
  true
513
596
  end
514
597
 
@@ -534,8 +617,7 @@ module MatrixSdk
534
617
  #
535
618
  # @return [Response] The content of the m.room.create event
536
619
  def creation_info
537
- # Not caching here, easier to cache the important values separately instead
538
- client.api.get_room_creation_info(id)
620
+ room_state['m.room.create']
539
621
  end
540
622
 
541
623
  # Retrieves the type of the room
@@ -543,9 +625,6 @@ module MatrixSdk
543
625
  # @return ['m.space',String,nil] The type of the room
544
626
  def room_type
545
627
  # Can't change, so a permanent cache is ok
546
- return @room_type if @room_type_retrieved || @room_type
547
-
548
- @room_type_retrieved = true
549
628
  @room_type ||= creation_info[:type]
550
629
  end
551
630
 
@@ -553,6 +632,7 @@ module MatrixSdk
553
632
  #
554
633
  # @return [String] The version of the room
555
634
  def room_version
635
+ # Can't change, so a permanent cache is ok
556
636
  @room_version ||= creation_info[:room_version]
557
637
  end
558
638
 
@@ -627,8 +707,7 @@ module MatrixSdk
627
707
  #
628
708
  # @param name [String] The new name to set
629
709
  def name=(name)
630
- tinycache_adapter.write(:name, name)
631
- client.api.set_room_name(id, name)
710
+ room_state['m.room.name'] = { name: name }
632
711
  name
633
712
  end
634
713
 
@@ -636,7 +715,7 @@ module MatrixSdk
636
715
  #
637
716
  # @return [Boolean] if the name was changed or not
638
717
  def reload_name!
639
- clear_name_cache
718
+ room_state.expire('m.room.name')
640
719
  end
641
720
  alias refresh_name! reload_name!
642
721
 
@@ -644,8 +723,7 @@ module MatrixSdk
644
723
  #
645
724
  # @param topic [String] The new topic to set
646
725
  def topic=(topic)
647
- tinycache_adapter.write(:topic, topic)
648
- client.api.set_room_topic(id, topic)
726
+ room_state['m.room.topic'] = { topic: topic }
649
727
  topic
650
728
  end
651
729
 
@@ -653,7 +731,7 @@ module MatrixSdk
653
731
  #
654
732
  # @return [Boolean] if the topic was changed or not
655
733
  def reload_topic!
656
- clear_topic_cache
734
+ room_state.expire('m.room.topic')
657
735
  end
658
736
  alias refresh_topic! reload_topic!
659
737
 
@@ -672,6 +750,7 @@ module MatrixSdk
672
750
  # @note The list of aliases is not sorted, ordering changes will result in
673
751
  # alias list updates.
674
752
  def reload_aliases!
753
+ room_state.expire('m.room.canonical_alias')
675
754
  clear_aliases_cache
676
755
  end
677
756
  alias refresh_aliases! reload_aliases!
@@ -688,8 +767,7 @@ module MatrixSdk
688
767
  #
689
768
  # @param join_rule [:invite,:public] The join rule of the room
690
769
  def join_rule=(join_rule)
691
- client.api.set_room_join_rules(id, join_rule)
692
- tinycache_adapter.write(:join_rule, join_rule)
770
+ room_state['m.room.join_rules'] = { join_rule: join_rule }
693
771
  join_rule
694
772
  end
695
773
 
@@ -705,8 +783,7 @@ module MatrixSdk
705
783
  #
706
784
  # @param guest_access [:can_join,:forbidden] The new guest access status of the room
707
785
  def guest_access=(guest_access)
708
- client.api.set_room_guest_access(id, guest_access)
709
- tinycache_adapter.write(:guest_access, guest_access)
786
+ room_state['m.room.guest_access'] = { guest_access: guest_access }
710
787
  guest_access
711
788
  end
712
789
 
@@ -717,8 +794,7 @@ module MatrixSdk
717
794
  avatar_url = URI(avatar_url) unless avatar_url.is_a? URI
718
795
  raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MXC
719
796
 
720
- client.api.set_room_avatar(id, avatar_url)
721
- tinycache_adapter.write(:avatar_url, avatar_url)
797
+ room_state['m.room.avatar_url'] = { avatar_url: avatar_url }
722
798
  avatar_url
723
799
  end
724
800
 
@@ -728,7 +804,7 @@ module MatrixSdk
728
804
  # @return [Hash] The current power levels as set for the room
729
805
  # @see Protocols::CS#get_power_levels
730
806
  def power_levels
731
- client.api.get_power_levels(id)
807
+ get_state('m.room.power_levels')
732
808
  end
733
809
 
734
810
  # Gets the power level of a user in the room
@@ -740,13 +816,27 @@ module MatrixSdk
740
816
  def user_powerlevel(user, use_default: true)
741
817
  user = user.id if user.is_a? User
742
818
  user = MXID.new(user.to_s) unless user.is_a? MXID
743
- raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
819
+ raise ArgumentError, 'Must provide a valid User or MXID' unless user.user?
744
820
 
745
821
  level = power_levels.dig(:users, user.to_s.to_sym)
746
- level = power_levels[:users_default] || 0 if level.nil? && use_default
822
+ level ||= power_levels[:users_default] || 0 if use_default
747
823
  level
748
824
  end
749
825
 
826
+ # Checks if a user can send a given event type in the room
827
+ #
828
+ # @param user [User,MXID,String] The user to check
829
+ # @param event [String,Symbol] The event type to check
830
+ # @param state [Boolean] If the given event is a state event or a message event
831
+ # @return [Boolean] If the given user is allowed to send an event of the given type
832
+ def user_can_send?(user, event, state: false)
833
+ user_pl = user_powerlevel(user)
834
+ event_pl = power_levels.dig(:events, event.to_s.to_sym)
835
+ event_pl ||= state ? (power_levels[:state_default] || 50) : (power_levels[:events_default] || 0)
836
+
837
+ user_pl >= event_pl
838
+ end
839
+
750
840
  # Check if a user is an admin in the room
751
841
  #
752
842
  # @param user [User,MXID,String] The user to check for admin privileges
@@ -811,8 +901,9 @@ module MatrixSdk
811
901
  def modify_user_power_levels(users = nil, users_default = nil)
812
902
  return false if users.nil? && users_default.nil?
813
903
 
814
- data = power_levels_without_cache
815
- tinycache_adapter.write(:power_levels, data)
904
+ room_state.tinycache_adapter.expire 'm.room.power_levels'
905
+
906
+ data = power_levels
816
907
  data[:users_default] = users_default unless users_default.nil?
817
908
 
818
909
  if users
@@ -830,7 +921,7 @@ module MatrixSdk
830
921
  end
831
922
  end
832
923
 
833
- client.api.set_power_levels(id, data)
924
+ room_state['m.room.power_levels'] = data
834
925
  true
835
926
  end
836
927
 
@@ -842,8 +933,9 @@ module MatrixSdk
842
933
  def modify_required_power_levels(events = nil, params = {})
843
934
  return false if events.nil? && (params.nil? || params.empty?)
844
935
 
845
- data = power_levels_without_cache
846
- tinycache_adapter.write(:power_levels, data)
936
+ room_state.tinycache_adapter.expire 'm.room.power_levels'
937
+
938
+ data = power_levels
847
939
  data.merge!(params)
848
940
  data.delete_if { |_k, v| v.nil? }
849
941
 
@@ -853,37 +945,21 @@ module MatrixSdk
853
945
  data[:events].delete_if { |_k, v| v.nil? }
854
946
  end
855
947
 
856
- client.api.set_power_levels(id, data)
948
+ room_state['m.room.power_levels'] = data
857
949
  true
858
950
  end
859
951
 
860
952
  private
861
953
 
862
954
  def ensure_member(member)
955
+ return unless client.cache == :all
956
+
863
957
  tinycache_adapter.write(:joined_members, []) unless tinycache_adapter.exist? :joined_members
864
958
 
865
959
  members = tinycache_adapter.read(:joined_members) || []
866
960
  members << member unless members.any? { |m| m.id == member.id }
867
- end
868
961
 
869
- def handle_power_levels(event)
870
- tinycache_adapter.write(:power_levels, event[:content])
871
- end
872
-
873
- def handle_room_name(event)
874
- tinycache_adapter.write(:name, event.dig(*%i[content name]))
875
- end
876
-
877
- def handle_room_topic(event)
878
- tinycache_adapter.write(:topic, event.dig(*%i[content topic]))
879
- end
880
-
881
- def handle_room_guest_access(event)
882
- tinycache_adapter.write(:guest_access, event.dig(*%i[content guest_access])&.to_sym)
883
- end
884
-
885
- def handle_room_join_rules(event)
886
- tinycache_adapter.write(:join_rule, event.dig(*%i[content join_rule])&.to_sym)
962
+ tinycache_adapter.write(:joined_members, members)
887
963
  end
888
964
 
889
965
  def handle_room_member(event)
@@ -900,20 +976,13 @@ module MatrixSdk
900
976
  end
901
977
 
902
978
  def handle_room_canonical_alias(event)
903
- canonical_alias = tinycache_adapter.write(:canonical_alias, event.dig(*%i[content alias]))
979
+ room_state.tinycache_adapter.write('m.room.canonical_alias', event[:content], expires_in: room_state.cache_time)
980
+ canonical_alias = event.dig(*%i[content alias])
904
981
 
905
982
  data = tinycache_adapter.read(:aliases) || []
906
983
  data << canonical_alias
907
- tinycache_adapter.write(:aliases, data)
908
- end
909
-
910
- def handle_room_aliases(event)
911
- tinycache_adapter.write(:aliases, []) unless tinycache_adapter.exist? :aliases
912
-
913
- aliases = tinycache_adapter.read(:aliases) || []
914
- aliases.concat(event.dig(*%i[content aliases]))
915
-
916
- tinycache_adapter.write(:aliases, aliases)
984
+ data += event.dig(*%i[content alt_aliases]) || []
985
+ tinycache_adapter.write(:aliases, data.uniq.sort)
917
986
  end
918
987
 
919
988
  def room_handlers?
@@ -922,22 +991,13 @@ module MatrixSdk
922
991
 
923
992
  def ensure_room_handlers
924
993
  client.instance_variable_get(:@room_handlers)[id] ||= {
994
+ account_data: MatrixSdk::EventHandlerArray.new,
925
995
  event: MatrixSdk::EventHandlerArray.new,
926
996
  state_event: MatrixSdk::EventHandlerArray.new,
927
997
  ephemeral_event: MatrixSdk::EventHandlerArray.new
928
998
  }
929
999
  end
930
1000
 
931
- INTERNAL_HANDLERS = {
932
- 'm.room.aliases' => :handle_room_aliases,
933
- 'm.room.canonical_alias' => :handle_room_canonical_alias,
934
- 'm.room.guest_access' => :handle_room_guest_access,
935
- 'm.room.join_rules' => :handle_room_join_rules,
936
- 'm.room.member' => :handle_room_member,
937
- 'm.room.name' => :handle_room_name,
938
- 'm.room.power_levels' => :handle_power_levels,
939
- 'm.room.topic' => :handle_room_topic
940
- }.freeze
941
1001
  def put_event(event)
942
1002
  ensure_room_handlers[:event].fire(MatrixEvent.new(self, event), event[:type]) if room_handlers?
943
1003
 
@@ -945,14 +1005,37 @@ module MatrixSdk
945
1005
  @events.shift if @events.length > @event_history_limit
946
1006
  end
947
1007
 
1008
+ def put_account_data(event)
1009
+ if client.cache != :none
1010
+ adapter = account_data.tinycache_adapter
1011
+ adapter.write(event[:type], event[:content], expires_in: account_data.cache_time)
1012
+ end
1013
+
1014
+ return unless room_handlers?
1015
+
1016
+ ensure_room_handlers[:account_data].fire(MatrixEvent.new(self, event))
1017
+ end
1018
+
948
1019
  def put_ephemeral_event(event)
949
1020
  return unless room_handlers?
950
1021
 
951
1022
  ensure_room_handlers[:ephemeral_event].fire(MatrixEvent.new(self, event), event[:type])
952
1023
  end
953
1024
 
1025
+ INTERNAL_HANDLERS = {
1026
+ 'm.room.canonical_alias' => :handle_room_canonical_alias,
1027
+ 'm.room.member' => :handle_room_member
1028
+ }.freeze
1029
+
954
1030
  def put_state_event(event)
955
- send(INTERNAL_HANDLERS[event[:type]], event) if INTERNAL_HANDLERS.key? event[:type]
1031
+ if INTERNAL_HANDLERS.key? event[:type]
1032
+ send(INTERNAL_HANDLERS[event[:type]], event)
1033
+ elsif client.cache != :none
1034
+ adapter = room_state.tinycache_adapter
1035
+ key = event[:type]
1036
+ key += "|#{event[:state_key]}" unless event[:state_key].nil? || event[:state_key].empty?
1037
+ adapter.write(key, event[:content], expires_in: room_state.cache_time)
1038
+ end
956
1039
 
957
1040
  return unless room_handlers?
958
1041
 
@@ -6,12 +6,12 @@ module MatrixSdk::Rooms
6
6
 
7
7
  def tree(suggested_only: nil, max_rooms: nil)
8
8
  begin
9
- data = client.api.request :get, :client_unstable, "/org.matrix.msc2946/rooms/#{id}/spaces", query: {
9
+ data = client.api.request :get, :client_r0, "/rooms/#{id}/spaces", query: {
10
10
  suggested_only: suggested_only,
11
11
  max_rooms_per_space: max_rooms
12
12
  }.compact
13
13
  rescue MatrixRequestError
14
- data = client.api.request :get, :client_r0, "/rooms/#{id}/spaces", query: {
14
+ data = client.api.request :get, :client_unstable, "/org.matrix.msc2946/rooms/#{id}/spaces", query: {
15
15
  suggested_only: suggested_only,
16
16
  max_rooms_per_space: max_rooms
17
17
  }.compact
@@ -28,6 +28,12 @@ module MatrixSdk
28
28
  end
29
29
  end
30
30
 
31
+ def to_s
32
+ "#{display_name} (#{id})" if @display_name
33
+
34
+ @id.to_s
35
+ end
36
+
31
37
  # @return [String] the display name
32
38
  # @see MatrixSdk::Protocols::CS#get_display_name
33
39
  def display_name
@@ -68,6 +74,22 @@ module MatrixSdk
68
74
  @avatar_url = url
69
75
  end
70
76
 
77
+ # Check if the user is an admin in a given room
78
+ #
79
+ # @param room [String,MXID] the room to check
80
+ # @return [Boolean] If the user is an admin (PL >= 100)
81
+ def admin?(room)
82
+ client.ensure_room(room).user_powerlevel(self) >= 100
83
+ end
84
+
85
+ # Check if the user is a moderator in a given room
86
+ #
87
+ # @param room [String,MXID] the room to check
88
+ # @return [Boolean] If the user is an admin (PL >= 50)
89
+ def moderator?(room)
90
+ client.ensure_room(room).user_powerlevel(self) >= 50
91
+ end
92
+
71
93
  # Get the user's current presence status
72
94
  #
73
95
  # @return [Symbol] One of :online, :offline, :unavailable
@@ -132,7 +154,7 @@ module MatrixSdk
132
154
 
133
155
  # Returns all the current device keys for the user, retrieving them if necessary
134
156
  def device_keys
135
- @device_keys ||= client.api.keys_query(device_keys: { id => [] }).yield_self do |resp|
157
+ @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
158
  resp.dig(:device_keys, id.to_sym)
137
159
  end
138
160
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MatrixSdk::Util
4
+ class AccountDataCache
5
+ extend MatrixSdk::Extensions
6
+ extend MatrixSdk::Util::Tinycache
7
+ include Enumerable
8
+
9
+ attr_reader :client, :room
10
+
11
+ attr_accessor :cache_time
12
+
13
+ ignore_inspect :client, :room, :tinycache_adapter
14
+
15
+ def initialize(client, room: nil, cache_time: 1 * 60 * 60, **_params)
16
+ raise ArgumentError, 'Must be given a Client instance' unless client.is_a? MatrixSdk::Client
17
+
18
+ @client = client
19
+ @cache_time = cache_time
20
+
21
+ return unless room
22
+
23
+ @room = room
24
+ @room = client.ensure_room room unless @room.is_a? MatrixSdk::Room
25
+ end
26
+
27
+ def reload!
28
+ tinycache_adapter.clear
29
+ end
30
+
31
+ def keys
32
+ tinycache_adapter.send(:cache).keys
33
+ end
34
+
35
+ def values
36
+ keys.map { |key| tinycache_adapter.read(key) }
37
+ end
38
+
39
+ def size
40
+ keys.count
41
+ end
42
+
43
+ def key?(key)
44
+ keys.key?(key.to_s)
45
+ end
46
+
47
+ def each(live: false)
48
+ return to_enum(__method__, live: live) { keys.count } unless block_given?
49
+
50
+ keys.each do |key|
51
+ v = live ? self[key] : tinycache_adapter.read(key)
52
+ # hash = v.hash
53
+ yield key, v
54
+ # self[key] = v if hash != v.hash
55
+ end
56
+ end
57
+
58
+ def delete(key)
59
+ key = key.to_s unless key.is_a? String
60
+ if room
61
+ client.api.set_room_account_data(client.mxid, room.id, key, {})
62
+ else
63
+ client.api.set_account_data(client.mxid, key, {})
64
+ end
65
+ tinycache_adapter.delete(key)
66
+ end
67
+
68
+ def [](key)
69
+ key = key.to_s unless key.is_a? String
70
+ tinycache_adapter.fetch(key, expires_in: @cache_time) do
71
+ if room
72
+ client.api.get_room_account_data(client.mxid, room.id, key)
73
+ else
74
+ client.api.get_account_data(client.mxid, key)
75
+ end
76
+ rescue MatrixSdk::MatrixNotFoundError
77
+ {}
78
+ end
79
+ end
80
+
81
+ def []=(key, value)
82
+ key = key.to_s unless key.is_a? String
83
+ if room
84
+ client.api.set_room_account_data(client.mxid, room.id, key, value)
85
+ else
86
+ client.api.set_account_data(client.mxid, key, value)
87
+ end
88
+ tinycache_adapter.write(key, value)
89
+ end
90
+ end
91
+ end