Class: Mayu::VDOM::VTree::Updater

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/mayu/vdom/vtree.rb

Constant Summary collapse

DEFAULT_UPDATES_PER_SECOND =

This value limits how many updates per second we can make.

20

Instance Method Summary collapse

Constructor Details

#initialize(vtree, updates_per_second: DEFAULT_UPDATES_PER_SECOND) ⇒ Updater

Returns a new instance of Updater.



32
33
34
35
# File 'lib/mayu/vdom/vtree.rb', line 32

def initialize(vtree, updates_per_second: DEFAULT_UPDATES_PER_SECOND)
  @vtree = vtree
  @updates_per_second = updates_per_second
end

Instance Method Details

#run(metrics: nil, task: Async::Task.current, &block) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/mayu/vdom/vtree.rb', line 44

def run(metrics: nil, task: Async::Task.current, &block)
  task.async(annotation: "VTree updater") do |task|
    assets = T::Set[String].new

    loop do
      @vtree.update_queue.wait while @vtree.update_queue.empty?

      start_at = Time.now

      update(assets:, metrics:) do |event, payload|
        yield [event, payload]
      end

      delta_time_ms = (Time.now - start_at) * 1000

      # TODO: Make this configurable..
      # should also be in the prometheus output
      if delta_time_ms > 50
        Console.logger.warn(
          self,
          "Rendering took %.3fms" % delta_time_ms
        )
      end

      yield [:update_finished, delta_time_ms:]

      sleep 1.0 / @updates_per_second
    end
  rescue => e
    puts e.message
    puts e.backtrace
    error = {
      type: e.class.name,
      message: e.message,
      backtrace: e.backtrace
    }

    yield [:exception, error]
  end
end

#stylesheet_patch(stylesheets) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/mayu/vdom/vtree.rb', line 88

def stylesheet_patch(stylesheets)
  return [] if stylesheets.empty?

  paths = stylesheets.map { "/__mayu/static/#{_1}" }

  [{ type: :stylesheet, paths: }]
end

#update(assets: T::Set[String].new, metrics: nil) {|[:patch, patches]| ... } ⇒ Object

Yields:

  • ([:patch, patches])


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/mayu/vdom/vtree.rb', line 103

def update(assets: T::Set[String].new, metrics: nil, &block)
  ctx = UpdateContext.new

  @vtree.update_queue.size.times do
    case @vtree.update_queue.dequeue
    in [:replace_root, descriptor]
      @vtree.render(descriptor, ctx:)
    in [:navigate, path]
      yield [:navigate, path]
    in [:action, payload]
      yield [:action, payload]
    in [:exception, error]
      yield [:exception, error]
    in [:pong, timestamp]
      yield [:pong, timestamp]
    in VNode => vnode
      next if vnode.removed?
      next unless vnode.component&.dirty?

      if metrics
        type = vnode.descriptor.type
        vnode_type =
          if type.respond_to?(:__mayu_resource) &&
               resource = type.__mayu_resource
            resource.path
          else
            type.inspect[0..10].to_s
          end

        metrics.vnode_patch_times.observe(
          Benchmark.realtime do
            @vtree.patch(ctx, vnode, vnode.descriptor, lifecycles: true)
          end,
          labels: {
            vnode_type:
          }
        )
      else
        @vtree.patch(ctx, vnode, vnode.descriptor, lifecycles: true)
      end
    end
  end

  stylesheets = []

  @vtree.assets.each do |asset|
    next if assets.include?(asset)
    next unless asset.end_with?(".css")
    stylesheets.push(asset)
    assets.add(asset)
  end

  patches = [*stylesheet_patch(stylesheets), *ctx.patches]
  yield [:patch, patches] unless patches.empty?

  @vtree.cleanup_unused_handlers!
end