noah 0.0.5-jruby → 0.1-jruby

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +10 -0
  3. data/LICENSE +201 -0
  4. data/README.md +68 -212
  5. data/Rakefile +65 -41
  6. data/TODO.md +65 -0
  7. data/bin/noah +2 -1
  8. data/bin/noah-watcher.rb +103 -0
  9. data/config.ru +6 -3
  10. data/config/warble.rb +18 -0
  11. data/examples/README.md +116 -0
  12. data/examples/cluster.ru +2 -0
  13. data/examples/custom-watcher.rb +10 -0
  14. data/examples/httpclient-server.rb +7 -0
  15. data/examples/httpclient.rb +12 -0
  16. data/examples/httpclient2.rb +28 -0
  17. data/examples/js/FABridge.js +1452 -0
  18. data/examples/js/WebSocketMain.swf +830 -0
  19. data/examples/js/swfobject.js +851 -0
  20. data/examples/js/web_socket.js +312 -0
  21. data/examples/logger.rb +11 -0
  22. data/examples/reconfiguring-sinatra-watcher.rb +11 -0
  23. data/examples/reconfiguring-sinatra.rb +33 -0
  24. data/examples/simple-post.rb +17 -0
  25. data/examples/websocket.html +24 -0
  26. data/examples/websocket.rb +41 -0
  27. data/lib/noah.rb +6 -8
  28. data/lib/noah/app.rb +20 -268
  29. data/lib/noah/application_routes.rb +70 -0
  30. data/lib/noah/ark.rb +0 -0
  31. data/lib/noah/configuration_routes.rb +81 -0
  32. data/lib/noah/custom_watcher.rb +79 -0
  33. data/lib/noah/ephemeral_routes.rb +47 -0
  34. data/lib/noah/helpers.rb +37 -14
  35. data/lib/noah/host_routes.rb +69 -0
  36. data/lib/noah/models.rb +86 -5
  37. data/lib/noah/models/applications.rb +41 -0
  38. data/lib/noah/models/configurations.rb +49 -0
  39. data/lib/noah/models/ephemerals.rb +54 -0
  40. data/lib/noah/models/hosts.rb +56 -0
  41. data/lib/noah/models/services.rb +54 -0
  42. data/lib/noah/models/watchers.rb +62 -0
  43. data/lib/noah/passthrough.rb +11 -0
  44. data/lib/noah/service_routes.rb +71 -0
  45. data/lib/noah/validations.rb +1 -0
  46. data/lib/noah/validations/watcher_validations.rb +48 -0
  47. data/lib/noah/version.rb +1 -1
  48. data/lib/noah/watcher_routes.rb +45 -0
  49. data/noah.gemspec +25 -17
  50. data/spec/application_spec.rb +30 -30
  51. data/spec/configuration_spec.rb +78 -14
  52. data/spec/ephemeral_spec.rb +59 -0
  53. data/spec/host_spec.rb +21 -21
  54. data/spec/noahapp_application_spec.rb +6 -6
  55. data/spec/noahapp_configuration_spec.rb +5 -5
  56. data/spec/noahapp_ephemeral_spec.rb +115 -0
  57. data/spec/noahapp_host_spec.rb +3 -3
  58. data/spec/noahapp_service_spec.rb +10 -10
  59. data/spec/noahapp_watcher_spec.rb +123 -0
  60. data/spec/service_spec.rb +27 -27
  61. data/spec/spec_helper.rb +13 -22
  62. data/spec/support/db/.keep +0 -0
  63. data/spec/support/test-redis.conf +8 -0
  64. data/spec/watcher_spec.rb +62 -0
  65. data/views/index.haml +21 -15
  66. metadata +189 -146
  67. data/Gemfile.lock +0 -83
  68. data/doc/coverage/index.html +0 -138
  69. data/doc/coverage/jquery-1.3.2.min.js +0 -19
  70. data/doc/coverage/jquery.tablesorter.min.js +0 -15
  71. data/doc/coverage/lib-helpers_rb.html +0 -393
  72. data/doc/coverage/lib-models_rb.html +0 -1449
  73. data/doc/coverage/noah_rb.html +0 -2019
  74. data/doc/coverage/print.css +0 -12
  75. data/doc/coverage/rcov.js +0 -42
  76. data/doc/coverage/screen.css +0 -270
  77. data/lib/noah/applications.rb +0 -46
  78. data/lib/noah/configurations.rb +0 -49
  79. data/lib/noah/hosts.rb +0 -54
  80. data/lib/noah/services.rb +0 -57
  81. data/lib/noah/watchers.rb +0 -18
data/Rakefile CHANGED
@@ -1,48 +1,70 @@
1
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib")))
1
2
  require 'bundler'
2
- begin
3
- Bundler.setup(:default, :development)
4
- rescue Bundler::BundlerError => e
5
- $stderr.puts e.message
6
- $stderr.puts "Run `bundle install` to install missing gems"
7
- exit e.status_code
8
- end
9
- require 'rake'
10
-
11
3
  require 'rspec/core'
12
4
  require 'rspec/core/rake_task'
13
5
 
6
+ REDIS_DIR = File.expand_path(File.join("..", "spec", "support"), __FILE__)
7
+ REDIS_CNF = File.join(REDIS_DIR, "test-redis.conf")
8
+
14
9
  Bundler::GemHelper.install_tasks
10
+ RSpec::Core::RakeTask.new(:spec) do |spec|
11
+ spec.pattern = FileList['spec/**/*_spec.rb']
12
+ end
13
+
14
+
15
+ task :default => :run
16
+ task :test => :run
17
+
18
+ desc "Run tests and manage server start/stop"
19
+ task :run => [:start, :spec, :stop]
20
+
21
+ task :start do
22
+ puts "Starting redis-server"
23
+ system "redis-server #{REDIS_CNF}"
24
+ end
25
+
26
+ task :stop do
27
+ puts "Killing redis"
28
+ system "killall -TERM redis-server"
29
+ end
30
+
31
+ namespace :coverage do
32
+ task(:clean) { rm_f "coverage.data" }
33
+ end
34
+ RSpec::Core::RakeTask.new(:coverage) do |t|
35
+ t.rcov = true
36
+ t.verbose = true
37
+ t.rcov_opts = %q[--aggregate coverage.data --sort coverage --text-report --exclude "config,.bundle/*,gems/*,spec/*" -o doc/coverage -Ilib -i "noah.rb"]
38
+ end
15
39
 
16
40
  desc "Populate database with sample dataset"
17
41
  task :sample, :redis_url do |t, args|
18
- require 'ohm'
19
- begin
20
- require 'yajl'
21
- rescue LoadError
22
- require 'json'
23
- end
24
- require File.join(File.dirname(__FILE__), 'lib','noah')
42
+ require 'noah'
25
43
 
26
-
27
44
  Ohm::connect(:url => args.redis_url)
28
45
  Ohm::redis.flushdb
46
+ puts "Creating watchers..."
47
+ Noah::Watcher.create :endpoint => "http://localhost:3000/webhook", :pattern => "//noah/application"
48
+ Noah::Watcher.create :endpoint => "http://localhost:3001/webhook", :pattern => "//noah/configuration"
49
+ Noah::Watcher.create :endpoint => "http://localhost:3002/webhook", :pattern => "//noah/host"
50
+ Noah::Watcher.create :endpoint => "http://localhost:3003/webhook", :pattern => "//noah/service"
29
51
  puts "Creating Host entry for 'localhost'"
30
- h = Host.create(:name => 'localhost', :status => "up")
52
+ h = Noah::Host.create(:name => 'localhost', :status => "up")
31
53
  if h.save
32
54
  %w[redis noah].each do |service|
33
55
  puts "Create Service entry for #{service}"
34
- s = Service.create(:name => service, :status => "up", :host => h)
56
+ s = Noah::Service.create(:name => service, :status => "up", :host => h)
35
57
  h.services << s
36
58
  end
37
59
  end
38
60
 
39
61
  puts "Creating Application entry for 'noah'"
40
- a = Application.create(:name => 'noah')
62
+ a = Noah::Application.create(:name => 'noah')
41
63
  if a.save
42
64
  puts "Creating Configuration entry for 'noah'"
43
- cr = Configuration.create(:name => 'redis', :format => 'string', :body => 'redis://127.0.0.1:6379/0', :application => a)
44
- ch = Configuration.create(:name => 'host', :format => 'string', :body => 'localhost', :application => a)
45
- cp = Configuration.create(:name => 'port', :format => 'string', :body => '9292', :application => a)
65
+ cr = Noah::Configuration.create(:name => 'redis', :format => 'string', :body => 'redis://127.0.0.1:6379/0', :application => a)
66
+ ch = Noah::Configuration.create(:name => 'host', :format => 'string', :body => 'localhost', :application => a)
67
+ cp = Noah::Configuration.create(:name => 'port', :format => 'string', :body => '9292', :application => a)
46
68
  %w[cr ch cp].each do |c|
47
69
  a.configurations << eval(c)
48
70
  end
@@ -50,10 +72,10 @@ task :sample, :redis_url do |t, args|
50
72
 
51
73
  puts "Creating sample entries - Host and Service"
52
74
  %w[host1.domain.com host2.domain.com host3.domain.com].each do |host|
53
- h = Host.create(:name => host, :status => "up")
75
+ h = Noah::Host.create(:name => host, :status => "up")
54
76
  if h.save
55
77
  %w[http https smtp mysql].each do |service|
56
- s = Service.create(:name => service, :status => "pending", :host => h)
78
+ s = Noah::Service.create(:name => service, :status => "pending", :host => h)
57
79
  h.services << s
58
80
  end
59
81
  end
@@ -74,32 +96,34 @@ EOY
74
96
  }
75
97
  EOJ
76
98
 
77
- a1 = Application.create(:name => 'myrailsapp1')
99
+ a1 = Noah::Application.create(:name => 'myrailsapp1')
78
100
  if a1.save
79
- c1 = Configuration.create(:name => 'database.yml', :format => 'yaml', :body => my_yaml, :application => a1)
101
+ c1 = Noah::Configuration.create(:name => 'database.yml', :format => 'yaml', :body => my_yaml, :application => a1)
80
102
  a1.configurations << c1
81
103
  end
82
104
 
83
- a2 = Application.create(:name => 'myrestapp1')
105
+ a2 = Noah::Application.create(:name => 'myrestapp1')
84
106
  if a2.save
85
- c2 = Configuration.create(:name => 'config.json', :format => 'json', :body => my_json, :application => a2)
107
+ c2 = Noah::Configuration.create(:name => 'config.json', :format => 'json', :body => my_json, :application => a2)
86
108
  a2.configurations << c2
87
109
  end
88
110
  puts "Sample data populated!"
89
111
  end
90
-
91
112
 
92
- RSpec::Core::RakeTask.new(:spec) do |spec|
93
- spec.pattern = FileList['spec/**/*_spec.rb']
113
+ begin
114
+ require 'yard'
115
+ require 'yard/sinatra'
116
+ desc "Generate documentation"
117
+ YARD::Rake::YardocTask.new do |t|
118
+ t.files = ['lib/**/*.rb'] # optional
119
+ t.options = ['--title', "Noah #{Noah::VERSION} Documentation"]
120
+ t.options += ['--plugin', "yard-sinatra"]
121
+ t.options += ['--protected', '--private'] # optional
122
+ end
123
+ rescue LoadError
124
+ "You need YARD installed to generate docs"
94
125
  end
95
126
 
96
- namespace :coverage do
97
- desc "Delete aggregate coverage data."
98
- task(:clean) { rm_f "coverage.data" }
99
- end
100
- desc "Run Rcov code coverage analysis"
101
- RSpec::Core::RakeTask.new(:coverage) do |t|
102
- t.rcov = true
103
- t.verbose = true
104
- t.rcov_opts = %q[--aggregate coverage.data --sort coverage --text-report --exclude "config,.bundle/*,gems/*,spec/*" -o doc/coverage -Ilib -i "noah.rb"]
127
+ task :start_demo do
128
+ puts "Soon, young padawan"
105
129
  end
data/TODO.md ADDED
@@ -0,0 +1,65 @@
1
+ # Brain dump of stuff
2
+ * Fix JRuby
3
+
4
+ This is an ongoing issue for me. I can't rely on stuff that's MRI only.
5
+
6
+ * Break agent into separate gem
7
+
8
+ Again so that the server gem can be as lean as possible
9
+
10
+ * Documentation
11
+
12
+ Need to finish documenting everything for YARD to pick up.
13
+
14
+ * Stabilize API
15
+
16
+ I'm seriously considering moving to a single endpoint with JSON request bodies. Still up in the air. I'm not totally sold on the current layout.
17
+
18
+ * Write my own CLI class
19
+
20
+ I think I might be bumping into some issues related to Vegas as well.
21
+
22
+ * Watchers
23
+
24
+ **IN PROGRESS**
25
+ Need to resolve some issues around pathing for Configuration and Service nodes however watch registration and listing are up.
26
+ Need to address alternative watcher URIs. Webhook is the only one supported right now.
27
+
28
+ * Ephemeral nodes
29
+
30
+ **IN PROGRESS**
31
+ implement lifetime support
32
+
33
+ * Examples
34
+
35
+ Pretty happy with the examples I have but I need more. Want some in other languages - Python, Java, whatever!
36
+
37
+ * Clean up deps
38
+
39
+ Feels like I'm relying too much on external libraries.
40
+
41
+ * Benchmark
42
+
43
+ Need some client libs for this
44
+
45
+ # Done TODOS
46
+ * Github pages
47
+ - see [[http://lusis.github.com/Noah/]]
48
+
49
+ * Examples
50
+ - Sort of done. Demo app is up! [[http://noah-demo.heroku.com/]]. Also see `examples` directory.
51
+
52
+ * Consider ditching Sinatra::Namespace
53
+ - Done. It was also causing issues with YARD generation. @rkh confirmed known issue via twitter.
54
+
55
+ * Namespace models
56
+ - Done.
57
+
58
+ * Watchers
59
+ - Done. GET PUT DELETE are all available at the '/w/' endpoint now!
60
+
61
+
62
+ ## Watcher specific stuff
63
+ * Implement AMQP
64
+ * Implement REST
65
+ * Implement JMX on JRuby
data/bin/noah CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
3
+ require 'rubygems'
3
4
  require 'noah'
4
5
  require 'vegas'
5
6
 
6
7
  Vegas::Runner.new(Noah::App, 'noah') do |runner, opts, app|
7
- opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r }
8
+ opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r; Noah::App.set :redis_url, r }
8
9
  end
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
3
+ HELP = <<-EOH
4
+ Unfortunately, the agent script has some difficult requirements right now.
5
+ Please see https://github.com/lusis/Noah/Watcher-Agent for details.
6
+ EOH
7
+ begin
8
+ require 'rubygems'
9
+ require 'logger'
10
+ require 'optparse'
11
+ require 'em-hiredis'
12
+ require 'eventmachine'
13
+ require 'em-http-request'
14
+ require 'noah'
15
+ require 'json'
16
+ rescue LoadError
17
+ puts HELP
18
+ exit
19
+ end
20
+
21
+ LOGGER = Logger.new(STDOUT)
22
+
23
+ class EventMachine::NoahAgent
24
+ include EM::Deferrable
25
+
26
+ @@watchers = Noah::Watcher.watch_list
27
+
28
+ def initialize
29
+ @logger = LOGGER
30
+ @logger.debug("Initializing with #{@@watchers.size} registered watches")
31
+ if EventMachine.reactor_running?
32
+ @worker = EM.spawn {|event, message, watch_list|
33
+ logger = LOGGER
34
+ logger.info("Worker initiated")
35
+ logger.debug("got event on http worker: #{event}")
36
+ matches = watch_list.find_all{|w| event =~ /^#{Base64.decode64(w)}/}
37
+ logger.debug("Found #{matches.size} matches for #{event}")
38
+ EM::Iterator.new(matches).each do |watch, iter|
39
+ p, ep = Base64.decode64(watch).split("|")
40
+ logger.info("Sending message to: #{ep} for pattern: #{p}")
41
+ http = EM::HttpRequest.new(ep, :connection_timeout => 2, :inactivity_timeout => 4).post :body => message
42
+ http.callback {
43
+ logger.info("Message posted to #{ep} successfully")
44
+ }
45
+ http.errback {
46
+ logger.error("Something went wrong")
47
+ }
48
+ iter.next
49
+ end
50
+ }
51
+ self.succeed("Succeed callback")
52
+ else
53
+ logger.fatal("Must be inside a reactor!")
54
+ end
55
+ end
56
+
57
+ def watchers
58
+ @@watchers.size
59
+ end
60
+
61
+ def reread_watchers
62
+ @logger.debug("Found new watches")
63
+ @logger.debug("Current watch count: #{@@watchers.size}")
64
+ @@watchers = Noah::Watcher.watch_list
65
+ @logger.debug("New watch count: #{@@watchers.size}")
66
+ #@logger.debug(@@watchers)
67
+ end
68
+
69
+ def broker(msg)
70
+ # This is just for testing for now
71
+ e,m = msg.split("|")
72
+ be = Base64.encode64(e).gsub("\n","")
73
+ @worker.notify e, m, @@watchers.clone
74
+ end
75
+ end
76
+
77
+ EventMachine.run do
78
+ EM.error_handler do |e|
79
+ Logger.new(STDOUT).warn(e)
80
+ end
81
+ logger = LOGGER
82
+ trap("INT") { logger.debug("Shutting down. Watches will not be fired");EM.stop }
83
+ noah = EventMachine::NoahAgent.new
84
+ noah.errback{|x| logger.error("Errback: #{x}")}
85
+ noah.callback{|y| logger.info("Callback: #{y}")}
86
+ # Passing messages...like a boss
87
+ master_channel = EventMachine::Channel.new
88
+
89
+ r = EventMachine::Hiredis::Client.connect
90
+ r.errback{|x| logger.error("Unable to connect to redis: #{x}")}
91
+ logger.debug("Starting up")
92
+ r.psubscribe("//noah/*")
93
+ r.on(:pmessage) do |pattern, event, message|
94
+ noah.reread_watchers if event =~ /^\/\/noah\/watcher\/.*/
95
+ master_channel.push "#{event}|#{message}"
96
+ logger.debug("Saw[#{event}]")
97
+ end
98
+
99
+ sub = master_channel.subscribe {|msg|
100
+ # We short circuit if we have no watchers
101
+ noah.broker(msg) unless noah.watchers == 0
102
+ }
103
+ end
data/config.ru CHANGED
@@ -1,3 +1,6 @@
1
- require File.join(File.dirname(__FILE__), 'lib','noah')
2
- ENV['REDIS_URL'] = "redis://localhost:6379/0"
3
- run Noah::App
1
+ require 'rubygems'
2
+ require File.join('.', 'lib','noah')
3
+ ## Uncomment the following to hardcode a redis url
4
+ ENV['REDIS_URL'] = "redis://localhost:6379/1"
5
+ noah = Noah::App.new
6
+ run noah
data/config/warble.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Disable automatic framework detection by uncommenting/setting to false
2
+ # Warbler.framework_detection = false
3
+
4
+ # Warbler web application assembly configuration file
5
+ Warbler::Config.new do |config|
6
+ #config.features = %w(gemjar)
7
+ config.dirs = %w(config lib views)
8
+ config.includes = FileList["config.ru"]
9
+ config.excludes = FileList["noah.gemspec", "Gemfile", "Gemfile.lock"]
10
+ config.bundler = false
11
+ config.gems += ["json", "ohm", "ohm-contrib", "sinatra", "sinatra-namespace", "haml"]
12
+ config.gem_excludes = [/^(test|spec)\//]
13
+ config.public_html = FileList["views/**/*"]
14
+ config.webxml.booter = :rack
15
+ #config.webxml.rackup.path = 'WEB-INF/config.ru'
16
+ #config.webxml.rackup = %{require './lib/noah'; run Noah::App}
17
+ # config.webxml.rackup = require 'cgi' && CGI::escapeHTML(File.read("config.ru"))
18
+ end
@@ -0,0 +1,116 @@
1
+ # Examples
2
+ The following is a list of notes regarding the examples in this directory.
3
+
4
+ ## General Requirements
5
+
6
+ You'll need a few additional gems
7
+
8
+ * [em-hiredis](https://github.com/mloughran/em-hiredis)
9
+ You'll have to compile/install from source. Sorry. Should pull in the `hiredis` native ext.
10
+ * [em-http-request](https://github.com/igrigorik/em-http-request)
11
+ Available via rubygems
12
+ * [em-websocket](https://github.com/igrigorik/em-websocket)
13
+ Available via rubygems
14
+
15
+ ## custom-watcher.rb
16
+ This is an idea I'm tossing around for allowing easy custom watchers to be written.
17
+ Essentially the idea is that you tap into the Redis subscription with a defined pattern and a destination.
18
+
19
+ ### Example
20
+
21
+ require './watcher-idea.rb'
22
+
23
+ Noah::Watcher.watch do
24
+ pattern "//noah/configuration/*"
25
+ destination Proc.new {|x| something_with(x)}
26
+ run!
27
+ end
28
+
29
+ ## logger.rb
30
+ An example using logger as a watcher. Pretty straighforward.
31
+
32
+
33
+ ## httpclient.rb/httpclient-server.rb
34
+ This is an example of how the Webhook system would work
35
+
36
+ ### Running
37
+
38
+ To get the maximum effect, start with a clean Redis database
39
+
40
+ * Start the webhook reciever
41
+
42
+ noah/examples$ ruby httpclient-server.rb
43
+ == Sinatra/1.1.2 has taken the stage on 4567 for development with backup from Thin
44
+ >> Thin web server (v1.2.7 codename No Hup)
45
+ >> Maximum connections set to 1024
46
+ >> Listening on 0.0.0.0:4567, CTRL+C to stop
47
+
48
+ * Start the webhook publisher
49
+
50
+ noah/examples$ ruby httpclient.rb
51
+
52
+ * Run the rake sample script
53
+
54
+ In the publisher window, you should see some messages like so:
55
+
56
+ Got message for noah.Host[localhost].create
57
+ Got message for noah.Host[localhost].save
58
+ Got message for noah.Host[localhost].save
59
+ Got message for noah.Host[localhost].update
60
+
61
+ In the server window, you should see the following:
62
+
63
+ "{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
64
+ 127.0.0.1 - - [15/Feb/2011 00:19:05] "POST /webhook HTTP/1.1" 200 135 0.0024
65
+ "{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
66
+ 127.0.0.1 - - [15/Feb/2011 00:19:05] "POST /webhook HTTP/1.1" 200 135 0.0004
67
+ "{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
68
+
69
+
70
+ ## websocket.rb
71
+ This is an example of using Websockets, EventMachine and Redis PubSub to provide a "status" console of sorts.
72
+
73
+ ### Running
74
+
75
+ To get the maximum effect, start with a clean Redis database.
76
+
77
+ * Start the server:
78
+
79
+ ~/development/noah/examples$ ./websocket.rb
80
+ >> Thin web server (v1.2.7 codename No Hup)
81
+ >> Maximum connections set to 1024
82
+ >> Listening on 0.0.0.0:3000, CTRL+C to stop
83
+
84
+ You should be able to load up the "normal" Noah sample page on [http://localhost:3000].
85
+
86
+ * Load the "websocket" file
87
+
88
+ In another browser window, open the `websocket.html` file.
89
+
90
+ * Send a message
91
+
92
+ From another terminal window send the following:
93
+
94
+ curl -X PUT -d '{"name":"testhost2","status":"down"}' http://localhost:3000/h/testhost2
95
+
96
+ You should see the message come across in the browser window like so:
97
+
98
+ connected...
99
+
100
+ 2 connected and waiting....
101
+
102
+ (noah.Host[testhost2].create) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
103
+
104
+ (noah.Host[testhost2].save) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
105
+
106
+ (noah.Host[testhost2].save) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
107
+
108
+ (noah.Host[testhost2].update) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
109
+
110
+ You can see the Watcher pattern in the parenthesis and then the JSON message body.
111
+
112
+ For fun, refresh the page to clear it and then run the sample data population rake task.
113
+
114
+ ### Known issues
115
+ When I started working on the Watcher stuff, I realized that I'm sending A LOT of extranous messages. These are mostly the result of the way I'm creating new objects with Ohm (i.e. via `.create`).
116
+ I'll be cleaning that up and trying to get down to a single message per operation.