matrix_sdk 2.1.2 → 2.4.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.
@@ -47,7 +47,7 @@ module MatrixSdk::Protocols::MSC
47
47
  query[:user_id] = params.delete(:user_id) if protocol?(:AS) && params.key?(:user_id)
48
48
 
49
49
  req = Net::HTTP::Get.new(homeserver.dup.tap do |u|
50
- u.path = api_to_path(:client_r0) + '/sync/sse'
50
+ u.path = "#{api_to_path :client_r0}/sync/sse"
51
51
  u.query = URI.encode_www_form(query)
52
52
  end)
53
53
  req['accept'] = 'text/event-stream'
@@ -46,7 +46,9 @@ module MatrixSdk
46
46
  attr_reader :api
47
47
 
48
48
  def respond_to_missing?(name, *_args)
49
- key? name
49
+ return true if key? name
50
+
51
+ super
50
52
  end
51
53
 
52
54
  def method_missing(name, *args)
@@ -1,62 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'matrix_sdk'
4
+ require 'matrix_sdk/util/events'
5
+ require 'matrix_sdk/util/tinycache'
4
6
 
5
7
  module MatrixSdk
6
8
  # A class for tracking the information about a room on Matrix
7
9
  class Room
8
10
  extend MatrixSdk::Extensions
11
+ extend MatrixSdk::Util::Tinycache
9
12
  include MatrixSdk::Logging
10
13
 
11
- # @!attribute [rw] canonical_alias
12
- # @return [String, nil] the canonical alias of the room
13
14
  # @!attribute [rw] event_history_limit
14
15
  # @return [Fixnum] the limit of events to keep in the event log
15
- attr_accessor :canonical_alias, :event_history_limit
16
+ attr_accessor :event_history_limit
16
17
  # @!attribute [r] id
17
18
  # @return [String] the internal ID of the room
18
19
  # @!attribute [r] client
19
20
  # @return [Client] the client for the room
20
- # @!attribute [rw] name
21
- # @return [String, nil] the user-provided name of the room
22
- # @see reload_name!
23
- # @!attribute [rw] topic
24
- # @return [String, nil] the user-provided topic of the room
25
- # @see reload_topic!
26
- # @!attribute [r] aliases
27
- # @return [Array(String)] a list of user-set aliases for the room
28
- # @see add_alias
29
- # @see reload_alias!
30
- # @!attribute [rw] join_rule
31
- # @return [:invite, :public] the join rule for the room -
32
- # either +:invite+ or +:public+
33
- # @!attribute [rw] guest_access
34
- # @return [:can_join, :forbidden] the guest access for the room -
35
- # either +:can_join+ or +:forbidden+
36
- # @!attribute [r] members
37
- # @return [Array(User)] the members of the room
38
- # @see reload_members!
39
21
  # @!attribute [r] events
40
22
  # @return [Array(Object)] the last +event_history_limit+ events to arrive in the room
41
23
  # @see https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-sync
42
24
  # The timeline events are what will end up in here
43
- attr_reader :id, :client, :topic, :aliases, :members, :events
25
+ attr_reader :id, :client, :events
44
26
 
45
- # @!attribute [r] on_event
46
- # @return [EventHandlerArray] The list of event handlers for all events
47
- # @!attribute [r] on_state_event
48
- # @return [EventHandlerArray] The list of event handlers for only state events
49
- # @!attribute [r] on_ephemeral_event
50
- # @return [EventHandlerArray] The list of event handlers for only ephemeral events
51
- events :event, :state_event, :ephemeral_event
52
27
  # @!method inspect
53
28
  # An inspect method that skips a handful of instance variables to avoid
54
29
  # flooding the terminal with debug data.
55
30
  # @return [String] a regular inspect string without the data for some variables
56
- ignore_inspect :client, :members, :events, :prev_batch, :logger,
57
- :on_event, :on_state_event, :on_ephemeral_event
31
+ ignore_inspect :client, :events, :prev_batch, :logger, :tinycache_adapter
32
+
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
37
+
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
58
40
 
59
41
  alias room_id id
42
+ alias members joined_members
60
43
 
61
44
  # Create a new room instance
62
45
  #
@@ -80,40 +63,80 @@ module MatrixSdk
80
63
  # @option data [String,URI] :avatar_url The avatar URL for the room
81
64
  # @option data [String] :prev_batch The previous batch token for backfill
82
65
  def initialize(client, room_id, data = {})
66
+ if client.is_a? Room
67
+ copy = client
68
+ client = copy.client
69
+ room_id = copy.id
70
+ # data = copy.attributes
71
+ end
72
+
83
73
  raise ArgumentError, 'Must be given a Client instance' unless client.is_a? Client
84
74
 
75
+ @client = client
85
76
  room_id = MXID.new room_id unless room_id.is_a?(MXID)
86
77
  raise ArgumentError, 'room_id must be a valid Room ID' unless room_id.room_id?
87
78
 
88
- event_initialize
89
-
90
- @name = nil
91
- @topic = nil
92
- @canonical_alias = nil
93
- @aliases = []
94
- @join_rule = nil
95
- @guest_access = nil
96
- @world_readable = nil
97
- @members = []
98
79
  @events = []
99
- @members_loaded = false
100
80
  @event_history_limit = 10
101
- @avatar_url = nil
81
+ @room_type = nil
102
82
 
103
83
  @prev_batch = nil
104
84
 
105
85
  data.each do |k, v|
106
- instance_variable_set("@#{k}", v) if instance_variable_defined? "@#{k}"
86
+ next if %i[client].include? k
87
+
88
+ if respond_to?("#{k}_cached?".to_sym) && send("#{k}_cached?".to_sym)
89
+ tinycache_adapter.write(k, v)
90
+ elsif instance_variable_defined? "@#{k}"
91
+ instance_variable_set("@#{k}", v)
92
+ end
107
93
  end
108
94
 
109
- @client = client
110
95
  @id = room_id.to_s
111
96
 
112
- @name_checked = Time.new(0)
113
-
114
97
  logger.debug "Created room #{room_id}"
115
98
  end
116
99
 
100
+ #
101
+ # Casting operators
102
+ #
103
+
104
+ def to_space
105
+ return nil unless space?
106
+
107
+ Rooms::Space.new self, nil
108
+ end
109
+
110
+ def to_s
111
+ prefix = canonical_alias if canonical_alias_has_value?
112
+ prefix ||= id
113
+ return "#{prefix} | #{name}" if name_has_value?
114
+
115
+ prefix
116
+ end
117
+
118
+ #
119
+ # Event handlers
120
+ #
121
+
122
+ # @!attribute [r] on_event
123
+ # @return [EventHandlerArray] The list of event handlers for all events
124
+ def on_event
125
+ ensure_room_handlers[:event]
126
+ end
127
+
128
+ # @!attribute [r] on_state_event
129
+ # @return [EventHandlerArray] The list of event handlers for only state events
130
+ def on_state_event
131
+ ensure_room_handlers[:state_event]
132
+ end
133
+
134
+ # @!attribute [r] on_ephemeral_event
135
+ # @return [EventHandlerArray] The list of event handlers for only ephemeral events
136
+ def on_ephemeral_event
137
+ ensure_room_handlers[:ephemeral_event]
138
+ end
139
+
117
140
  #
118
141
  # State readers
119
142
  #
@@ -142,19 +165,22 @@ module MatrixSdk
142
165
  'Empty Room'
143
166
  end
144
167
 
168
+ # @return [String, nil] the canonical alias of the room
169
+ def canonical_alias
170
+ client.api.get_room_state(id, 'm.room.canonical_alias')[:alias]
171
+ rescue MatrixSdk::MatrixNotFoundError
172
+ nil
173
+ end
174
+
145
175
  # Populates and returns the #members array
146
176
  #
147
177
  # @return [Array(User)] The list of members in the room
148
178
  def joined_members
149
- return members if @members_loaded && !members.empty?
150
-
151
- client.api.get_room_joined_members(id)[:joined].each do |mxid, data|
152
- ensure_member(User.new(client, mxid.to_s,
153
- display_name: data.fetch(:display_name, nil),
154
- avatar_url: data.fetch(:avatar_url, nil)))
179
+ client.api.get_room_joined_members(id)[:joined].map do |mxid, data|
180
+ User.new(client, mxid.to_s,
181
+ display_name: data.fetch(:display_name, nil),
182
+ avatar_url: data.fetch(:avatar_url, nil))
155
183
  end
156
- @members_loaded = true
157
- members
158
184
  end
159
185
 
160
186
  # Get all members (member events) in the room
@@ -174,10 +200,7 @@ module MatrixSdk
174
200
  #
175
201
  # @return [String,nil] The room name - if any
176
202
  def name
177
- return @name if Time.now - @name_checked < 900
178
-
179
- @name_checked = Time.now
180
- @name ||= client.api.get_room_name(id)
203
+ client.api.get_room_name(id)[:name]
181
204
  rescue MatrixNotFoundError
182
205
  # No room name has been specified
183
206
  nil
@@ -187,18 +210,34 @@ module MatrixSdk
187
210
  #
188
211
  # @return [String,nil] The avatar URL - if any
189
212
  def avatar_url
190
- @avatar_url ||= client.api.get_room_avatar(id).url
213
+ client.api.get_room_avatar(id)[:url]
191
214
  rescue MatrixNotFoundError
192
215
  # No avatar has been set
193
216
  nil
194
217
  end
195
218
 
219
+ # Gets the room topic - if any
220
+ #
221
+ # @return [String,nil] The topic of the room
222
+ def topic
223
+ client.api.get_room_topic(id)[:topic]
224
+ rescue MatrixNotFoundError
225
+ # No room name has been specified
226
+ nil
227
+ end
228
+
229
+ # Gets the guest access rights for the room
230
+ #
231
+ # @return [:can_join,:forbidden] The current guest access right
196
232
  def guest_access
197
- @guest_access ||= client.api.get_room_guest_access(id).guest_access.to_sym
233
+ client.api.get_room_guest_access(id)[:guest_access].to_sym
198
234
  end
199
235
 
236
+ # Gets the join rule for the room
237
+ #
238
+ # @return [:public,:knock,:invite,:private] The current join rule
200
239
  def join_rule
201
- @join_rule ||= client.api.get_room_join_rules(id).join_rule.to_sym
240
+ client.api.get_room_join_rules(id)[:join_rule].to_sym
202
241
  end
203
242
 
204
243
  # Checks if +guest_access+ is set to +:can_join+
@@ -211,6 +250,34 @@ module MatrixSdk
211
250
  join_rule == :invite
212
251
  end
213
252
 
253
+ # Gets the history visibility of the room
254
+ #
255
+ # @return [:invited,:joined,:shared,:world_readable] The current history visibility for the room
256
+ def history_visibility
257
+ client.api.get_room_state(id, 'm.room.history_visibility')[:history_visibility].to_sym
258
+ end
259
+
260
+ # Checks if the room history is world readable
261
+ #
262
+ # @return [Boolean] If the history is world readable
263
+ def world_readable?
264
+ history_visibility == :world_readable
265
+ end
266
+ alias world_readable world_readable?
267
+
268
+ # Gets the room aliases
269
+ #
270
+ # @return [Array[String]] The assigned room aliases
271
+ def aliases
272
+ client.api.get_room_aliases(id).aliases
273
+ rescue MatrixNotFoundError
274
+ data = client.api.get_room_state_all(id)
275
+ data.select { |chunk| chunk[:type] == 'm.room.aliases' && chunk.key?(:content) && chunk[:content].key?(:aliases) }
276
+ .map { |chunk| chunk[:content][:aliases] }
277
+ .flatten
278
+ .compact
279
+ end
280
+
214
281
  #
215
282
  # Message handling
216
283
  #
@@ -351,7 +418,13 @@ module MatrixSdk
351
418
  # @param reverse [Boolean] whether to fill messages in reverse or not
352
419
  # @param limit [Integer] the maximum number of messages to backfill
353
420
  # @note This will trigger the `on_event` events as messages are added
354
- def backfill_messages(reverse = false, limit = 10)
421
+ def backfill_messages(*args, reverse: false, limit: 10)
422
+ # To be backwards-compatible
423
+ if args.length == 2
424
+ reverse = args.first
425
+ limit = args.last
426
+ end
427
+
355
428
  data = client.api.get_room_messages(id, @prev_batch, direction: :b, limit: limit)
356
429
 
357
430
  events = data[:chunk]
@@ -452,6 +525,41 @@ module MatrixSdk
452
525
  true
453
526
  end
454
527
 
528
+ # Gets the room creation information
529
+ #
530
+ # @return [Response] The content of the m.room.create event
531
+ def creation_info
532
+ # Not caching here, easier to cache the important values separately instead
533
+ client.api.get_room_creation_info(id)
534
+ end
535
+
536
+ # Retrieves the type of the room
537
+ #
538
+ # @return ['m.space',String,nil] The type of the room
539
+ def room_type
540
+ # Can't change, so a permanent cache is ok
541
+ return @room_type if @room_type_retrieved || @room_type
542
+
543
+ @room_type_retrieved = true
544
+ @room_type ||= creation_info[:type]
545
+ end
546
+
547
+ # Retrieves the room version
548
+ #
549
+ # @return [String] The version of the room
550
+ def room_version
551
+ @room_version ||= creation_info[:room_version]
552
+ end
553
+
554
+ # Checks if the room is a Matrix Space
555
+ #
556
+ # @return [Boolean,nil] True if the room is a space
557
+ def space?
558
+ room_type == 'm.space'
559
+ rescue MatrixSdk::MatrixForbiddenError, MatrixSdk::MatrixNotFoundError
560
+ nil
561
+ end
562
+
455
563
  # Returns a list of the room tags
456
564
  #
457
565
  # @return [Response] A list of the tags and their data, with add and remove methods implemented
@@ -469,7 +577,7 @@ module MatrixSdk
469
577
  @room
470
578
  end
471
579
  tag_obj.define_singleton_method(:add) do |tag, **data|
472
- @room.add_tag(tag.to_s.to_sym, data)
580
+ @room.add_tag(tag.to_s.to_sym, **data)
473
581
  self[tag.to_s.to_sym] = data
474
582
  self
475
583
  end
@@ -514,22 +622,16 @@ module MatrixSdk
514
622
  #
515
623
  # @param name [String] The new name to set
516
624
  def name=(name)
625
+ tinycache_adapter.write(:name, name)
517
626
  client.api.set_room_name(id, name)
518
- @name = name
627
+ name
519
628
  end
520
629
 
521
630
  # Reloads the name of the room
522
631
  #
523
632
  # @return [Boolean] if the name was changed or not
524
633
  def reload_name!
525
- data = begin
526
- client.api.get_room_name(id)
527
- rescue MatrixNotFoundError
528
- nil
529
- end
530
- changed = data[:name] != @name
531
- @name = data[:name] if changed
532
- changed
634
+ clear_name_cache
533
635
  end
534
636
  alias refresh_name! reload_name!
535
637
 
@@ -537,22 +639,16 @@ module MatrixSdk
537
639
  #
538
640
  # @param topic [String] The new topic to set
539
641
  def topic=(topic)
642
+ tinycache_adapter.write(:topic, topic)
540
643
  client.api.set_room_topic(id, topic)
541
- @topic = topic
644
+ topic
542
645
  end
543
646
 
544
647
  # Reloads the topic of the room
545
648
  #
546
649
  # @return [Boolean] if the topic was changed or not
547
650
  def reload_topic!
548
- data = begin
549
- client.api.get_room_topic(id)
550
- rescue MatrixNotFoundError
551
- nil
552
- end
553
- changed = data[:topic] != @topic
554
- @topic = data[:topic] if changed
555
- changed
651
+ clear_topic_cache
556
652
  end
557
653
  alias refresh_topic! reload_topic!
558
654
 
@@ -561,7 +657,7 @@ module MatrixSdk
561
657
  # @return [Boolean] if the addition was successful or not
562
658
  def add_alias(room_alias)
563
659
  client.api.set_room_alias(id, room_alias)
564
- @aliases << room_alias
660
+ tinycache_adapter.read(:aliases) << room_alias if tinycache_adapter.exist?(:aliases)
565
661
  true
566
662
  end
567
663
 
@@ -571,21 +667,7 @@ module MatrixSdk
571
667
  # @note The list of aliases is not sorted, ordering changes will result in
572
668
  # alias list updates.
573
669
  def reload_aliases!
574
- begin
575
- new_aliases = client.api.get_room_aliases(id).aliases
576
- rescue MatrixNotFoundError
577
- data = client.api.get_room_state_all(id)
578
- new_aliases = data.select { |chunk| chunk[:type] == 'm.room.aliases' && chunk.key?(:content) && chunk[:content].key?(:aliases) }
579
- .map { |chunk| chunk[:content][:aliases] }
580
- .flatten
581
- .compact
582
- end
583
-
584
- return false if new_aliases.nil?
585
-
586
- changed = new_aliases != aliases
587
- @aliases = new_aliases if changed
588
- changed
670
+ clear_aliases_cache
589
671
  end
590
672
  alias refresh_aliases! reload_aliases!
591
673
 
@@ -594,7 +676,7 @@ module MatrixSdk
594
676
  # @param invite_only [Boolean] If it should be invite only or not
595
677
  def invite_only=(invite_only)
596
678
  self.join_rule = invite_only ? :invite : :public
597
- @join_rule == :invite
679
+ invite_only
598
680
  end
599
681
 
600
682
  # Sets the join rule of the room
@@ -602,7 +684,8 @@ module MatrixSdk
602
684
  # @param join_rule [:invite,:public] The join rule of the room
603
685
  def join_rule=(join_rule)
604
686
  client.api.set_room_join_rules(id, join_rule)
605
- @join_rule = join_rule
687
+ tinycache_adapter.write(:join_rule, join_rule)
688
+ join_rule
606
689
  end
607
690
 
608
691
  # Sets if guests are allowed in the room
@@ -610,7 +693,7 @@ module MatrixSdk
610
693
  # @param allow_guests [Boolean] If guests are allowed to join or not
611
694
  def allow_guests=(allow_guests)
612
695
  self.guest_access = (allow_guests ? :can_join : :forbidden)
613
- @guest_access == :can_join
696
+ allow_guests
614
697
  end
615
698
 
616
699
  # Sets the guest access status for the room
@@ -618,18 +701,101 @@ module MatrixSdk
618
701
  # @param guest_access [:can_join,:forbidden] The new guest access status of the room
619
702
  def guest_access=(guest_access)
620
703
  client.api.set_room_guest_access(id, guest_access)
621
- @guest_access = guest_access
704
+ tinycache_adapter.write(:guest_access, guest_access)
705
+ guest_access
622
706
  end
623
707
 
624
708
  # Sets a new avatar URL for the room
625
709
  #
626
- # @param avatar_url [URI::MATRIX] The mxc:// URL for the new room avatar
710
+ # @param avatar_url [URI::MXC] The mxc:// URL for the new room avatar
627
711
  def avatar_url=(avatar_url)
628
712
  avatar_url = URI(avatar_url) unless avatar_url.is_a? URI
629
- raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MATRIX
713
+ raise ArgumentError, 'Must be a valid MXC URL' unless avatar_url.is_a? URI::MXC
630
714
 
631
715
  client.api.set_room_avatar(id, avatar_url)
632
- @avatar_url = avatar_url
716
+ tinycache_adapter.write(:avatar_url, avatar_url)
717
+ avatar_url
718
+ end
719
+
720
+ # Get the power levels of the room
721
+ #
722
+ # @note The returned power levels are cached for a minute
723
+ # @return [Hash] The current power levels as set for the room
724
+ # @see Protocols::CS#get_power_levels
725
+ def power_levels
726
+ client.api.get_power_levels(id)
727
+ end
728
+
729
+ # Gets the power level of a user in the room
730
+ #
731
+ # @param user [User,MXID,String] The user to check the power level for
732
+ # @param use_default [Boolean] Should the user default level be checked if no user-specific one exists
733
+ # @return [Integer,nil] The current power level for the requested user, nil if there's no user specific level
734
+ # and use_default is false
735
+ def user_powerlevel(user, use_default: true)
736
+ user = user.id if user.is_a? User
737
+ user = MXID.new(user.to_s) unless user.is_a? MXID
738
+ raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
739
+
740
+ level = power_levels[:users][user.to_s.to_sym]
741
+ level = power_levels[:users_default] || 0 if level.nil? && use_default
742
+ level
743
+ end
744
+
745
+ # Check if a user is an admin in the room
746
+ #
747
+ # @param user [User,MXID,String] The user to check for admin privileges
748
+ # @param target_level [Integer] The power level that's to be considered as admin privileges
749
+ # @return [Boolean] If the requested user has a power level highe enough to be an admin
750
+ # @see #user_powerlevel
751
+ def admin?(user, target_level: 100)
752
+ level = user_powerlevel(user, use_default: false)
753
+ return false unless level
754
+
755
+ level >= target_level
756
+ end
757
+
758
+ # Make a user an admin in the room
759
+ #
760
+ # @param user [User,MXID,String] The user to give admin privileges
761
+ # @param level [Integer] The power level to set the user to
762
+ # @see #modify_user_power_levels
763
+ def admin!(user, level: 100)
764
+ return true if admin?(user, target_level: level)
765
+
766
+ user = user.id if user.is_a? User
767
+ user = MXID.new(user.to_s) unless user.is_a? MXID
768
+ raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
769
+
770
+ modify_user_power_levels({ user.to_s.to_sym => level })
771
+ end
772
+
773
+ # Check if a user is a moderator in the room
774
+ #
775
+ # @param user [User,MXID,String] The user to check for admin privileges
776
+ # @param target_level [Integer] The power level that's to be considered as admin privileges
777
+ # @return [Boolean] If the requested user has a power level highe enough to be an admin
778
+ # @see #user_powerlevel
779
+ def moderator?(user, target_level: 50)
780
+ level = user_powerlevel(user, use_default: false)
781
+ return false unless level
782
+
783
+ level >= target_level
784
+ end
785
+
786
+ # Make a user a moderator in the room
787
+ #
788
+ # @param user [User,MXID,String] The user to give moderator privileges
789
+ # @param level [Integer] The power level to set the user to
790
+ # @see #modify_user_power_levels
791
+ def moderator!(user, level: 50)
792
+ return true if moderator?(user, target_level: level)
793
+
794
+ user = user.id if user.is_a? User
795
+ user = MXID.new(user.to_s) unless user.is_a? MXID
796
+ raise ArgumentError, 'Must provide a valid user or MXID' unless user.user?
797
+
798
+ modify_user_power_levels({ user.to_s.to_sym => level })
633
799
  end
634
800
 
635
801
  # Modifies the power levels of the room
@@ -640,7 +806,8 @@ module MatrixSdk
640
806
  def modify_user_power_levels(users = nil, users_default = nil)
641
807
  return false if users.nil? && users_default.nil?
642
808
 
643
- data = client.api.get_power_levels(id)
809
+ data = power_levels_without_cache
810
+ tinycache_adapter.write(:power_levels, data)
644
811
  data[:users_default] = users_default unless users_default.nil?
645
812
 
646
813
  if users
@@ -661,7 +828,8 @@ module MatrixSdk
661
828
  def modify_required_power_levels(events = nil, params = {})
662
829
  return false if events.nil? && (params.nil? || params.empty?)
663
830
 
664
- data = client.api.get_power_levels(id)
831
+ data = power_levels_without_cache
832
+ tinycache_adapter.write(:power_levels, data)
665
833
  data.merge!(params)
666
834
  data.delete_if { |_k, v| v.nil? }
667
835
 
@@ -678,22 +846,103 @@ module MatrixSdk
678
846
  private
679
847
 
680
848
  def ensure_member(member)
849
+ tinycache_adapter.write(:joined_members, []) unless tinycache_adapter.exist? :joined_members
850
+
851
+ members = tinycache_adapter.read(:joined_members) || []
681
852
  members << member unless members.any? { |m| m.id == member.id }
682
853
  end
683
854
 
855
+ def handle_power_levels(event)
856
+ tinycache_adapter.write(:power_levels, event[:content])
857
+ end
858
+
859
+ def handle_room_name(event)
860
+ tinycache_adapter.write(:name, event[:content][:name])
861
+ end
862
+
863
+ def handle_room_topic(event)
864
+ tinycache_adapter.write(:topic, event[:content][:topic])
865
+ end
866
+
867
+ def handle_room_guest_access(event)
868
+ tinycache_adapter.write(:guest_access, event[:content][:guest_access].to_sym)
869
+ end
870
+
871
+ def handle_room_join_rules(event)
872
+ tinycache_adapter.write(:join_rule, event[:content][:join_rule].to_sym)
873
+ end
874
+
875
+ def handle_room_member(event)
876
+ return unless client.cache == :all
877
+
878
+ if event[:content][:membership] == 'join'
879
+ ensure_member(client.get_user(event[:state_key]).dup.tap do |u|
880
+ u.instance_variable_set :@display_name, event[:content][:displayname]
881
+ end)
882
+ elsif tinycache_adapter.exist? :joined_members
883
+ members = tinycache_adapter.read(:joined_members)
884
+ members.delete_if { |m| m.id == event[:state_key] }
885
+ end
886
+ end
887
+
888
+ def handle_room_canonical_alias(event)
889
+ canonical_alias = tinycache_adapter.write :canonical_alias, event[:content][:alias]
890
+
891
+ data = tinycache_adapter.read(:aliases) || []
892
+ data << canonical_alias
893
+ tinycache_adapter.write(:aliases, data)
894
+ end
895
+
896
+ def handle_room_aliases(event)
897
+ tinycache_adapter.write(:aliases, []) unless tinycache_adapter.exist? :aliases
898
+
899
+ aliases = tinycache_adapter.read(:aliases) || []
900
+ aliases.concat event[:content][:aliases]
901
+
902
+ tinycache_adapter.write(:aliases, aliases)
903
+ end
904
+
905
+ def room_handlers?
906
+ client.instance_variable_get(:@room_handlers).key? id
907
+ end
908
+
909
+ def ensure_room_handlers
910
+ client.instance_variable_get(:@room_handlers)[id] ||= {
911
+ event: MatrixSdk::EventHandlerArray.new,
912
+ state_event: MatrixSdk::EventHandlerArray.new,
913
+ ephemeral_event: MatrixSdk::EventHandlerArray.new
914
+ }
915
+ end
916
+
917
+ INTERNAL_HANDLERS = {
918
+ 'm.room.aliases' => :handle_room_aliases,
919
+ 'm.room.canonical_alias' => :handle_room_canonical_alias,
920
+ 'm.room.guest_access' => :handle_room_guest_access,
921
+ 'm.room.join_rules' => :handle_room_join_rules,
922
+ 'm.room.member' => :handle_room_member,
923
+ 'm.room.name' => :handle_room_name,
924
+ 'm.room.power_levels' => :handle_power_levels,
925
+ 'm.room.topic' => :handle_room_topic
926
+ }.freeze
684
927
  def put_event(event)
928
+ ensure_room_handlers[:event].fire(MatrixEvent.new(self, event), event[:type]) if room_handlers?
929
+
685
930
  @events.push event
686
931
  @events.shift if @events.length > @event_history_limit
687
-
688
- fire_event MatrixEvent.new(self, event)
689
932
  end
690
933
 
691
934
  def put_ephemeral_event(event)
692
- fire_ephemeral_event MatrixEvent.new(self, event)
935
+ return unless room_handlers?
936
+
937
+ ensure_room_handlers[:ephemeral_event].fire(MatrixEvent.new(self, event), event[:type])
693
938
  end
694
939
 
695
940
  def put_state_event(event)
696
- fire_state_event MatrixEvent.new(self, event)
941
+ send(INTERNAL_HANDLERS[event[:type]], event) if INTERNAL_HANDLERS.key? event[:type]
942
+
943
+ return unless room_handlers?
944
+
945
+ ensure_room_handlers[:state_event].fire(MatrixEvent.new(self, event), event[:type])
697
946
  end
698
947
  end
699
948
  end