From a72d94d6d4581affcd437e6e9dc7cb7dc8894cfa Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 2 Sep 2020 12:21:23 +0200 Subject: [PATCH 1/6] remove weird spaces --- lib/dashing/app.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 0a172fd..4cb17ad 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -54,7 +54,7 @@ def authenticated?(token) settings.sprockets.append_path("assets/#{path}") end -['widgets', File.expand_path('../../../javascripts', __FILE__)]. each do |path| +['widgets', File.expand_path('../../../javascripts', __FILE__)].each do |path| settings.sprockets.append_path(path) end @@ -141,7 +141,7 @@ def stop_with_connection_closing def send_event(id, body, target=nil) body[:id] = id - body[:updatedAt] ||= (Time.now.to_f * 1000.0).to_i + body[:updatedAt] ||= (Time.now.to_f * 1000.0).to_i event = format_event(body.to_json, target) Sinatra::Application.settings.history[id] = event unless target == 'dashboards' Sinatra::Application.settings.connections.each { |out| From dff0e3f3dc8d5b4778f162f0f69244ffd823ed7d Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 2 Sep 2020 15:02:31 +0200 Subject: [PATCH 2/6] send only data that is needed on the dashboard --- javascripts/dashing.coffee | 65 ++++++++++++++++++++------------------ lib/dashing/app.rb | 17 +++++----- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index 02a8c0b..3910376 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -53,8 +53,9 @@ class Dashing.Widget extends Batman.View super @mixin($(@node).data()) - Dashing.widgets[@id] ||= [] - Dashing.widgets[@id].push(@) + if @id # skip widgets without id + Dashing.widgets[@id] ||= [] + Dashing.widgets[@id].push(@) type = Batman.Filters.dashize(@view) $(@node).addClass("widget widget-#{type} #{@id}") @@ -121,34 +122,38 @@ Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} Dashing.debugMode = false -source = new EventSource('events') -source.addEventListener 'open', (e) -> - console.log("Connection opened", e) - -source.addEventListener 'error', (e)-> - console.log("Connection error", e) - if (e.currentTarget.readyState == EventSource.CLOSED) - console.log("Connection closed") - setTimeout (-> - window.location.reload() - ), 5*60*1000 - -source.addEventListener 'message', (e) -> - data = JSON.parse(e.data) - if lastEvents[data.id]?.updatedAt != data.updatedAt - if Dashing.debugMode - console.log("Received data for #{data.id}", data) - lastEvents[data.id] = data - if widgets[data.id]?.length > 0 - for widget in widgets[data.id] - widget.receiveData(data) - -source.addEventListener 'dashboards', (e) -> - data = JSON.parse(e.data) - if Dashing.debugMode - console.log("Received data for dashboards", data) - if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}" - Dashing.fire data.event, data +Dashing.on 'run', -> + setTimeout -> # run only when all widgets are created + ids = Object.keys(Dashing.widgets) + source = new EventSource('events?ids=' + encodeURIComponent(ids.join(','))) + source.addEventListener 'open', (e) -> + console.log("Connection opened", e) + + source.addEventListener 'error', (e)-> + console.log("Connection error", e) + if (e.currentTarget.readyState == EventSource.CLOSED) + console.log("Connection closed") + setTimeout (-> + window.location.reload() + ), 5*60*1000 + + source.addEventListener 'message', (e) -> + data = JSON.parse(e.data) + if lastEvents[data.id]?.updatedAt != data.updatedAt + if Dashing.debugMode + console.log("Received data for #{data.id}", data) + lastEvents[data.id] = data + if widgets[data.id]?.length > 0 + for widget in widgets[data.id] + widget.receiveData(data) + + source.addEventListener 'dashboards', (e) -> + data = JSON.parse(e.data) + if Dashing.debugMode + console.log("Received data for dashboards", data) + if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}" + Dashing.fire data.event, data + , 0 $(document).ready -> Dashing.run() diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 4cb17ad..b0aac53 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -36,7 +36,7 @@ def authenticated?(token) set :assets_prefix, '/assets' set :digest_assets, false set :server, 'thin' -set :connections, [] +set :connections, {} set :history_file, 'history.yml' set :public_folder, File.join(settings.root, 'public') set :views, File.join(settings.root, 'dashboards') @@ -77,9 +77,10 @@ def authenticated?(token) get '/events', :provides => 'text/event-stream' do protected! response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx + ids = params[:ids].to_s.split(',').to_set stream :keep_open do |out| - settings.connections << out - out << latest_events + settings.connections[out] = ids + out << latest_events(ids) out.callback { settings.connections.delete(out) } end end @@ -144,9 +145,9 @@ def send_event(id, body, target=nil) body[:updatedAt] ||= (Time.now.to_f * 1000.0).to_i event = format_event(body.to_json, target) Sinatra::Application.settings.history[id] = event unless target == 'dashboards' - Sinatra::Application.settings.connections.each { |out| + Sinatra::Application.settings.connections.each { |out, ids| begin - out << event + out << event if ids.include?(id) rescue IOError => e # if the socket is closed an IOError is thrown Sinatra::Application.settings.connections.delete(out) end @@ -159,9 +160,9 @@ def format_event(body, name=nil) str << "data: #{body}\n\n" end -def latest_events - settings.history.inject("") do |str, (_id, body)| - str << body +def latest_events(ids) + settings.history.each_with_object("") do |(id, body), str| + str << body if ids.include?(id) end end From 0b0b5ee410a12fc0b220239e5d7f1d446e94f197 Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 2 Sep 2020 15:02:54 +0200 Subject: [PATCH 3/6] inline latest_events method --- lib/dashing/app.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index b0aac53..cf496bf 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -80,7 +80,9 @@ def authenticated?(token) ids = params[:ids].to_s.split(',').to_set stream :keep_open do |out| settings.connections[out] = ids - out << latest_events(ids) + settings.history.each do |id, event| + out << event if ids.include?(id) + end out.callback { settings.connections.delete(out) } end end @@ -160,12 +162,6 @@ def format_event(body, name=nil) str << "data: #{body}\n\n" end -def latest_events(ids) - settings.history.each_with_object("") do |(id, body), str| - str << body if ids.include?(id) - end -end - def first_dashboard files = Dir[File.join(settings.views, '*')].collect { |f| File.basename(f, '.*') } files -= ['layout'] From 5f5f31e7b88207d90a8533440289865f42c31956 Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 24 Feb 2021 16:00:45 +0100 Subject: [PATCH 4/6] fix tests to work with connections being a Hash instead of an Array --- test/app_test.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/app_test.rb b/test/app_test.rb index 40e8b62..d5a809d 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -4,7 +4,9 @@ class AppTest < Dashing::Test def setup @connection = [] - app.settings.connections = [@connection] + # stop sinatra from handling Hash value specially which makes it merge new value into previous one + app.settings.connections = nil + app.settings.connections = {@connection => ['some_widget']} app.settings.auth_token = nil app.settings.default_dashboard = nil app.settings.history_file = File.join(Dir.tmpdir, 'history.yml') From 97a72a41efdb2d9c9260f01fe8d5e083f09ffd13 Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 24 Feb 2021 16:04:55 +0100 Subject: [PATCH 5/6] correct closing streams when stopping the server --- lib/dashing/app.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index cf496bf..8af2746 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -134,7 +134,7 @@ def authenticated?(token) Thin::Server.class_eval do def stop_with_connection_closing - Sinatra::Application.settings.connections.dup.each(&:close) + Sinatra::Application.settings.connections.dup.each_key(&:close) stop_without_connection_closing end From 4216c86c419d4d6d6a7986e1f4b92483f459bdd6 Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Wed, 24 Feb 2021 16:05:39 +0100 Subject: [PATCH 6/6] allow all dashboards events to pass through --- lib/dashing/app.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 8af2746..54405a4 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -149,7 +149,7 @@ def send_event(id, body, target=nil) Sinatra::Application.settings.history[id] = event unless target == 'dashboards' Sinatra::Application.settings.connections.each { |out, ids| begin - out << event if ids.include?(id) + out << event if target == 'dashboards' || ids.include?(id) rescue IOError => e # if the socket is closed an IOError is thrown Sinatra::Application.settings.connections.delete(out) end