gom-script 0.1.2
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.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.markdown +31 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/lib/gom-script.rb +1 -0
- data/lib/gom/remote.rb +8 -0
- data/lib/gom/remote/connection.rb +194 -0
- data/lib/gom/remote/daemon.rb +78 -0
- data/lib/gom/remote/entry.rb +27 -0
- data/lib/gom/remote/http_server.rb +124 -0
- data/lib/gom/remote/subscription.rb +38 -0
- data/spec/gom/remote/connection_spec.rb +109 -0
- data/spec/gom/remote/daemon_spec.rb +57 -0
- data/spec/gom/remote/http_server_spec.rb +106 -0
- data/spec/gom/remote/subscription_spec.rb +48 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +48 -0
- metadata +127 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 art+com AG/dirk luesebrink
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# GOM Script
|
2
|
+
|
3
|
+
Easy access over the wire to a remote GOM node. This gem includes a GNP
|
4
|
+
callback server, support for automatic observer refreshments and command line
|
5
|
+
tools for reading, writing and observing GOM entries.
|
6
|
+
|
7
|
+
|
8
|
+
## Install
|
9
|
+
|
10
|
+
use the jewler tasks:
|
11
|
+
|
12
|
+
$ rake gemspec build install
|
13
|
+
|
14
|
+
## Dependencies
|
15
|
+
|
16
|
+
## credits
|
17
|
+
|
18
|
+
## Note on Patches/Pull Requests
|
19
|
+
|
20
|
+
* Fork the project.
|
21
|
+
* Make your feature addition or bug fix.
|
22
|
+
* Add tests for it. This is important so I don't break it in a
|
23
|
+
future version unintentionally.
|
24
|
+
* Commit, do not mess with rakefile, version, or history.
|
25
|
+
(if you want to have your own version, that is fine but
|
26
|
+
bump version in a commit by itself I can ignore when I pull)
|
27
|
+
* Send me a pull request. Bonus points for topic branches.
|
28
|
+
|
29
|
+
## Copyright
|
30
|
+
|
31
|
+
Copyright (c) 2009 art+com AG/dirk luesebrink. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
# gem is a Gem::Specification... see
|
8
|
+
# http://www.rubygems.org/read/chapter/20 for additional settings
|
9
|
+
#
|
10
|
+
gem.name = "gom-script"
|
11
|
+
gem.summary = %Q{connecting scripts and daemons with a remote GOM instance}
|
12
|
+
gem.description = %Q{
|
13
|
+
GOM is a schema-less object database in ruby with Resource Oriented API,
|
14
|
+
server-side javascript, distributed HTTP notifications and some more.
|
15
|
+
This gom-script script simplifies coding of clients and daemon which like
|
16
|
+
to listen on state change event in the GOM.
|
17
|
+
}.gsub /\n\n/, ''
|
18
|
+
gem.email = "dirk.luesebrink@gmail.com"
|
19
|
+
gem.homepage = "http://github.com/crux/gom-script"
|
20
|
+
gem.authors = ["art+com/dirk luesebrink"]
|
21
|
+
gem.add_runtime_dependency "applix", ">=0.2.1"
|
22
|
+
gem.add_runtime_dependency "rack"
|
23
|
+
gem.add_runtime_dependency "gom-core"
|
24
|
+
|
25
|
+
gem.add_development_dependency "rspec"
|
26
|
+
gem.add_development_dependency "fakeweb", ">=1.2.7"
|
27
|
+
end
|
28
|
+
rescue LoadError
|
29
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'spec/rake/spectask'
|
33
|
+
desc "Run all specs in spec directory"
|
34
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
35
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
36
|
+
t.spec_opts = %w(-c)
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
require 'rcov/rcovtask'
|
41
|
+
Rcov::RcovTask.new do |test|
|
42
|
+
test.libs << 'test'
|
43
|
+
test.pattern = 'spec/**/*_spec.rb'
|
44
|
+
test.verbose = true
|
45
|
+
end
|
46
|
+
rescue LoadError
|
47
|
+
task :rcov do
|
48
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'rake/rdoctask'
|
53
|
+
Rake::RDocTask.new do |rdoc|
|
54
|
+
if File.exist?('VERSION')
|
55
|
+
version = File.read('VERSION')
|
56
|
+
else
|
57
|
+
version = ""
|
58
|
+
end
|
59
|
+
|
60
|
+
rdoc.rdoc_dir = 'rdoc'
|
61
|
+
rdoc.title = "GOM Remote - #{version}"
|
62
|
+
rdoc.rdoc_files.include('README*')
|
63
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
64
|
+
end
|
65
|
+
|
66
|
+
task :test => :check_dependencies
|
67
|
+
task :default => :spec
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.2
|
data/lib/gom-script.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'gom/remote'
|
data/lib/gom/remote.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Gom
|
6
|
+
module Remote
|
7
|
+
|
8
|
+
class << self; attr_accessor :connection; end
|
9
|
+
|
10
|
+
class Connection
|
11
|
+
|
12
|
+
attr_reader :target_url, :initial_path, :callback_server
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# take apart the URL into GOM and node path part
|
16
|
+
def split_url url
|
17
|
+
u = URI.parse url
|
18
|
+
re = %r|#{u.scheme}://#{u.host}(:#{u.port})?|
|
19
|
+
server = (re.match url).to_s
|
20
|
+
path = (url.sub server, '').sub(/\/$/, '')
|
21
|
+
[server, path]
|
22
|
+
end
|
23
|
+
|
24
|
+
def init url, callback_port = nil
|
25
|
+
connection = (self.new url, callback_port)
|
26
|
+
[connection, connection.initial_path]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# url: initial GOM url, path or attribute. The remote GOM server
|
31
|
+
# address gets extracted from this and, unless nil, the given block
|
32
|
+
# will be called with the remaining GOM path, aka:
|
33
|
+
#
|
34
|
+
# url == http://gom:1234/foo/bar:attribute
|
35
|
+
#
|
36
|
+
# will use 'http://gom:1234' as GOM server and call the block with
|
37
|
+
# '/foo/bar:attribute' as path argument.
|
38
|
+
#
|
39
|
+
def initialize url, callback_port = nil
|
40
|
+
@target_url, @initial_path = (Connection.split_url url)
|
41
|
+
#Gom::Remote.connection and (raise "connection already open")
|
42
|
+
Gom::Remote.connection = self
|
43
|
+
|
44
|
+
@subscriptions = []
|
45
|
+
@callback_server = init_callback_server callback_port
|
46
|
+
end
|
47
|
+
|
48
|
+
def write path, value
|
49
|
+
if value.kind_of? Hash
|
50
|
+
write_node path, attributes
|
51
|
+
else
|
52
|
+
write_attribute path, value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_attribute path, value
|
57
|
+
# TODO: Primitive#encode returns to_s for all unknow types. exception
|
58
|
+
# would be correct.
|
59
|
+
txt, type = (Gom::Core::Primitive.encode value)
|
60
|
+
params = { "attribute" => txt, "type" => type }
|
61
|
+
url = "#{@target_url}#{path}"
|
62
|
+
http_put(url, params)
|
63
|
+
end
|
64
|
+
|
65
|
+
def write_node path, attributes
|
66
|
+
raise "not yet implemented"
|
67
|
+
end
|
68
|
+
|
69
|
+
def read path
|
70
|
+
url = "#{@target_url}#{path}"
|
71
|
+
open(url).read
|
72
|
+
rescue Timeout::Error => e
|
73
|
+
raise "connection timeout: #{url}"
|
74
|
+
rescue OpenURI::HTTPError => e
|
75
|
+
case code = e.to_s.to_i rescue 0
|
76
|
+
when 404
|
77
|
+
raise NameError, "undefined: #{path}"
|
78
|
+
else
|
79
|
+
puts " ## gom connection error: #{url} -- #{e}"
|
80
|
+
throw e
|
81
|
+
end
|
82
|
+
rescue => e
|
83
|
+
puts " ## read error: #{url} -- #{e}"
|
84
|
+
throw e
|
85
|
+
end
|
86
|
+
|
87
|
+
# update subscription observers. GNP callbacks will look like:
|
88
|
+
#
|
89
|
+
# http://<callback server>:<callback port>/gnp;<subscription name>;<subscription path>
|
90
|
+
#
|
91
|
+
def refresh
|
92
|
+
puts " -- refresh subscriptions(#{@subscriptions.size}):"
|
93
|
+
|
94
|
+
run_callback_server # call it once to make sure it runs
|
95
|
+
|
96
|
+
@subscriptions.each do |sub|
|
97
|
+
puts " - #{sub.name}"
|
98
|
+
params = { "attributes[accept]" => 'application/json' }
|
99
|
+
|
100
|
+
query = "/gnp;#{sub.name};#{sub.entry_uri}"
|
101
|
+
params["attributes[callback_url]"] = "#{callback_server.base_url}#{query}"
|
102
|
+
|
103
|
+
[:operations, :uri_regexp, :condition_script].each do |key|
|
104
|
+
(v = sub.send key) and params["attributes[#{key}]"] = v
|
105
|
+
end
|
106
|
+
|
107
|
+
url = "#{@target_url}#{sub.uri}"
|
108
|
+
http_put(url, params) # {|req| req.content_type = 'application/json'}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def subscribe sub
|
113
|
+
@subscriptions.delete sub # every sub only once!
|
114
|
+
@subscriptions.push sub
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def init_callback_server port
|
120
|
+
txt = (read "/gom/config/connection.txt")
|
121
|
+
unless m = (txt.match /^client_ip:\s*(\d+\.\d+\.\d+\.\d+)/)
|
122
|
+
raise "/gom/config/connection: No Client IP? '#{txt}'"
|
123
|
+
end
|
124
|
+
# this is the IP by which i am seen from the GOM
|
125
|
+
ip = m[1]
|
126
|
+
|
127
|
+
http = (HttpServer.new :host => ip, :port => port)
|
128
|
+
http.mount "^/gnp;", lambda {|*args| gnp_handler *args}
|
129
|
+
|
130
|
+
http
|
131
|
+
end
|
132
|
+
|
133
|
+
def run_callback_server
|
134
|
+
callback_server.start unless callback_server.running?
|
135
|
+
end
|
136
|
+
|
137
|
+
#def gnp_callback name, entry_uri, req
|
138
|
+
def gnp_handler request_uri, env
|
139
|
+
op, name, entry_uri = (request_uri.to_s.split /;/)
|
140
|
+
unless sub = @subscriptions.find { |s| s.name == name }
|
141
|
+
raise "no such subscription: #{name} :: #{entry_uri}"#\n#{@subscriptions.inspect}"
|
142
|
+
end
|
143
|
+
|
144
|
+
begin
|
145
|
+
req = Rack::Request.new(env)
|
146
|
+
op, payload = (decode_gnp_body req.body.read)
|
147
|
+
(sub.callback.call op, payload)
|
148
|
+
rescue Exception => e
|
149
|
+
callstack = "#{e.backtrace.join "\n "}"
|
150
|
+
puts " ## Subscription::callback - #{e}\n -> #{callstack}"
|
151
|
+
end
|
152
|
+
|
153
|
+
# HTTP OK keeps the subscription alive, even in case of handler errors
|
154
|
+
[200, {"Content-Type"=>"text/plain"}, ["keep going dude!"]]
|
155
|
+
end
|
156
|
+
|
157
|
+
def decode_gnp_body txt
|
158
|
+
debugger if (defined? debugger)
|
159
|
+
json = (JSON.parse txt)
|
160
|
+
puts " -- json GNP: #{json.inspect}"
|
161
|
+
|
162
|
+
payload = nil
|
163
|
+
op = %w{update delete create}.find { |op| json[op] }
|
164
|
+
%w{attribute node}.find { |t| payload = json[op][t] }
|
165
|
+
#puts "payload: #{payload.inspect}"
|
166
|
+
[op, payload]
|
167
|
+
|
168
|
+
#op = (json.include? 'update') ? :udpate : nil
|
169
|
+
#op ||= (json.include? 'delete') ? :delete : nil
|
170
|
+
#op ||= (json.include? 'create') ? :create : nil
|
171
|
+
#op or (raise "unknown GNP op: #{txt}")
|
172
|
+
|
173
|
+
#payload = json[op.to_s]
|
174
|
+
#[op, (payload['attribute'] || payload['node'])]
|
175
|
+
end
|
176
|
+
|
177
|
+
# incapsulates the underlying net access
|
178
|
+
def http_put(url, params, &request_modifier)
|
179
|
+
uri = URI.parse url
|
180
|
+
req = Net::HTTP::Put.new uri.path
|
181
|
+
req.set_form_data(params)
|
182
|
+
request_modifier && (request_modifier.call req)
|
183
|
+
|
184
|
+
session = (Net::HTTP.new uri.host, uri.port)
|
185
|
+
case res = session.start { |http| http.request req }
|
186
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
187
|
+
# OK
|
188
|
+
else
|
189
|
+
res.error!
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
module Gom
|
3
|
+
module Remote
|
4
|
+
class Daemon
|
5
|
+
|
6
|
+
include ::Timeout
|
7
|
+
|
8
|
+
Defaults = {
|
9
|
+
:actor_dt => 60,
|
10
|
+
:sensor_dt => 1,
|
11
|
+
:callback_port => 8815,
|
12
|
+
:stealth => false,
|
13
|
+
}
|
14
|
+
|
15
|
+
include OAttr
|
16
|
+
oattr :actor_dt, :sensor_dt, :stealth
|
17
|
+
|
18
|
+
# service_path is derived from the service_url (server part stripped)
|
19
|
+
attr :service_path
|
20
|
+
|
21
|
+
def initialize service_url, options = {}, &blk
|
22
|
+
@options = (Defaults.merge options)
|
23
|
+
callback_port = @options[:callback_port]
|
24
|
+
@gom, @service_path = (Connection.init service_url, callback_port)
|
25
|
+
(blk.call self, @service_path) unless blk.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
=begin
|
29
|
+
def open_nagios_port jjjjj
|
30
|
+
@gom.callback_server.mount(%r{^/nagios}, lambda do |*args|
|
31
|
+
uri, env = *args
|
32
|
+
req = Rack::Request.new(env)
|
33
|
+
envmap = (env.map { |k,v| "#{k}: #{v}" }.join "\n")
|
34
|
+
body = ["OK -- #{env['REQUEST_URI']}\n---\n#{envmap}"]
|
35
|
+
[200, {"Content-Type"=>"text/plain"}, body]
|
36
|
+
end)
|
37
|
+
end
|
38
|
+
hs = HttpServer.new o
|
39
|
+
hs.mount "^/gnp;", lambda {|*args| gnp_handler *args}
|
40
|
+
=end
|
41
|
+
def sensor_loop interval = sensor_dt, &tic
|
42
|
+
puts " -- running gom-script sensor loop.."
|
43
|
+
forever(interval) { tic.call self }
|
44
|
+
end
|
45
|
+
|
46
|
+
def actor_loop interval = actor_dt, &tic
|
47
|
+
puts " -- running gom-script actor loop.."
|
48
|
+
forever(interval) do
|
49
|
+
@gom.refresh
|
50
|
+
tic && (tic.call self) || :continue
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def forever interval = 0, &callback
|
55
|
+
loop do
|
56
|
+
begin
|
57
|
+
rc = callback.call
|
58
|
+
rescue Exception => e
|
59
|
+
puts " ## <#{e.class}> #{self} - #{e}\n -> #{e.backtrace.join "\n "}"
|
60
|
+
ensure
|
61
|
+
break if rc == :stop
|
62
|
+
sleep interval
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# push own ip and monitoring port back to GOM node
|
68
|
+
def check_in
|
69
|
+
if stealth
|
70
|
+
puts " -- no GOM check-in in stealth mode"
|
71
|
+
else
|
72
|
+
@gom.write "#{service_path}:daemon_ip", @gom.callback_server.host
|
73
|
+
#@gom.write "#{service_path}:nagios_port", nagios_port
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Gom
|
2
|
+
module Remote
|
3
|
+
class Entry
|
4
|
+
include Gom::Remote
|
5
|
+
def gom
|
6
|
+
Gom::Remote.connection
|
7
|
+
end
|
8
|
+
# @deprecated?
|
9
|
+
def connection
|
10
|
+
Gom::Remote.connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def gnode path
|
14
|
+
json = (connection.read "#{path}.json")
|
15
|
+
(JSON.parse json)["node"]["entries"].select do |entry|
|
16
|
+
# 1. select attribute entries
|
17
|
+
entry.has_key? "attribute"
|
18
|
+
end.inject({}) do |h, a|
|
19
|
+
# 2. make it a key, value list
|
20
|
+
h[a["attribute"]["name"].to_sym] = a["attribute"]["value"]
|
21
|
+
h
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/handler/mongrel'
|
3
|
+
require 'thread'
|
4
|
+
require 'applix/oattr'
|
5
|
+
|
6
|
+
module Gom
|
7
|
+
module Remote
|
8
|
+
class HttpServer
|
9
|
+
|
10
|
+
Defaults = {
|
11
|
+
:host => "0.0.0.0", :port => 25191
|
12
|
+
}
|
13
|
+
|
14
|
+
include OAttr
|
15
|
+
oattr :host, :port
|
16
|
+
|
17
|
+
def initialize options = {}
|
18
|
+
@options = (Defaults.merge options)
|
19
|
+
@mounts = {}
|
20
|
+
@mounts_access = Mutex.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_url
|
24
|
+
p = (port == 80 ? '' : ":#{port}")
|
25
|
+
"http://#{host}#{p}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def running?
|
29
|
+
!@server.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def mount pattern, handler
|
33
|
+
@mounts_access.synchronize { @mounts.update pattern => handler }
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def unmount pattern
|
38
|
+
@mounts_access.synchronize { @mounts.delete pattern }
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def start
|
43
|
+
@server.nil? or (raise "already running!")
|
44
|
+
@thread = Thread.new { start_mongrel_server }
|
45
|
+
sleep 0.1 # give thread time for start-up
|
46
|
+
@thread
|
47
|
+
end
|
48
|
+
|
49
|
+
def stop
|
50
|
+
@server.nil? and (raise "not running!")
|
51
|
+
puts ' -- stopping callback server..'
|
52
|
+
@server.stop
|
53
|
+
@server = nil
|
54
|
+
puts ' down.'
|
55
|
+
sleep 2 # sleep added as a precaution
|
56
|
+
puts ' -- killing server thread now...'
|
57
|
+
@thread.kill
|
58
|
+
@thread = nil
|
59
|
+
puts ' and gone.'
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# take the URI on walk it through the list of mounts and return the one
|
64
|
+
# with the longest match or nil. In case of a match the corresponding
|
65
|
+
# handler is returned, nil otherwise.
|
66
|
+
def match uri
|
67
|
+
targets = []
|
68
|
+
@mounts_access.synchronize do
|
69
|
+
targets = @mounts.map do |re, app|
|
70
|
+
[app, (uri.path.match re).to_s]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# sort for longest match. And target might be nil already for an empty
|
75
|
+
# targets list, which is ok as we return nil in that case.
|
76
|
+
target = targets.sort!{|a,b| a[1].length <=> b[1].length}.last
|
77
|
+
func, pattern = target
|
78
|
+
(pattern.nil? || pattern.empty?) ? nil : func
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# dispatching a request URI from env['REQUEST_URI'] which look
|
84
|
+
# somethings like:
|
85
|
+
#
|
86
|
+
# http://172.20.2.9:2719/gnp;enttec-dmx;/services/enttec-dmx-usb-pro/values
|
87
|
+
#
|
88
|
+
def dispatch env
|
89
|
+
#req = Rack::Request.new(env)
|
90
|
+
uri = (URI.parse env['REQUEST_URI'])
|
91
|
+
if func = (match uri)
|
92
|
+
func.call uri, env
|
93
|
+
else
|
94
|
+
puts " !! no handler for: #{req.fullpath} -- #{@mounts.keys.inspect}"
|
95
|
+
[404, {"Content-Type"=>"text/plain"}, ["Not Found"]]
|
96
|
+
end
|
97
|
+
rescue => e
|
98
|
+
puts " ## #{e}\n -> #{e.backtrace.join "\n "}"
|
99
|
+
[500, {"Content-Type"=>"text/plain"}, [e]]
|
100
|
+
end
|
101
|
+
|
102
|
+
# as i absolutly dislike capitalized options i use lowercase options
|
103
|
+
# throughout and only convert them just before i pass them the the
|
104
|
+
# mongrel server. Nothing to be proud of, but i definitly don't want to
|
105
|
+
# write --Port on the command line...
|
106
|
+
def mongrel_opts
|
107
|
+
@options.merge :Host => @options[:host], :Port => @options[:port]
|
108
|
+
end
|
109
|
+
|
110
|
+
def start_mongrel_server
|
111
|
+
puts " -- starting http server: #{@options.inspect}"
|
112
|
+
@server.nil? or (raise "already running!")
|
113
|
+
f = Proc.new {|env| dispatch env}
|
114
|
+
Rack::Handler::Mongrel.run(f, mongrel_opts) do |server|
|
115
|
+
@server = server
|
116
|
+
puts " mongrel up: #{@options.inspect}"
|
117
|
+
end
|
118
|
+
rescue Exception => e
|
119
|
+
puts " ## oops: #{e}"
|
120
|
+
puts @options.inspect
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gom
|
2
|
+
module Remote
|
3
|
+
class Subscription
|
4
|
+
|
5
|
+
Defaults = {
|
6
|
+
:name => nil,
|
7
|
+
:operations => [:update],
|
8
|
+
:condition_script => nil,
|
9
|
+
:uri_regexp => nil,
|
10
|
+
:callback => nil,
|
11
|
+
}
|
12
|
+
|
13
|
+
attr_reader :entry_uri, :uri, :callback
|
14
|
+
attr_accessor :callback
|
15
|
+
attr_reader :name, :operations, :condition_script, :uri_regexp
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#{self.class}: #{@options.inject}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# hint: supplying a recognizable name helps with distributed gom
|
22
|
+
# operations
|
23
|
+
#
|
24
|
+
def initialize entry_uri, options = {}, &blk
|
25
|
+
@name = options[:name] || "0x#{object_id}"
|
26
|
+
# URI for the observer node
|
27
|
+
@uri = "/gom/observer#{entry_uri.sub ':', '/'}/.#{@name}"
|
28
|
+
|
29
|
+
@options = Defaults.merge options
|
30
|
+
@entry_uri = entry_uri
|
31
|
+
@callback = options[:callback] || blk;
|
32
|
+
@operations = (@options[:operations] || []).join ', '
|
33
|
+
@uri_regexp = (re = @options[:uri_regexp]) && (Regexp.new re) || nil
|
34
|
+
@condition_script = @options[:condition_script]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../../spec_helper'
|
2
|
+
|
3
|
+
describe Gom::Remote::Connection do
|
4
|
+
|
5
|
+
describe "initialization" do
|
6
|
+
it "should split a GOM node url" do
|
7
|
+
gom, path = (Gom::Remote::Connection.split_url 'http://gom:345/dmx/node')
|
8
|
+
gom.should == 'http://gom:345'
|
9
|
+
path.should == '/dmx/node'
|
10
|
+
end
|
11
|
+
it "should strip last slash from the node" do
|
12
|
+
gom, path = (Gom::Remote::Connection.split_url 'http://xxx:4321/a/b/c/')
|
13
|
+
gom.should == 'http://xxx:4321'
|
14
|
+
path.should == '/a/b/c'
|
15
|
+
gom, path = (Gom::Remote::Connection.split_url 'http://xxx:4321/a/b:c/')
|
16
|
+
gom.should == 'http://xxx:4321'
|
17
|
+
path.should == '/a/b:c'
|
18
|
+
end
|
19
|
+
it "should split an attribute URL" do
|
20
|
+
gom, path = (Gom::Remote::Connection.split_url 'http://xxx/a:x')
|
21
|
+
gom.should == 'http://xxx'
|
22
|
+
path.should == '/a:x'
|
23
|
+
end
|
24
|
+
it "should split a GOM node url on init" do
|
25
|
+
gom, path = (Gom::Remote::Connection.init 'http://gom:345/dmx/node')
|
26
|
+
gom.target_url.should == 'http://gom:345'
|
27
|
+
path.should == '/dmx/node'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "with a connection it" do
|
32
|
+
before :each do
|
33
|
+
@gom, path = (Gom::Remote::Connection.init 'http://gom:345/dmx/node')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should fetch the callback_ip from remote" do
|
37
|
+
@gom.callback_server.host.should == "10.0.0.23"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should put attribute values to remote" do
|
41
|
+
@gom.should_receive(:http_put).
|
42
|
+
with("http://gom:345/some/node:attr", { "attribute" => "abc", "type" => :string })
|
43
|
+
@gom.write '/some/node:attr', "abc"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "with subscriptions" do
|
48
|
+
before :each do
|
49
|
+
@gom, path = (Gom::Remote::Connection.init 'http://localhost:3000')
|
50
|
+
@gom.stub!(:run_callback_server).and_return(true)
|
51
|
+
end
|
52
|
+
|
53
|
+
#it "should have no subscriptions on init" do
|
54
|
+
# @gom.subscriptions.should == []
|
55
|
+
#end
|
56
|
+
|
57
|
+
it "should subscribe operations whitelist" do
|
58
|
+
s = (Gom::Remote::Subscription.new '/node', :operations => [:delete, :create])
|
59
|
+
@gom.should_receive(:http_put).with(
|
60
|
+
"http://localhost:3000/gom/observer/node/.#{s.name}",
|
61
|
+
hash_including("attributes[operations]" => 'delete, create')
|
62
|
+
)
|
63
|
+
@gom.subscribe s
|
64
|
+
@gom.refresh
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have an uri regexp" do
|
68
|
+
s = (Gom::Remote::Subscription.new '/node', :uri_regexp => /foo/)
|
69
|
+
@gom.should_receive(:http_put).with(
|
70
|
+
"http://localhost:3000/gom/observer/node/.#{s.name}",
|
71
|
+
hash_including("attributes[uri_regexp]" => /foo/)
|
72
|
+
)
|
73
|
+
@gom.subscribe s
|
74
|
+
@gom.refresh
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have accept=application/json param" do
|
78
|
+
s = (Gom::Remote::Subscription.new '/node')
|
79
|
+
@gom.should_receive(:http_put).with(
|
80
|
+
"http://localhost:3000/gom/observer/node/.#{s.name}",
|
81
|
+
hash_including("attributes[accept]" => 'application/json')
|
82
|
+
)
|
83
|
+
@gom.subscribe s
|
84
|
+
@gom.refresh
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should put observer to gom on refresh" do
|
88
|
+
s = (Gom::Remote::Subscription.new '/node/values')
|
89
|
+
@gom.should_receive(:http_put).with(
|
90
|
+
"http://localhost:3000/gom/observer/node/values/.#{s.name}",
|
91
|
+
#hash_including("attributes[callback_url]" => "http://1.2.3.4:2179/gnp;#{s.name};/node/values")
|
92
|
+
hash_including("attributes[callback_url]" => anything)
|
93
|
+
)
|
94
|
+
@gom.subscribe s
|
95
|
+
@gom.refresh
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should observe an attribute entry" do
|
99
|
+
s = (Gom::Remote::Subscription.new '/node:attribute')
|
100
|
+
@gom.should_receive(:http_put).with(
|
101
|
+
"http://localhost:3000/gom/observer/node/attribute/.#{s.name}",
|
102
|
+
#hash_including("attributes[callback_url]" => "http://1.2.3.4:2179/gnp;#{s.name};/node:attribute")
|
103
|
+
hash_including("attributes[callback_url]" => anything)
|
104
|
+
)
|
105
|
+
@gom.subscribe s
|
106
|
+
@gom.refresh
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../../spec_helper'
|
2
|
+
|
3
|
+
include Gom::Remote
|
4
|
+
|
5
|
+
describe Gom::Remote::Daemon do
|
6
|
+
|
7
|
+
describe "with a plain vanilla daemon" do
|
8
|
+
before :each do
|
9
|
+
@daemon = Daemon.new 'http://gom:345/gom-script/test'
|
10
|
+
end
|
11
|
+
it "should have a default actor_dt" do
|
12
|
+
@daemon.actor_dt.should == Daemon::Defaults[:actor_dt]
|
13
|
+
end
|
14
|
+
it "should have stealth mode off by default" do
|
15
|
+
@daemon.stealth.should == false
|
16
|
+
end
|
17
|
+
it "should have a default sensor_dt" do
|
18
|
+
@daemon.sensor_dt.should == Daemon::Defaults[:sensor_dt]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse the service_path from the service_url" do
|
22
|
+
@daemon.service_path.should == '/gom-script/test'
|
23
|
+
end
|
24
|
+
it "should terminate sensor loop on :stop" do
|
25
|
+
count = 0
|
26
|
+
timeout(1) do
|
27
|
+
@daemon.sensor_loop(0.1) { count += 1; :stop if count == 3 }
|
28
|
+
end
|
29
|
+
count.should == 3
|
30
|
+
end
|
31
|
+
it "should terminate actor loop on :stop" do
|
32
|
+
Gom::Remote.connection.should_receive(:refresh)
|
33
|
+
timeout(1) { @daemon.actor_loop { :stop } }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should check in with its client ip" do
|
37
|
+
Gom::Remote.connection.should_receive(:write).
|
38
|
+
with("/gom-script/test:daemon_ip", "10.0.0.23")
|
39
|
+
@daemon.check_in
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "initialization" do
|
44
|
+
it "should find the class" do
|
45
|
+
Daemon.should_not == nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should init the connection" do
|
49
|
+
Gom::Remote.connection.should == nil
|
50
|
+
Daemon.new 'http://gom:345/gom-script/test'
|
51
|
+
(c = Gom::Remote.connection).should_not == nil
|
52
|
+
c.target_url.should == 'http://gom:345'
|
53
|
+
c.initial_path.should == '/gom-script/test'
|
54
|
+
c.callback_server.port.should == Daemon::Defaults[:callback_port]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../../spec_helper'
|
2
|
+
|
3
|
+
describe Gom::Remote::HttpServer do
|
4
|
+
|
5
|
+
describe "initialization" do
|
6
|
+
it "should not be running on creation" do
|
7
|
+
server = Gom::Remote::HttpServer.new
|
8
|
+
server.running?.should == false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should overwrite host option" do
|
13
|
+
server = Gom::Remote::HttpServer.new :host => "1.2.3.4"
|
14
|
+
server.host.should == "1.2.3.4"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should overwrite port option" do
|
18
|
+
server = Gom::Remote::HttpServer.new :port => 9151
|
19
|
+
server.port.should == 9151
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have a base url" do
|
23
|
+
h, p = (Gom::Remote::HttpServer::Defaults.values_at :host, :port)
|
24
|
+
|
25
|
+
server = Gom::Remote::HttpServer.new
|
26
|
+
server.base_url.should == "http://#{h}:#{p}"
|
27
|
+
server = Gom::Remote::HttpServer.new :port => 9151
|
28
|
+
server.base_url.should == "http://#{h}:9151"
|
29
|
+
server = Gom::Remote::HttpServer.new :host => '127.0.0.1'
|
30
|
+
server.base_url.should == "http://127.0.0.1:#{p}"
|
31
|
+
server = Gom::Remote::HttpServer.new :port => 1234, :host => '10.1.1.10'
|
32
|
+
server.base_url.should == "http://10.1.1.10:1234"
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "with a server" do
|
36
|
+
before :each do
|
37
|
+
@server = Gom::Remote::HttpServer.new
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should match empty mounts to nil" do
|
41
|
+
@server.send(:match, (URI.parse '/foo/aa;bb;cc?p1=12&p2=oo')).should == nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not missmatch" do
|
45
|
+
@server.mount '^/a', lambda { }
|
46
|
+
@server.mount '^/a/b', lambda { }
|
47
|
+
@server.mount '^/a/b/c', lambda { }
|
48
|
+
@server.match(URI.parse '/x/a/b/c').should == nil
|
49
|
+
@server.match(URI.parse '/x/a/b').should == nil
|
50
|
+
@server.match(URI.parse '/x/a').should == nil
|
51
|
+
@server.match(URI.parse 'a').should == nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should unmount" do
|
55
|
+
@server.mount '/a/b/c', (l = lambda { "block 6" })
|
56
|
+
@server.match(URI.parse '/a/b/c/d').should == l
|
57
|
+
@server.unmount '/a/b/c'
|
58
|
+
@server.match(URI.parse '/a/b/c/d').should == nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should match with regexp as well" do
|
62
|
+
@server.mount %r{/a}, (l1 = lambda { "block 1" })
|
63
|
+
@server.mount %r{/a/b}, (l2 = lambda { "block 2" })
|
64
|
+
@server.mount %r{/a/b/c}, (l3 = lambda { "block 3" })
|
65
|
+
@server.match(URI.parse '/a/b').should == l2
|
66
|
+
@server.match(URI.parse '/a/b/c').should == l3
|
67
|
+
@server.match(URI.parse '/a/b/x').should == l2
|
68
|
+
@server.match(URI.parse '/a/b/c/d').should == l3
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should prefer longer matches" do
|
72
|
+
@server.mount '/a', (l1 = lambda { "block 1" })
|
73
|
+
@server.mount '/a/b', (l2 = lambda { "block 2" })
|
74
|
+
@server.mount '/a/b/c', (l3 = lambda { "block 3" })
|
75
|
+
@server.match(URI.parse '/a/b').should == l2
|
76
|
+
@server.match(URI.parse '/a/b/c').should == l3
|
77
|
+
@server.match(URI.parse '/a/b/x').should == l2
|
78
|
+
@server.match(URI.parse '/a/b/c/d').should == l3
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should match simple strings" do
|
82
|
+
@server.mount "/foo", (l = lambda { puts "needs some code here" })
|
83
|
+
@server.match(URI.parse '/foo/aa;bb;cc?p1=12&p2=oo').should == l
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should have default mongrel options" do
|
87
|
+
@server.port.should == Gom::Remote::HttpServer::Defaults[:port]
|
88
|
+
@server.host.should == Gom::Remote::HttpServer::Defaults[:host]
|
89
|
+
end
|
90
|
+
|
91
|
+
#it "should dispatch a nagios callback" do
|
92
|
+
# @cs.should_not_receive(:gnp_dispatcher)
|
93
|
+
# response = @cs.send(:dispatch_request_uri, "/nagios;foo;bar", {})
|
94
|
+
# response.should == [200, {"Content-Type"=>"text/plain"}, ["OK"]]
|
95
|
+
#end
|
96
|
+
|
97
|
+
it "should start and stop" do
|
98
|
+
@server.start.class.should == Thread
|
99
|
+
#sleep 1
|
100
|
+
@server.running?.should == true
|
101
|
+
@server.stop.should == @server
|
102
|
+
sleep 1
|
103
|
+
@server.running?.should == false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../../spec_helper'
|
2
|
+
|
3
|
+
describe Gom::Remote::Subscription do
|
4
|
+
|
5
|
+
describe "when created with default options" do
|
6
|
+
before :each do
|
7
|
+
@sub = (Gom::Remote::Subscription.new '/dmx/node/values')
|
8
|
+
end
|
9
|
+
it "should have a object id as name" do
|
10
|
+
@sub.name.should == "0x#{@sub.object_id}"
|
11
|
+
end
|
12
|
+
it "should have operations whitelist" do
|
13
|
+
@sub.operations.should == "update"
|
14
|
+
end
|
15
|
+
it "should have nil condition_script" do
|
16
|
+
@sub.condition_script.should == nil
|
17
|
+
end
|
18
|
+
it "should have a nil uri_regexp" do
|
19
|
+
@sub.uri_regexp.should == nil
|
20
|
+
end
|
21
|
+
it "should have a nil callback" do
|
22
|
+
@sub.callback.should == nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should overwrite callback from options" do
|
27
|
+
callback = lambda {}
|
28
|
+
s = (Gom::Remote::Subscription.new '/node/values', :callback => callback )
|
29
|
+
s.callback.should == callback
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should overwrite name from options value" do
|
33
|
+
name = "test-#{Time.now.to_i}"
|
34
|
+
s = (Gom::Remote::Subscription.new '/node/values', :name => name)
|
35
|
+
s.name.should == name
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "observer uri" do
|
39
|
+
it "should construct a proper gom observer uri" do
|
40
|
+
s = (Gom::Remote::Subscription.new '/dmx/node/values')
|
41
|
+
s.uri.should == "/gom/observer/dmx/node/values/.#{s.name}"
|
42
|
+
end
|
43
|
+
it "should interpret attribute paths" do
|
44
|
+
s = (Gom::Remote::Subscription.new '/dmx/node:attribute')
|
45
|
+
s.uri.should == "/gom/observer/dmx/node/attribute/.#{s.name}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--backtrace --debugger
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# figure out where we are being loaded from
|
2
|
+
if $LOADED_FEATURES.grep(/spec\/spec_helper\.rb/).any?
|
3
|
+
begin
|
4
|
+
raise "foo"
|
5
|
+
rescue => e
|
6
|
+
puts <<-MSG
|
7
|
+
===================================================
|
8
|
+
It looks like spec_helper.rb has been loaded
|
9
|
+
multiple times. Normalize the require to:
|
10
|
+
|
11
|
+
require "spec/spec_helper"
|
12
|
+
|
13
|
+
Things like File.join and File.expand_path will
|
14
|
+
cause it to be loaded multiple times.
|
15
|
+
|
16
|
+
Loaded this time from:
|
17
|
+
|
18
|
+
#{e.backtrace.join("\n ")}
|
19
|
+
===================================================
|
20
|
+
MSG
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
25
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
26
|
+
require 'spec'
|
27
|
+
require 'spec/autorun'
|
28
|
+
require 'fakeweb'
|
29
|
+
|
30
|
+
require 'gom-script'
|
31
|
+
|
32
|
+
Spec::Runner.configure do |config|
|
33
|
+
config.before :each do
|
34
|
+
FakeWeb.register_uri(
|
35
|
+
:get, "http://gom:345/gom/config/connection.txt",
|
36
|
+
:body => "client_ip: 10.0.0.23"
|
37
|
+
)
|
38
|
+
FakeWeb.register_uri(
|
39
|
+
:get, "http://localhost:3000/gom/config/connection.txt",
|
40
|
+
:body => "client_ip: 10.0.0.23"
|
41
|
+
)
|
42
|
+
|
43
|
+
Gom::Remote.connection = nil # reset for every test
|
44
|
+
end
|
45
|
+
|
46
|
+
config.after :each do
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gom-script
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- art+com/dirk luesebrink
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-30 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: applix
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.2.1
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rack
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: gom-core
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rspec
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fakeweb
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.2.7
|
64
|
+
version:
|
65
|
+
description: " \n GOM is a schema-less object database in ruby with Resource Oriented API,\n server-side javascript, distributed HTTP notifications and some more.\n This gom-script script simplifies coding of clients and daemon which like\n to listen on state change event in the GOM.\n "
|
66
|
+
email: dirk.luesebrink@gmail.com
|
67
|
+
executables: []
|
68
|
+
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files:
|
72
|
+
- LICENSE
|
73
|
+
- README.markdown
|
74
|
+
files:
|
75
|
+
- .document
|
76
|
+
- .gitignore
|
77
|
+
- LICENSE
|
78
|
+
- README.markdown
|
79
|
+
- Rakefile
|
80
|
+
- VERSION
|
81
|
+
- lib/gom-script.rb
|
82
|
+
- lib/gom/remote.rb
|
83
|
+
- lib/gom/remote/connection.rb
|
84
|
+
- lib/gom/remote/daemon.rb
|
85
|
+
- lib/gom/remote/entry.rb
|
86
|
+
- lib/gom/remote/http_server.rb
|
87
|
+
- lib/gom/remote/subscription.rb
|
88
|
+
- spec/gom/remote/connection_spec.rb
|
89
|
+
- spec/gom/remote/daemon_spec.rb
|
90
|
+
- spec/gom/remote/http_server_spec.rb
|
91
|
+
- spec/gom/remote/subscription_spec.rb
|
92
|
+
- spec/spec.opts
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: http://github.com/crux/gom-script
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options:
|
100
|
+
- --charset=UTF-8
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
version:
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.3.5
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: connecting scripts and daemons with a remote GOM instance
|
122
|
+
test_files:
|
123
|
+
- spec/gom/remote/connection_spec.rb
|
124
|
+
- spec/gom/remote/daemon_spec.rb
|
125
|
+
- spec/gom/remote/http_server_spec.rb
|
126
|
+
- spec/gom/remote/subscription_spec.rb
|
127
|
+
- spec/spec_helper.rb
|