Class: Upkeep::DAG::SubscriptionShape

Inherits:
Object
  • Object
show all
Defined in:
lib/upkeep/dag/subscription_shape.rb

Defined Under Namespace

Classes: Trace

Constant Summary collapse

DIGEST_SCOPE =
"upkeep-subscription-shape"
FRAME_PAYLOAD_SHAPE_IGNORED_KEYS =
%i[manifest recipe].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(signature:) ⇒ SubscriptionShape

Returns a new instance of SubscriptionShape.



157
158
159
# File 'lib/upkeep/dag/subscription_shape.rb', line 157

def initialize(signature:)
  @signature = signature
end

Instance Attribute Details

#signatureObject (readonly)

Returns the value of attribute signature.



13
14
15
# File 'lib/upkeep/dag/subscription_shape.rb', line 13

def signature
  @signature
end

Class Method Details

.canonical_term(*parts) ⇒ Object



149
150
151
# File 'lib/upkeep/dag/subscription_shape.rb', line 149

def self.canonical_term(*parts)
  parts.map { |part| canonical_value(part) }.join("\0")
end

.canonical_value(value) ⇒ Object



153
154
155
# File 'lib/upkeep/dag/subscription_shape.rb', line 153

def self.canonical_value(value)
  shape_value(value).inspect
end

.contains_term(from, to) ⇒ Object



134
135
136
# File 'lib/upkeep/dag/subscription_shape.rb', line 134

def self.contains_term(from, to)
  canonical_term(:contains, from, to)
end

.dependency_component(graph, node) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/upkeep/dag/subscription_shape.rb', line 122

def self.dependency_component(graph, node)
  {
    id: node.id,
    dependency: shape_value(node.payload.to_h),
    owners: graph.dependency_owner_ids(node.id).sort_by(&:to_s)
  }
end

.dependency_term(id, dependency, owners) ⇒ Object



130
131
132
# File 'lib/upkeep/dag/subscription_shape.rb', line 130

def self.dependency_term(id, dependency, owners)
  canonical_term(:dependency, id, dependency.to_h, owners.sort_by(&:to_s))
end

.frame_component(id, payload) ⇒ Object



98
99
100
101
102
103
# File 'lib/upkeep/dag/subscription_shape.rb', line 98

def self.frame_component(id, payload)
  {
    id: id,
    payload: frame_payload_component(payload)
  }
end

.frame_payload_component(payload) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/upkeep/dag/subscription_shape.rb', line 109

def self.frame_payload_component(payload)
  component = payload.reject do |key, _value|
    key.respond_to?(:to_sym) && FRAME_PAYLOAD_SHAPE_IGNORED_KEYS.include?(key.to_sym)
  end
  component = shape_value(component)
  recipe = payload[:recipe] || payload["recipe"]
  kind = payload[:kind] || payload["kind"]
  if recipe && kind.to_s == "render_site"
    component[:shared_stream_signature] = SharedStreams.signature_for(recipe)
  end
  component
end

.frame_term(id, payload) ⇒ Object



105
106
107
# File 'lib/upkeep/dag/subscription_shape.rb', line 105

def self.frame_term(id, payload)
  canonical_term(:frame, id, frame_payload_component(payload))
end

.from_components(graph_component, request_signature: nil) ⇒ Object



19
20
21
# File 'lib/upkeep/dag/subscription_shape.rb', line 19

def self.from_components(graph_component, request_signature: nil)
  new(signature: signature_for_terms(request_signature, terms_for_component(graph_component)))
end

.from_graph(graph, request_signature: nil) ⇒ Object



15
16
17
# File 'lib/upkeep/dag/subscription_shape.rb', line 15

def self.from_graph(graph, request_signature: nil)
  new(signature: signature_for_terms(request_signature, graph_terms(graph)))
end

.from_terms(graph_terms, request_signature: nil) ⇒ Object



23
24
25
# File 'lib/upkeep/dag/subscription_shape.rb', line 23

def self.from_terms(graph_terms, request_signature: nil)
  new(signature: signature_for_terms(request_signature, graph_terms))
end

.from_trace_digest(trace_digest, request_signature: nil) ⇒ Object



27
28
29
# File 'lib/upkeep/dag/subscription_shape.rb', line 27

def self.from_trace_digest(trace_digest, request_signature: nil)
  new(signature: signature_for_trace_digest(request_signature, trace_digest))
end

.graph_component(graph) ⇒ Object



67
68
69
70
71
72
73
74
75
76
# File 'lib/upkeep/dag/subscription_shape.rb', line 67

def self.graph_component(graph)
  {
    frames: graph.frame_nodes.map { |node| frame_component(node.id, node.payload) }.sort_by { |component| component.fetch(:id).to_s },
    dependencies: graph.dependency_nodes.map { |node| dependency_component(graph, node) }.sort_by { |component| component.fetch(:id).inspect },
    contains: graph.edges
      .select { |edge| edge.reason == :contains }
      .map { |edge| [edge.from, edge.to] }
      .sort_by(&:inspect)
  }
end

.graph_terms(graph) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/upkeep/dag/subscription_shape.rb', line 78

def self.graph_terms(graph)
  {
    frames: graph.frame_nodes.map { |node| frame_term(node.id, node.payload) },
    dependencies: graph.dependency_nodes.map { |node| dependency_term(node.id, node.payload, graph.dependency_owner_ids(node.id)) },
    contains: graph.edges
      .select { |edge| edge.reason == :contains }
      .map { |edge| contains_term(edge.from, edge.to) }
  }
end

.request_signature_component(signature) ⇒ Object



61
62
63
64
65
# File 'lib/upkeep/dag/subscription_shape.rb', line 61

def self.request_signature_component(signature)
  return nil unless signature

  signature.respond_to?(:to_h) ? signature.to_h : signature
end

.shape_value(value) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'lib/upkeep/dag/subscription_shape.rb', line 138

def self.shape_value(value)
  case value
  when Hash
    value.keys.sort_by(&:to_s).to_h { |key| [key, shape_value(value.fetch(key))] }
  when Array
    value.map { |item| shape_value(item) }
  else
    value.respond_to?(:to_h) ? shape_value(value.to_h) : value
  end
end

.signature_for_terms(request_signature, graph_terms) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/upkeep/dag/subscription_shape.rb', line 31

def self.signature_for_terms(request_signature, graph_terms)
  digest = Digest::SHA256.new
  digest.update(DIGEST_SCOPE)
  digest.update("\0")
  digest.update(Upkeep::VERSION)
  digest.update("\0")
  digest.update(canonical_value(request_signature_component(request_signature)))
  %i[frames dependencies contains].each do |group|
    digest.update("\0")
    digest.update(group.to_s)
    Array(graph_terms[group]).each do |term|
      digest.update("\0")
      digest.update(term)
    end
  end
  digest.hexdigest
end

.signature_for_trace_digest(request_signature, trace_digest) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/upkeep/dag/subscription_shape.rb', line 49

def self.signature_for_trace_digest(request_signature, trace_digest)
  digest = Digest::SHA256.new
  digest.update(DIGEST_SCOPE)
  digest.update("\0")
  digest.update(Upkeep::VERSION)
  digest.update("\0")
  digest.update(canonical_value(request_signature_component(request_signature)))
  digest.update("\0")
  digest.update(trace_digest)
  digest.hexdigest
end

.terms_for_component(graph_component) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/upkeep/dag/subscription_shape.rb', line 88

def self.terms_for_component(graph_component)
  {
    frames: graph_component.fetch(:frames).map { |component| canonical_term(:frame, component.fetch(:id), component.fetch(:payload)) },
    dependencies: graph_component.fetch(:dependencies).map do |component|
      canonical_term(:dependency, component.fetch(:id), component.fetch(:dependency), component.fetch(:owners))
    end,
    contains: graph_component.fetch(:contains).map { |from, to| contains_term(from, to) }
  }
end