From 2a820797694f3c79ecf0c8d0a0c82729c216f93b Mon Sep 17 00:00:00 2001 From: Tyler Mauthe Date: Mon, 22 Feb 2016 00:15:27 -0700 Subject: [PATCH 01/11] :bug: Modify SSE connection handling for Puma - Keep track of events on per-client basis - Clients get a UUID - If a client's event queue grows too big it gets dropped - If a Puma thread tries to send the next batch of events to a client and it's event queue is dropped, the queue will be created - Updated tests to match above changes --- lib/dashing/app.rb | 24 +++++++++++++++++++----- test/app_test.rb | 17 ++++++----------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index b11352d..2ffe036 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -1,4 +1,6 @@ +require 'securerandom' require 'sinatra' +require 'sinatra/streaming' require 'sprockets' require 'sinatra/content_for' require 'rufus/scheduler' @@ -34,7 +36,7 @@ def authenticated?(token) set :sprockets, Sprockets::Environment.new(settings.root) set :assets_prefix, '/assets' set :digest_assets, false -set server: 'thin', connections: [], history_file: 'history.yml' +set server: 'puma', client_events: {}, history_file: 'history.yml' set :public_folder, File.join(settings.root, 'public') set :views, File.join(settings.root, 'dashboards') set :default_dashboard, nil @@ -73,10 +75,15 @@ def authenticated?(token) get '/events', provides: 'text/event-stream' do protected! response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx - stream :keep_open do |out| - settings.connections << out + client_id = SecureRandom.uuid + stream do |out| out << latest_events - out.callback { settings.connections.delete(out) } + loop do + settings.client_events[client_id] = [] unless settings.client_events.has_key?(client_id) + while event = settings.client_events[client_id].shift do + out << event unless out.closed? + end + end end end @@ -138,7 +145,14 @@ def send_event(id, body, target=nil) body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json, target) Sinatra::Application.settings.history[id] = event unless target == 'dashboards' - Sinatra::Application.settings.connections.each { |out| out << event } + max_event_queue_size = Sinatra::Application.settings.history.length * 2 + Sinatra::Application.settings.client_events.each do |connection_id, events| + if events.length > max_event_queue_size + Sinatra::Application.settings.client_events.delete(connection_id) + else + events << event + end + end end def format_event(body, name=nil) diff --git a/test/app_test.rb b/test/app_test.rb index 36cd310..dcf1ae3 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -3,8 +3,7 @@ class AppTest < Dashing::Test def setup - @connection = [] - app.settings.connections = [@connection] + app.settings.client_events = {'tests' => []} app.settings.auth_token = nil app.settings.default_dashboard = nil app.settings.history_file = File.join(Dir.tmpdir, 'history.yml') @@ -49,8 +48,8 @@ def test_post_widgets_without_auth_token post '/widgets/some_widget', JSON.generate({value: 6}) assert_equal 204, last_response.status - assert_equal 1, @connection.length - data = parse_data @connection[0] + assert_equal 1, app.settings.client_events.length + data = parse_data app.settings.client_events.values.first.first assert_equal 6, data['value'] assert_equal 'some_widget', data['id'] assert data['updatedAt'] @@ -72,19 +71,15 @@ def test_get_events post '/widgets/some_widget', JSON.generate({value: 8}) assert_equal 204, last_response.status - get '/events' - assert_equal 200, last_response.status - assert_equal 8, parse_data(@connection[0])['value'] + assert_equal 8, parse_data(app.settings.client_events.values.first.first)['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'] + assert_equal 'dashboards', parse_event(app.settings.client_events.values.first.first) + assert_equal 'reload', parse_data(app.settings.client_events.values.first.first)['event'] end def test_get_dashboard From 64d365c7414d43174c2531a58dc9a0308f35f1b3 Mon Sep 17 00:00:00 2001 From: Tyler Mauthe Date: Sun, 28 Feb 2016 00:38:55 -0700 Subject: [PATCH 02/11] :bug: Properly fix SSE connections in Puma! - Realized that Rufus can also be multi-threaded now - Added a mutex for each connection, allowing safe access during send_event - Don't need to track a queue of events per connection - should lower memory footprint - Connection termination detected by catching Puma::ConnectionError exceptions during send_event conntion writing - Updated tests accordingly --- lib/dashing/app.rb | 31 ++++++++++++++++++++----------- test/app_test.rb | 20 +++++++++++++------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 2ffe036..b85028f 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -36,7 +36,7 @@ def authenticated?(token) set :sprockets, Sprockets::Environment.new(settings.root) set :assets_prefix, '/assets' set :digest_assets, false -set server: 'puma', client_events: {}, history_file: 'history.yml' +set server: 'puma', connections: [], history_file: 'history.yml' set :public_folder, File.join(settings.root, 'public') set :views, File.join(settings.root, 'dashboards') set :default_dashboard, nil @@ -72,18 +72,23 @@ def authenticated?(token) redirect "/" + dashboard end + get '/events', provides: 'text/event-stream' do protected! response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx - client_id = SecureRandom.uuid stream do |out| out << latest_events + settings.connections << connection = {out: out, mutex: Mutex.new, terminated: false} + terminated = false + loop do - settings.client_events[client_id] = [] unless settings.client_events.has_key?(client_id) - while event = settings.client_events[client_id].shift do - out << event unless out.closed? + connection[:mutex].synchronize do + terminated = true if connection[:terminated] end + break if terminated end + + settings.connections.delete(connection) end end @@ -145,12 +150,16 @@ def send_event(id, body, target=nil) body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json, target) Sinatra::Application.settings.history[id] = event unless target == 'dashboards' - max_event_queue_size = Sinatra::Application.settings.history.length * 2 - Sinatra::Application.settings.client_events.each do |connection_id, events| - if events.length > max_event_queue_size - Sinatra::Application.settings.client_events.delete(connection_id) - else - events << event + Sinatra::Application.settings.connections.each do |connection| + connection[:mutex].synchronize do + begin + connection[:out] << event unless connection[:out].closed? + rescue Puma::ConnectionError + connection[:terminated] = true + rescue Exception => e + connection[:terminated] = true + puts e + end end end end diff --git a/test/app_test.rb b/test/app_test.rb index dcf1ae3..353df44 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,9 +1,16 @@ require 'test_helper' require 'haml' +class StreamStub < Array + def closed? + return false + end +end + class AppTest < Dashing::Test def setup - app.settings.client_events = {'tests' => []} + @connection = {out: StreamStub.new, mutex: Mutex.new, terminated: false} + app.settings.connections = [ @connection ] app.settings.auth_token = nil app.settings.default_dashboard = nil app.settings.history_file = File.join(Dir.tmpdir, 'history.yml') @@ -47,9 +54,8 @@ def test_errors_out_when_no_dashboards_available def test_post_widgets_without_auth_token post '/widgets/some_widget', JSON.generate({value: 6}) assert_equal 204, last_response.status - - assert_equal 1, app.settings.client_events.length - data = parse_data app.settings.client_events.values.first.first + assert_equal 1, @connection[:out].length + data = parse_data @connection[:out][0] assert_equal 6, data['value'] assert_equal 'some_widget', data['id'] assert data['updatedAt'] @@ -71,15 +77,15 @@ def test_get_events post '/widgets/some_widget', JSON.generate({value: 8}) assert_equal 204, last_response.status - assert_equal 8, parse_data(app.settings.client_events.values.first.first)['value'] + assert_equal 8, parse_data(@connection[:out][0])['value'] end def test_dashboard_events post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) assert_equal 204, last_response.status - assert_equal 'dashboards', parse_event(app.settings.client_events.values.first.first) - assert_equal 'reload', parse_data(app.settings.client_events.values.first.first)['event'] + assert_equal 'dashboards', parse_event(@connection[:out][0]) + assert_equal 'reload', parse_data(@connection[:out][0])['event'] end def test_get_dashboard From 34ec439d2623125c8e9375208e07d57ed891ec9d Mon Sep 17 00:00:00 2001 From: Tyler Mauthe Date: Sun, 28 Feb 2016 00:42:57 -0700 Subject: [PATCH 03/11] Cleanup imports --- lib/dashing/app.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index b85028f..a1ac50c 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -1,12 +1,11 @@ -require 'securerandom' +require 'coffee-script' +require 'json' +require 'rufus/scheduler' +require 'sass' require 'sinatra' +require 'sinatra/content_for' require 'sinatra/streaming' require 'sprockets' -require 'sinatra/content_for' -require 'rufus/scheduler' -require 'coffee-script' -require 'sass' -require 'json' require 'yaml' require 'thin' From ee64d7df2d5850d723807ab36735f2a80ebe14a3 Mon Sep 17 00:00:00 2001 From: Quentin Brossard Date: Tue, 9 Feb 2016 09:03:59 +0100 Subject: [PATCH 04/11] Switch server to puma, provide puma config and adapt command line - configure puma using config/puma.rb config file - add default puma.rb config file for new projects - adapt dashing cli to use the config file and correctly handle -d (daemonize) arg. - adapt cli_test.rb to the new setup - remove tmp dir from gitignore as we want to generate it in the project template - add tmp/pids/ dir in project template (for saving puma pid / state files. --- .gitignore | 1 - .travis.yml | 3 +- dashing.gemspec | 2 +- lib/dashing/app.rb | 11 ------ lib/dashing/cli.rb | 14 ++++--- templates/project/config/puma.rb | 42 +++++++++++++++++++++ templates/project/tmp/pids/.empty_directory | 1 + test/cli_test.rb | 24 ++++++++---- 8 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 templates/project/config/puma.rb create mode 100644 templates/project/tmp/pids/.empty_directory diff --git a/.gitignore b/.gitignore index 65cbda8..fe7f5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,5 @@ *.gem coverage/ log/ -tmp/ .ruby-version history.yml diff --git a/.travis.yml b/.travis.yml index f68ed76..84155ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,6 @@ rvm: - 2.3.0 - 2.2.4 - 2.1.8 - + - jruby-19mode + - jruby-9.0.4.0 script: "rake test" diff --git a/dashing.gemspec b/dashing.gemspec index 33b5b17..80b7db2 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency('execjs', '~> 2.0.2') s.add_dependency('sinatra', '~> 1.4.4') s.add_dependency('sinatra-contrib', '~> 1.4.2') - s.add_dependency('thin', '~> 1.6.1') + s.add_dependency('puma', '~> 2.16.0') s.add_dependency('rufus-scheduler', '~> 2.0.24') s.add_dependency('thor', '> 0.18.1') s.add_dependency('sprockets', '~> 2.10.1') diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index a1ac50c..f153a33 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -7,7 +7,6 @@ require 'sinatra/streaming' require 'sprockets' require 'yaml' -require 'thin' SCHEDULER = Rufus::Scheduler.new @@ -134,16 +133,6 @@ def authenticated?(token) end end -Thin::Server.class_eval do - def stop_with_connection_closing - Sinatra::Application.settings.connections.dup.each(&:close) - stop_without_connection_closing - end - - alias_method :stop_without_connection_closing, :stop - alias_method :stop, :stop_with_connection_closing -end - def send_event(id, body, target=nil) body[:id] = id body[:updatedAt] ||= Time.now.to_i diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb index 4b93f89..374686a 100644 --- a/lib/dashing/cli.rb +++ b/lib/dashing/cli.rb @@ -57,16 +57,20 @@ def install(gist_id, *args) desc "start", "Starts the server in style!" method_option :job_path, :desc => "Specify the directory where jobs are stored" def start(*args) - port_option = args.include?('-p') ? '' : ' -p 3030' + daemonize = args.include?('-d') args = args.join(' ') - command = "bundle exec thin -R config.ru start#{port_option} #{args}" + command = "bundle exec puma #{args}" command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] + command.prepend "export DAEMONIZE=true; " if daemonize run_command(command) end - desc "stop", "Stops the thin server" - def stop - command = "bundle exec thin stop" + desc "stop", "Stops the puma server (daemon mode only)" + def stop(*args) + args = args.join(' ') + # TODO correctly handle pidfile location change in puma config + daemon_pidfile = !args.include?('--pidfile') ? '--pidfile ./tmp/pids/puma.pid' : args + command = "bundle exec pumactl #{daemon_pidfile} stop" run_command(command) end diff --git a/templates/project/config/puma.rb b/templates/project/config/puma.rb new file mode 100644 index 0000000..26140fa --- /dev/null +++ b/templates/project/config/puma.rb @@ -0,0 +1,42 @@ +# For a complete list of puma configuration parameters, please see +# https://github.com/puma/puma + +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum. +# +threads_count = ENV.fetch("PUMA_MAX_THREADS") { 5 }.to_i +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests, default is 2020. +# +port ENV.fetch("DASHING_PORT") { 3030 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RACK_ENV") { "production" } + +# Daemonize the server into the background. Highly suggest that +# this be combined with "pidfile" and "stdout_redirect". +# +# The default is "false". +# +daemonize ENV.fetch("DAEMONIZE") { false } + +# Store the pid of the server in the file at "path". +# +pidfile './tmp/pids/puma.pid' + +# Use "path" as the file to store the server info state. This is +# used by "pumactl" to query and control the server. +# +state_path './tmp/pids/puma.state' + +# Redirect STDOUT and STDERR to files specified. The 3rd parameter +# ("append") specifies whether the output is appended, the default is +# "false". +# +# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr' +# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr', true \ No newline at end of file diff --git a/templates/project/tmp/pids/.empty_directory b/templates/project/tmp/pids/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/tmp/pids/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/test/cli_test.rb b/test/cli_test.rb index 4d82296..c0efa8d 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -101,14 +101,24 @@ def test_install_task_warns_when_gist_not_found assert_includes output, 'Could not find gist at ' end - def test_start_task_starts_thin_with_default_port - command = 'bundle exec thin -R config.ru start -p 3030 ' + def test_start_task_starts_puma_with_default_port + command = 'bundle exec puma ' @cli.stubs(:run_command).with(command).once @cli.start end - def test_start_task_starts_thin_with_specified_port - command = 'bundle exec thin -R config.ru start -p 2020' + def test_start_task_starts_puma_in_daemon_mode + commands = [ + 'export DAEMONIZE=true; ', + 'bundle exec puma -d' + ] + + @cli.stubs(:run_command).with(commands.join('')).once + @cli.start('-d') + end + + def test_start_task_starts_puma_with_specified_port + command = 'bundle exec puma -p 2020' @cli.stubs(:run_command).with(command).once @cli.start('-p', '2020') end @@ -116,7 +126,7 @@ def test_start_task_starts_thin_with_specified_port def test_start_task_supports_job_path_option commands = [ 'export JOB_PATH=other_spot; ', - 'bundle exec thin -R config.ru start -p 3030 ' + 'bundle exec puma ' ] @cli.stubs(:options).returns(job_path: 'other_spot') @@ -124,8 +134,8 @@ def test_start_task_supports_job_path_option @cli.start end - def test_stop_task_stops_thin_server - @cli.stubs(:run_command).with('bundle exec thin stop') + def test_stop_task_stops_puma_server + @cli.stubs(:run_command).with('bundle exec pumactl --pidfile ./tmp/pids/puma.pid stop') @cli.stop end From e386220b8cd89c74d99552a378d73c0a592df753 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 10:26:23 +0200 Subject: [PATCH 05/11] Disable warnings --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index fc91969..331526a 100644 --- a/Rakefile +++ b/Rakefile @@ -6,6 +6,7 @@ require 'rake/testtask' Rake::TestTask.new(:test) do |test| test.libs << 'lib' << 'test' test.pattern = 'test/**/*_test.rb' + test.warning = false end task :default => [:test] From 19355622bafee1e542af93da25154234a5bf4098 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 10:27:44 +0200 Subject: [PATCH 06/11] Update all gems except Sinatra and Tilt --- smashing.gemspec | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/smashing.gemspec b/smashing.gemspec index d699e85..c526e63 100644 --- a/smashing.gemspec +++ b/smashing.gemspec @@ -15,21 +15,22 @@ Gem::Specification.new do |s| s.files = Dir['README.md', 'javascripts/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] - s.add_dependency('sass', '~> 3.2.12') - s.add_dependency('coffee-script', '~> 2.2.0') - s.add_dependency('execjs', '~> 2.0.2') - s.add_dependency('sinatra', '~> 1.4.4') - s.add_dependency('sinatra-contrib', '~> 1.4.2') - s.add_dependency('puma', '~> 2.16.0') - s.add_dependency('rufus-scheduler', '~> 2.0.24') - s.add_dependency('thor', '~> 0.19') - s.add_dependency('sprockets', '~> 2.10.1') - s.add_dependency('rack', '~> 1.5.4') + s.add_dependency('sass', '~> 3.4.24') + s.add_dependency('coffee-script', '~> 2.4.1') + s.add_dependency('execjs', '~> 2.7.0') + s.add_dependency('sinatra', '~> 1.4.8') + s.add_dependency('sinatra-contrib', '~> 1.4.7') + s.add_dependency('tilt', '~> 1.4.1') + s.add_dependency('puma', '~> 3.8.2') + s.add_dependency('rufus-scheduler', '~> 3.4.2') + s.add_dependency('thor', '~> 0.19.4') + s.add_dependency('sprockets', '~> 3.7.1') - s.add_development_dependency('rake', '~> 10.1.0') - s.add_development_dependency('haml', '~> 4.0.4') - s.add_development_dependency('minitest', '~> 5.2.0') - s.add_development_dependency('mocha', '~> 0.14.0') + s.add_development_dependency('rake', '~> 12.0.0') + s.add_development_dependency('haml', '~> 5.0.1') + s.add_development_dependency('rack-test', '~> 0.6.3') + s.add_development_dependency('minitest', '~> 5.10.2') + s.add_development_dependency('mocha', '~> 1.2.1') s.add_development_dependency('fakeweb', '~> 1.3.0') - s.add_development_dependency('simplecov', '~> 0.8.2') + s.add_development_dependency('simplecov', '~> 0.14.1') end From bd12de67ab3d3c73f1f63d86991ed6fa56166355 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 10:30:05 +0200 Subject: [PATCH 07/11] Modern Ruby hash syntax --- Rakefile | 2 +- lib/dashing/app.rb | 2 +- lib/dashing/cli.rb | 6 +++--- templates/job/%name%.rb | 4 ++-- templates/project/jobs/twitter.rb | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Rakefile b/Rakefile index 331526a..da4603e 100644 --- a/Rakefile +++ b/Rakefile @@ -9,4 +9,4 @@ Rake::TestTask.new(:test) do |test| test.warning = false end -task :default => [:test] +task default: [:test] diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 19792f8..776c982 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -57,7 +57,7 @@ def authenticated?(token) end not_found do - send_file File.join(settings.public_folder, '404.html'), :status => 404 + send_file File.join(settings.public_folder, '404.html'), status: 404 end at_exit do diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb index 374686a..50db83b 100644 --- a/lib/dashing/cli.rb +++ b/lib/dashing/cli.rb @@ -55,7 +55,7 @@ def install(gist_id, *args) end desc "start", "Starts the server in style!" - method_option :job_path, :desc => "Specify the directory where jobs are stored" + method_option :job_path, desc: "Specify the directory where jobs are stored" def start(*args) daemonize = args.include?('-d') args = args.join(' ') @@ -98,10 +98,10 @@ def install_widget_from_gist(gist, skip_overwrite) if file =~ /\.(html|coffee|scss)\z/ widget_name = File.basename(file, '.*') new_path = File.join(Dir.pwd, 'widgets', widget_name, file) - create_file(new_path, details['content'], :skip => skip_overwrite) + create_file(new_path, details['content'], skip: skip_overwrite) elsif file.end_with?('.rb') new_path = File.join(Dir.pwd, 'jobs', file) - create_file(new_path, details['content'], :skip => skip_overwrite) + create_file(new_path, details['content'], skip: skip_overwrite) end end end diff --git a/templates/job/%name%.rb b/templates/job/%name%.rb index 76f221a..c5c00c7 100644 --- a/templates/job/%name%.rb +++ b/templates/job/%name%.rb @@ -1,4 +1,4 @@ # :first_in sets how long it takes before the job is first run. In this case, it is run immediately -SCHEDULER.every '1m', :first_in => 0 do |job| +SCHEDULER.every '1m', first_in: 0 do |job| send_event('widget_id', { }) -end \ No newline at end of file +end diff --git a/templates/project/jobs/twitter.rb b/templates/project/jobs/twitter.rb index 7b2bd6f..0cac98e 100644 --- a/templates/project/jobs/twitter.rb +++ b/templates/project/jobs/twitter.rb @@ -12,7 +12,7 @@ search_term = URI::encode('#todayilearned') -SCHEDULER.every '10m', :first_in => 0 do |job| +SCHEDULER.every '10m', first_in: 0 do |job| begin tweets = twitter.search("#{search_term}") @@ -25,4 +25,4 @@ rescue Twitter::Error puts "\e[33mFor the twitter widget to work, you need to put in your twitter API keys in the jobs/twitter.rb file.\e[0m" end -end \ No newline at end of file +end From 8a51ed3fa7ebbc363dbac3c054914c1700bbaaf2 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 11:03:49 +0200 Subject: [PATCH 08/11] Update to Sinatra 2.0 and Tilt 2.0 --- lib/dashing/app.rb | 20 +++++++------------- smashing.gemspec | 5 ++--- templates/project/config.ru | 5 +++++ 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 776c982..fbefa0b 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -94,9 +94,9 @@ def authenticated?(token) get '/:dashboard' do protected! - tilt_html_engines.each do |suffix, _| - file = File.join(settings.views, "#{params[:dashboard]}.#{suffix}") - return render(suffix.to_sym, params[:dashboard].to_sym) if File.exist? file + settings.template_languages.each do |language| + file = File.join(settings.views, "#{params[:dashboard]}.#{language}") + return render(language, params[:dashboard].to_sym) if File.exist?(file) end halt 404 @@ -129,10 +129,11 @@ def authenticated?(token) get '/views/:widget?.html' do protected! - tilt_html_engines.each do |suffix, engines| - file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") - return engines.first.new(file).render if File.exist? file + settings.template_languages.each do |language| + file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{language}") + return Tilt[language].new(file).render if File.exist?(file) end + "Drats! Unable to find a widget file named: #{params[:widget]} to render." end @@ -173,13 +174,6 @@ def first_dashboard files.sort.first end -def tilt_html_engines - Tilt.mappings.select do |_, engines| - default_mime_type = engines.first.default_mime_type - default_mime_type.nil? || default_mime_type == 'text/html' - end -end - def require_glob(relative_glob) Dir[File.join(settings.root, relative_glob)].each do |file| require file diff --git a/smashing.gemspec b/smashing.gemspec index c526e63..5043886 100644 --- a/smashing.gemspec +++ b/smashing.gemspec @@ -18,9 +18,8 @@ Gem::Specification.new do |s| s.add_dependency('sass', '~> 3.4.24') s.add_dependency('coffee-script', '~> 2.4.1') s.add_dependency('execjs', '~> 2.7.0') - s.add_dependency('sinatra', '~> 1.4.8') - s.add_dependency('sinatra-contrib', '~> 1.4.7') - s.add_dependency('tilt', '~> 1.4.1') + s.add_dependency('sinatra', '~> 2.0.0') + s.add_dependency('sinatra-contrib', '~> 2.0.0') s.add_dependency('puma', '~> 3.8.2') s.add_dependency('rufus-scheduler', '~> 3.4.2') s.add_dependency('thor', '~> 0.19.4') diff --git a/templates/project/config.ru b/templates/project/config.ru index 624244e..5441180 100644 --- a/templates/project/config.ru +++ b/templates/project/config.ru @@ -3,6 +3,11 @@ require 'dashing' configure do set :auth_token, 'YOUR_AUTH_TOKEN' + # See http://www.sinatrarb.com/intro.html > Available Template Languages on + # how to add additional template languages. + set :template_languages, %i[html erb] + template_languages << :haml if defined?(Haml) + helpers do def protected! # Put any authentication code you want in here. From c58925efd80689e53337e608980cdb8fa9c2ec53 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 11:08:24 +0200 Subject: [PATCH 09/11] Facilitate testing --- lib/dashing/app.rb | 1 + templates/project/config.ru | 1 - test/app_test.rb | 9 +++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index fbefa0b..d40cc0a 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -41,6 +41,7 @@ def authenticated?(token) set :views, File.join(settings.root, 'dashboards') set :default_dashboard, nil set :auth_token, nil +set :template_languages, %i[html erb] if File.exists?(settings.history_file) set :history, YAML.load_file(settings.history_file) diff --git a/templates/project/config.ru b/templates/project/config.ru index 5441180..eecd5e0 100644 --- a/templates/project/config.ru +++ b/templates/project/config.ru @@ -6,7 +6,6 @@ configure do # See http://www.sinatrarb.com/intro.html > Available Template Languages on # how to add additional template languages. set :template_languages, %i[html erb] - template_languages << :haml if defined?(Haml) helpers do def protected! diff --git a/test/app_test.rb b/test/app_test.rb index fb76c7f..b23b98b 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -105,6 +105,8 @@ def test_page_title_set_correctly end def test_get_haml_dashboard + app.template_languages << :haml + with_generated_project do |dir| File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') get '/hamltest' @@ -114,6 +116,8 @@ def test_get_haml_dashboard end def test_get_haml_widget + app.template_languages << :haml + with_generated_project do |dir| File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') File.unlink(File.join(dir, 'widgets/clock/clock.html')) @@ -157,6 +161,11 @@ def with_generated_project app.settings.public_folder = File.join(dir, 'new_project/public') app.settings.views = File.join(dir, 'new_project/dashboards') app.settings.root = File.join(dir, 'new_project') + + app.settings.raise_errors = true + app.settings.dump_errors = false + app.settings.show_exceptions = false + yield app.settings.root end end From dc156bc74abae66c18785b03ae00e2387051434e Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 11:12:43 +0200 Subject: [PATCH 10/11] Remove start/stop from CLI There's literally no reason to not just start/stop puma directly. --- README.md | 2 +- lib/dashing/cli.rb | 20 -------------------- test/cli_test.rb | 38 -------------------------------------- 3 files changed, 1 insertion(+), 59 deletions(-) diff --git a/README.md b/README.md index 6ff4065..1aa914b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ $ cd my-project # Install the bundle of project specific gems $ bundle # Start the example dashboard! -$ smashing start +$ puma ``` [Check out our wiki](https://github.com/Smashing/smashing/wiki). diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb index 50db83b..b141187 100644 --- a/lib/dashing/cli.rb +++ b/lib/dashing/cli.rb @@ -54,26 +54,6 @@ def install(gist_id, *args) say set_color("Could not find gist at #{public_url}"), :red end - desc "start", "Starts the server in style!" - method_option :job_path, desc: "Specify the directory where jobs are stored" - def start(*args) - daemonize = args.include?('-d') - args = args.join(' ') - command = "bundle exec puma #{args}" - command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] - command.prepend "export DAEMONIZE=true; " if daemonize - run_command(command) - end - - desc "stop", "Stops the puma server (daemon mode only)" - def stop(*args) - args = args.join(' ') - # TODO correctly handle pidfile location change in puma config - daemon_pidfile = !args.include?('--pidfile') ? '--pidfile ./tmp/pids/puma.pid' : args - command = "bundle exec pumactl #{daemon_pidfile} stop" - run_command(command) - end - desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set." def job(name, auth_token = "") Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require_file(file) } diff --git a/test/cli_test.rb b/test/cli_test.rb index c0efa8d..85191ce 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -101,44 +101,6 @@ def test_install_task_warns_when_gist_not_found assert_includes output, 'Could not find gist at ' end - def test_start_task_starts_puma_with_default_port - command = 'bundle exec puma ' - @cli.stubs(:run_command).with(command).once - @cli.start - end - - def test_start_task_starts_puma_in_daemon_mode - commands = [ - 'export DAEMONIZE=true; ', - 'bundle exec puma -d' - ] - - @cli.stubs(:run_command).with(commands.join('')).once - @cli.start('-d') - end - - def test_start_task_starts_puma_with_specified_port - command = 'bundle exec puma -p 2020' - @cli.stubs(:run_command).with(command).once - @cli.start('-p', '2020') - end - - def test_start_task_supports_job_path_option - commands = [ - 'export JOB_PATH=other_spot; ', - 'bundle exec puma ' - ] - - @cli.stubs(:options).returns(job_path: 'other_spot') - @cli.stubs(:run_command).with(commands.join('')).once - @cli.start - end - - def test_stop_task_stops_puma_server - @cli.stubs(:run_command).with('bundle exec pumactl --pidfile ./tmp/pids/puma.pid stop') - @cli.stop - end - def test_job_task_requires_job_file Dir.stubs(:pwd).returns('') @cli.stubs(:require_file).with('/jobs/special_job.rb').once From 0f46371240fe357b3ea1f4a6e621bcaf2aed660b Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Fri, 26 May 2017 11:20:43 +0200 Subject: [PATCH 11/11] Update travis matrix --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84155ea..efb2a95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: ruby rvm: - - 2.3.0 - - 2.2.4 - - 2.1.8 + - 2.3.4 + - 2.2.7 + - 2.1.10 - jruby-19mode - - jruby-9.0.4.0 -script: "rake test" + - jruby-9.1.10.0 +script: rake test