From 3f58bbd626cd84d1cb24375b4d8fe6df75ce85ba Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Sun, 4 Nov 2012 17:10:36 -0800 Subject: Adding application messaging. While widgets are the most common target for events, there is good reason to sometimes target the application as a whole. This patch adds support for such events using the /-prefixed notation. (This convention is safe for use since it represents an extremely uncommon widget ID, and one which data could not be POSTed to.) Such events are NOT subject to replay, and are handled on the client-side by firing corresponding events on the Dashing application class. As a proof of concept (and to fufill a feature request), this patch also introduces a POST /reload endpoint, which when provided with a valid authkey (and optionally a dashboard name) fires the appropriate 'reload' event on all of the loaded dashboards. The 'reload' event handler then reloads the dashboard, unless a different dashboard was specified. --- javascripts/dashing.coffee | 13 +++++++++++-- lib/dashing.rb | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index ebf5c0a..f90c14b 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -25,6 +25,12 @@ Batman.Filters.shortenedNumber = (num) -> num class window.Dashing extends Batman.App + @on 'reload', (data) -> + if data.dashboard? + location.reload() if window.location.pathname is "/#{data.dashboard}" + else + location.reload() + @root -> Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1)); @@ -83,7 +89,6 @@ Dashing.AnimatedValue = @[k] = num @set k, to , 10 - @[k] = num Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} @@ -98,9 +103,13 @@ source.addEventListener 'error', (e)-> if (e.readyState == EventSource.CLOSED) console.log("Connection closed") -source.addEventListener 'message', (e) => +source.addEventListener 'message', (e) -> data = JSON.parse(e.data) if lastEvents[data.id]?.updatedAt != data.updatedAt + # /messages are internal messages, and cannot correspond to widgets. + # We will handle them as events on the Dashing application. + return Dashing.fire(data.id.slice(1), data) if data.id[0] is '/' + if Dashing.debugMode console.log("Received data for #{data.id}", data) lastEvents[data.id] = data diff --git a/lib/dashing.rb b/lib/dashing.rb index dc62395..4c1b44b 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -81,9 +81,22 @@ get '/views/:widget?.html' do end end +post '/reload' do + request.body.rewind + body = JSON.parse(request.body.read) + auth_token = body.delete("auth_token") + if !settings.auth_token || settings.auth_token == auth_token + send_event('/reload', body) + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + post '/widgets/:id' do request.body.rewind - body = JSON.parse(request.body.read) + body = JSON.parse(request.body.read) auth_token = body.delete("auth_token") if !settings.auth_token || settings.auth_token == auth_token send_event(params['id'], body) @@ -110,7 +123,7 @@ def send_event(id, body) body[:id] = id body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json) - Sinatra::Application.settings.history[id] = event + Sinatra::Application.settings.history[id] = event unless id =~ /^\// Sinatra::Application.settings.connections.each { |out| out << event } end -- cgit v1.2.3 From 5f8cbcb7debde027e79d87733b84cb852aa47dad Mon Sep 17 00:00:00 2001 From: Chad Jolly Date: Sun, 14 Jul 2013 18:36:19 -0600 Subject: dashboard events - use SSE event names --- javascripts/dashing.coffee | 9 +++++---- lib/dashing.rb | 17 ++++++++++------- test/app_test.rb | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index f90c14b..c4178f3 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -106,10 +106,6 @@ source.addEventListener 'error', (e)-> source.addEventListener 'message', (e) -> data = JSON.parse(e.data) if lastEvents[data.id]?.updatedAt != data.updatedAt - # /messages are internal messages, and cannot correspond to widgets. - # We will handle them as events on the Dashing application. - return Dashing.fire(data.id.slice(1), data) if data.id[0] is '/' - if Dashing.debugMode console.log("Received data for #{data.id}", data) lastEvents[data.id] = data @@ -117,6 +113,11 @@ source.addEventListener 'message', (e) -> 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) + Dashing.fire data.event, data $(document).ready -> Dashing.run() diff --git a/lib/dashing.rb b/lib/dashing.rb index 4c1b44b..935a031 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -81,12 +81,13 @@ get '/views/:widget?.html' do end end -post '/reload' do +post '/dashboards/:id' do request.body.rewind body = JSON.parse(request.body.read) + body['dashboard'] ||= params['id'] auth_token = body.delete("auth_token") if !settings.auth_token || settings.auth_token == auth_token - send_event('/reload', body) + send_event(params['id'], body, 'dashboards') 204 # response without entity body else status 401 @@ -119,16 +120,18 @@ def production? ENV['RACK_ENV'] == 'production' end -def send_event(id, body) +def send_event(id, body, target=nil) body[:id] = id body[:updatedAt] ||= Time.now.to_i - event = format_event(body.to_json) - Sinatra::Application.settings.history[id] = event unless id =~ /^\// + event = format_event(body.to_json, target) + Sinatra::Application.settings.history[id] = event unless target == 'dashboards' Sinatra::Application.settings.connections.each { |out| out << event } end -def format_event(body) - "data: #{body}\n\n" +def format_event(body, name=nil) + str = "" + str << "event: #{name}\n" if name + str << "data: #{body}\n\n" end def latest_events diff --git a/test/app_test.rb b/test/app_test.rb index 8b1be19..69e57c9 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -41,6 +41,16 @@ class AppTest < Dashing::Test assert_equal 8, parse_data(@connection[0])['value'] end + def test_dashboard_events + post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) + assert_equal 204, last_response.status + + get '/events' + assert_equal 200, last_response.status + assert_equal 'dashboards', parse_event(@connection[0]) + assert_equal 'reload', parse_data(@connection[0])['event'] + end + def test_redirect_to_default_dashboard with_generated_project do Sinatra::Application.settings.default_dashboard = 'test1' @@ -141,4 +151,8 @@ class AppTest < Dashing::Test def parse_data(string) JSON.parse string[/data: (.+)/, 1] end -end \ No newline at end of file + + def parse_event(string) + string[/event: (.+)/, 1] + end +end -- cgit v1.2.3 From 60dcd73bac913afe0a49b6c6c07b709aa288fd7d Mon Sep 17 00:00:00 2001 From: Chad Jolly Date: Sat, 20 Jul 2013 14:09:51 -0600 Subject: only fire dashboard events when target is current dashboard * send event to all dashboards by including {"dashboard": "*"} in payload * reload event forces reload from server, no caching --- javascripts/dashing.coffee | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index c4178f3..5712e98 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -26,10 +26,7 @@ Batman.Filters.shortenedNumber = (num) -> class window.Dashing extends Batman.App @on 'reload', (data) -> - if data.dashboard? - location.reload() if window.location.pathname is "/#{data.dashboard}" - else - location.reload() + window.location.reload(true) @root -> Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1)); @@ -89,6 +86,7 @@ Dashing.AnimatedValue = @[k] = num @set k, to , 10 + @[k] = num Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} @@ -117,7 +115,8 @@ source.addEventListener 'dashboards', (e) -> data = JSON.parse(e.data) if Dashing.debugMode console.log("Received data for dashboards", data) - Dashing.fire data.event, data + if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}" + Dashing.fire data.event, data $(document).ready -> Dashing.run() -- cgit v1.2.3