matrix_sdk 2.5.0 → 2.8.0

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