summaryrefslogtreecommitdiff
path: root/lib/dashing.rb
blob: 8b2af2f01a2bc7bfe084b889b6eb7e4805590e98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
require 'sinatra'
require 'sinatra/content_for'
require 'rufus/scheduler'
require 'coffee-script'
require 'sass'
require 'json'

SCHEDULER = Rufus::Scheduler.start_new

set server: 'thin', connections: [], history: {}
set :public_folder, File.join(Dir.pwd, 'public')
set :views, File.join(Dir.pwd, 'dashboards')
set :default_dashboard, nil
set :auth_token, nil

helpers Sinatra::ContentFor
helpers do
  def protected!
    # override with auth logic
  end
end

get '/events', provides: 'text/event-stream' do
  protected!
  stream :keep_open do |out|
    settings.connections << out
    out << latest_events
    out.callback { settings.connections.delete(out) }
  end
end

get '/' do
  begin
  redirect "/" + (settings.default_dashboard || first_dashboard).to_s
  rescue NoMethodError => e
    raise Exception.new("There are no dashboards in your dashboard directory.")
  end
end

get '/:dashboard' do
  protected!
  erb params[:dashboard].to_sym
end

get '/views/:widget?.html' do
  protected!
  widget = params[:widget]
  send_file File.join(Dir.pwd, 'widgets', widget, "#{widget}.html")
end

post '/widgets/:id' 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(params['id'], body)
    204 # response without entity body
  else
    status 401
    "Invalid API key\n"
  end
end

def framework_javascripts
  ['jquery.js', 'es5-shim.js', 'batman.js', 'batman.jquery.js', 'application.coffee', 'widget.coffee'].collect do |f|
    File.join(File.expand_path('../../vendor/javascripts', __FILE__), f)
  end
end

def widget_javascripts
  asset_paths("/widgets/**/*.coffee")
end

def javascripts
  (framework_javascripts + widget_javascripts).collect do |f|
    if File.extname(f) == ".coffee"
      begin
      CoffeeScript.compile(File.read(f))
      rescue ExecJS::ProgramError => e
        message = e.message + ": in #{f}"
        raise ExecJS::ProgramError.new(message)
      end
    else
      File.read(f)
    end
  end.join("\n")
end

def stylesheets
  asset_paths("/public/**/*.scss", "/widgets/**/*.scss").collect do |f|
    Sass.compile File.read(f)
  end.join("\n")
end

def asset_paths(*paths)
  paths.inject([]) { |arr, path| arr + Dir[File.join(Dir.pwd, path)] }
end

def send_event(id, body)
  body["id"] = id
  event = format_event(JSON.unparse(body))
  settings.history[id] = event
  settings.connections.each { |out| out << event }
end

def format_event(body)
  "data: #{body}\n\n"
end

def latest_events
  settings.history.inject("") do |str, (id, body)|
    str << body
  end
end

def first_dashboard
  files = Dir[File.join(settings.views, '*.erb')].collect { |f| f.match(/(\w*).erb/)[1] }
  files -= ['layout']
  files.first
end

Dir[File.join(Dir.pwd, 'lib', '**', '*.rb')].each {|file| require file }

job_path = ENV["JOB_PATH"] || 'jobs'
files = Dir[File.join(Dir.pwd, job_path, '/*.rb')]
files.each { |job| require(job) }