Class: SolidObjects::ComponentSubscriptions

Inherits:
Object
  • Object
show all
Defined in:
lib/solid_objects/component_subscriptions.rb,
sig/generated/lib/solid_objects/component_subscriptions.rbs

Constant Summary collapse

MAXIMUM_COMPONENTS =

Returns:

  • (::Integer)
50
MAXIMUM_SERIALIZED_BYTES =

Returns:

  • (::Integer)
1_048_576

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registrations) ⇒ ComponentSubscriptions

Returns a new instance of ComponentSubscriptions.

RBS:

  • (Array[ComponentRegistration]) -> void

Parameters:



39
40
41
42
43
44
# File 'lib/solid_objects/component_subscriptions.rb', line 39

def initialize(registrations)
  @registrations = registrations
  @revisions = registrations.to_h do |registration|
    [ registration.dom_id, registration.revision_key ]
  end
end

Instance Attribute Details

#registrationsObject (readonly)

Returns the value of attribute registrations.

Returns:

  • (Object)


85
86
87
# File 'lib/solid_objects/component_subscriptions.rb', line 85

def registrations
  @registrations
end

#revisionsObject (readonly)

Returns the value of attribute revisions.

Returns:

  • (Object)


85
86
87
# File 'lib/solid_objects/component_subscriptions.rb', line 85

def revisions
  @revisions
end

Class Method Details

.parse(serialized, reference:) ⇒ ComponentSubscriptions

RBS:

  • (String?, reference: Reference) -> ComponentSubscriptions

Parameters:

Returns:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/solid_objects/component_subscriptions.rb', line 12

def self.parse(serialized, reference:)
  return new([]) unless serialized
  unless serialized.is_a?(String) &&
      serialized.bytesize <= MAXIMUM_SERIALIZED_BYTES
    raise InvalidComponentToken, "invalid actor component registrations"
  end

  tokens = JSON.parse(serialized)
  unless tokens.is_a?(Array) &&
      tokens.length <= MAXIMUM_COMPONENTS &&
      tokens.all? { |token| token.is_a?(String) }
    raise InvalidComponentToken, "invalid actor component registrations"
  end

  registrations = tokens.map do |token|
    ComponentRegistration.from_token(token).tap do |registration|
      validate_identity!(registration, reference)
    end
  end
  if registrations.map(&:dom_id).uniq.length != registrations.length
    raise InvalidComponentToken, "duplicate actor component registration"
  end

  new(registrations)
end

Instance Method Details

#newer_revision?(dom_id, instance_id, revision) ⇒ Boolean

RBS:

  • (String, Integer, Integer) -> bool

Parameters:

  • (String)
  • (Integer)
  • (Integer)

Returns:

  • (Boolean)


118
119
120
121
# File 'lib/solid_objects/component_subscriptions.rb', line 118

def newer_revision?(dom_id, instance_id, revision)
  current = revisions.fetch(dom_id)
  (current <=> [ instance_id, revision ]) == -1
end

#reconnect_refreshes(snapshot) ⇒ Array[String]

RBS:

  • (ActorSnapshot) -> Array[String]

Parameters:

Returns:

  • (Array[String])


59
60
61
62
63
64
65
66
67
68
# File 'lib/solid_objects/component_subscriptions.rb', line 59

def reconnect_refreshes(snapshot)
  stale = registrations.select do |registration|
    newer_revision?(
      registration.dom_id,
      snapshot.instance_id,
      snapshot.revision
    )
  end
  refresh_streams(stale, snapshot.instance_id, snapshot.revision)
end

#record_revision(registration, instance_id, revision) ⇒ void

This method returns an undefined value.

RBS:

  • (ComponentRegistration, Integer, Integer) -> void

Parameters:



103
104
105
# File 'lib/solid_objects/component_subscriptions.rb', line 103

def record_revision(registration, instance_id, revision)
  revisions[registration.dom_id] = [ instance_id, revision ]
end

#refresh(registration, instance_id, revision) ⇒ String

RBS:

  • (ComponentRegistration, Integer, Integer) -> String

Parameters:

Returns:

  • (String)


108
109
110
111
112
113
114
115
# File 'lib/solid_objects/component_subscriptions.rb', line 108

def refresh(registration, instance_id, revision)
  record_revision(registration, instance_id, revision)
  TurboStreamRenderer.component_refresh(
    registration,
    instance_id,
    revision
  )
end

#refresh_streams(changed, instance_id, revision) ⇒ Array[String]

Live invalidations and reconnect replays share this, so a reconnecting client pays the same number of requests a connected one does.

RBS:

  • (Array[ComponentRegistration], Integer, Integer) -> Array[String]

Parameters:

Returns:

  • (Array[String])


90
91
92
93
94
95
96
97
98
99
100
# File 'lib/solid_objects/component_subscriptions.rb', line 90

def refresh_streams(changed, instance_id, revision)
  batched, individual = changed.partition(&:batch)
  streams = individual.map do |registration|
    refresh(registration, instance_id, revision)
  end
  batched.group_by(&:batch).each_value do |group|
    group.each { |registration| record_revision(registration, instance_id, revision) }
    streams << TurboStreamRenderer.batch_refresh(group, instance_id, revision)
  end
  streams
end

#refreshes_for(invalidation) ⇒ Array[String]

RBS:

  • (Hash[String, untyped]) -> Array[String]

Parameters:

  • (Hash[String, untyped])

Returns:

  • (Array[String])


47
48
49
50
51
52
53
54
55
56
# File 'lib/solid_objects/component_subscriptions.rb', line 47

def refreshes_for(invalidation)
  observable_name = invalidation.fetch("observable_name")
  instance_id = invalidation.fetch("instance_id")
  revision = invalidation.fetch("revision")
  changed = registrations.select do |registration|
    registration.dependencies.include?(observable_name) &&
      newer_revision?(registration.dom_id, instance_id, revision)
  end
  refresh_streams(changed, instance_id, revision)
end