vayacondios-server 0.2.11 → 0.3.0
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/.gitignore +3 -1
- data/.travis.yml +2 -0
- data/Gemfile +15 -9
- data/LICENSE.md +2 -6
- data/Procfile +1 -1
- data/README.md +656 -111
- data/Rakefile +89 -6
- data/bin/vcd +10 -0
- data/bin/vcd-server +8 -0
- data/config/database.yml +6 -0
- data/config/spec.example.yml +18 -0
- data/config/vayacondios.example.yml +15 -0
- data/config/vcd-server.rb +37 -0
- data/examples/configuration.rb +56 -0
- data/examples/event_stream.rb +19 -0
- data/examples/simple.rb +61 -0
- data/features/event.feature +319 -0
- data/features/events.feature +208 -0
- data/features/stash.feature +840 -0
- data/features/stashes.feature +492 -0
- data/features/step_definitions/stash_steps.rb +113 -0
- data/features/stream.feature +30 -0
- data/features/support/em.rb +14 -0
- data/features/support/env.rb +13 -0
- data/lib/vayacondios/configuration.rb +63 -0
- data/lib/vayacondios/server/api.rb +126 -0
- data/lib/vayacondios/server/api_options.rb +56 -0
- data/lib/vayacondios/server/configuration.rb +23 -0
- data/lib/vayacondios/server/driver.rb +71 -0
- data/lib/vayacondios/server/drivers/mongo.rb +126 -0
- data/lib/vayacondios/server/handlers/document_handler.rb +81 -0
- data/lib/vayacondios/server/handlers/event_handler.rb +31 -26
- data/lib/vayacondios/server/handlers/events_handler.rb +31 -0
- data/lib/vayacondios/server/handlers/stash_handler.rb +69 -0
- data/lib/vayacondios/server/handlers/stashes_handler.rb +49 -0
- data/lib/vayacondios/server/handlers/stream_handler.rb +39 -0
- data/lib/vayacondios/server/models/document.rb +87 -0
- data/lib/vayacondios/server/models/event.rb +198 -0
- data/lib/vayacondios/server/models/stash.rb +100 -0
- data/lib/vayacondios/server.rb +35 -0
- data/lib/vayacondios-server.rb +19 -13
- data/lib/vayacondios.rb +22 -0
- data/pom.xml +124 -4
- data/spec/configuration_spec.rb +41 -0
- data/spec/server/api_options_spec.rb +32 -0
- data/spec/server/api_spec.rb +279 -0
- data/spec/server/configuration_spec.rb +27 -0
- data/spec/server/drivers/mongo_spec.rb +107 -0
- data/spec/server/handlers/event_handler_spec.rb +62 -0
- data/spec/server/handlers/events_handler_spec.rb +51 -0
- data/spec/server/handlers/stash_handler_spec.rb +68 -0
- data/spec/server/handlers/stashes_handler_spec.rb +50 -0
- data/spec/server/handlers/stream_handler_spec.rb +5 -0
- data/spec/server/models/document_spec.rb +9 -0
- data/spec/server/models/event_spec.rb +185 -0
- data/spec/server/models/stash_spec.rb +95 -0
- data/spec/spec_helper.rb +23 -3
- data/spec/support/database_helper.rb +42 -0
- data/spec/support/log_helper.rb +19 -0
- data/spec/support/shared_context_for_events.rb +22 -0
- data/spec/support/shared_context_for_stashes.rb +24 -0
- data/spec/support/shared_examples_for_handlers.rb +32 -0
- data/src/main/java/com/infochimps/vayacondios/BaseClient.java +342 -0
- data/src/main/java/com/infochimps/vayacondios/HTTPClient.java +426 -0
- data/src/main/java/com/infochimps/vayacondios/VayacondiosClient.java +487 -65
- data/src/main/java/com/infochimps/vayacondios/test/IntegrationTest.java +3 -0
- data/src/test/java/com/infochimps/vayacondios/BaseClientTest.java +50 -0
- data/src/test/java/com/infochimps/vayacondios/HTTPClientIT.java +267 -0
- data/vayacondios-server.gemspec +9 -9
- metadata +127 -122
- checksums.yaml +0 -15
- data/.rspec +0 -2
- data/.yardopts +0 -10
- data/Guardfile +0 -41
- data/app/http_shim.rb +0 -71
- data/bin/vcd.sh +0 -27
- data/config/http_shim.rb +0 -43
- data/config/vayacondios.example.yaml +0 -7
- data/config/vayacondios.yaml +0 -7
- data/examples/java/ItemSetTest.java +0 -76
- data/lib/tasks/publish.rake +0 -23
- data/lib/tasks/spec.rake +0 -11
- data/lib/tasks/yard.rake +0 -2
- data/lib/vayacondios/client/config.rb +0 -7
- data/lib/vayacondios/client/configliere.rb +0 -38
- data/lib/vayacondios/client/cube_client.rb +0 -39
- data/lib/vayacondios/client/http_client.rb +0 -49
- data/lib/vayacondios/client/itemset.rb +0 -130
- data/lib/vayacondios/client/legacy_switch.rb +0 -43
- data/lib/vayacondios/client/notifier.rb +0 -123
- data/lib/vayacondios/client/zabbix_client.rb +0 -148
- data/lib/vayacondios/legacy_switch.rb +0 -43
- data/lib/vayacondios/server/errors/bad_request.rb +0 -6
- data/lib/vayacondios/server/errors/not_found.rb +0 -6
- data/lib/vayacondios/server/handlers/config_handler.rb +0 -32
- data/lib/vayacondios/server/handlers/itemset_handler.rb +0 -60
- data/lib/vayacondios/server/legacy_switch.rb +0 -43
- data/lib/vayacondios/server/model/config_document.rb +0 -89
- data/lib/vayacondios/server/model/document.rb +0 -25
- data/lib/vayacondios/server/model/event_document.rb +0 -94
- data/lib/vayacondios/server/model/itemset_document.rb +0 -126
- data/lib/vayacondios/server/rack/extract_methods.rb +0 -35
- data/lib/vayacondios/server/rack/jsonize.rb +0 -43
- data/lib/vayacondios/server/rack/params.rb +0 -50
- data/lib/vayacondios/server/rack/path.rb +0 -23
- data/lib/vayacondios/server/rack/path_validation.rb +0 -22
- data/lib/vayacondios/version.rb +0 -3
- data/lib/vayacondios-client.rb +0 -22
- data/scripts/hadoop_monitor/configurable.rb +0 -66
- data/scripts/hadoop_monitor/hadoop_attempt_scraper.rb +0 -45
- data/scripts/hadoop_monitor/hadoop_client.rb +0 -273
- data/scripts/hadoop_monitor/hadoop_monitor.rb +0 -101
- data/scripts/hadoop_monitor/hadoopable.rb +0 -65
- data/scripts/hadoop_monitor/machine_monitor.rb +0 -115
- data/scripts/s3_cataloger/buckets +0 -33
- data/scripts/s3_cataloger/foreach_bucket +0 -88
- data/scripts/s3_cataloger/parse_ls.py +0 -391
- data/spec/client/itemset_legacy_spec.rb +0 -55
- data/spec/client/itemset_spec.rb +0 -60
- data/spec/client/notifier_spec.rb +0 -120
- data/spec/server/config_spec.rb +0 -113
- data/spec/server/event_spec.rb +0 -103
- data/spec/server/itemset_legacy_spec.rb +0 -320
- data/spec/server/itemset_spec.rb +0 -317
- data/spec/server/rack/extract_methods_spec.rb +0 -60
- data/spec/server/rack/path_spec.rb +0 -36
- data/spec/server/rack/path_validation_spec.rb +0 -22
- data/spec/server/server_spec.rb +0 -20
- data/spec/support/mongo_cleaner.rb +0 -32
- data/src/main/java/ItemSetTest.java +0 -76
- data/src/main/java/com/infochimps/util/CurrentClass.java +0 -26
- data/src/main/java/com/infochimps/util/DebugUtil.java +0 -38
- data/src/main/java/com/infochimps/util/HttpHelper.java +0 -181
- data/src/main/java/com/infochimps/vayacondios/ItemSets.java +0 -373
- data/src/main/java/com/infochimps/vayacondios/LinkToVCD.java +0 -18
- data/src/main/java/com/infochimps/vayacondios/MemoryVCDShim.java +0 -84
- data/src/main/java/com/infochimps/vayacondios/Organization.java +0 -62
- data/src/main/java/com/infochimps/vayacondios/PathBuilder.java +0 -13
- data/src/main/java/com/infochimps/vayacondios/StandardVCDLink.java +0 -218
- data/src/main/java/com/infochimps/vayacondios/VCDIntegrationTest.java +0 -108
- data/src/test/java/com/infochimps/vayacondios/TestVayacondiosInMemory.java +0 -78
- data/vayacondios-client.gemspec +0 -25
@@ -0,0 +1,63 @@
|
|
1
|
+
module Vayacondios
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
attr_accessor :base_filename, :load_order
|
5
|
+
|
6
|
+
def initialize(base_fname = nil)
|
7
|
+
@base_filename = base_fname || 'vayacondios.yml'
|
8
|
+
@load_order = %w[ global project ]
|
9
|
+
@settings = Configliere::Param.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def defaults
|
13
|
+
Hash.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def global
|
17
|
+
File.join('/etc/vayacondios', base_filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def project
|
21
|
+
File.join(ENV['PWD'], 'config', base_filename)
|
22
|
+
end
|
23
|
+
|
24
|
+
def overlay(conf = nil)
|
25
|
+
@overlay = conf unless conf.nil?
|
26
|
+
@overlay
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolved?
|
30
|
+
!!@resolved
|
31
|
+
end
|
32
|
+
|
33
|
+
def resolved_settings
|
34
|
+
resolve!
|
35
|
+
@resolved_settings.dup
|
36
|
+
end
|
37
|
+
|
38
|
+
def [] handle
|
39
|
+
resolved_settings[handle.to_sym]
|
40
|
+
end
|
41
|
+
|
42
|
+
def apply_all
|
43
|
+
scopes = load_order.dup.unshift(:defaults).push(:overlay)
|
44
|
+
scopes.each do |scope|
|
45
|
+
conf = send scope
|
46
|
+
if conf.is_a? String
|
47
|
+
@settings.read_yaml File.read(conf) if File.readable?(conf)
|
48
|
+
elsif conf.is_a? Hash
|
49
|
+
@settings.deep_merge! conf
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def resolve!
|
55
|
+
unless resolved?
|
56
|
+
apply_all
|
57
|
+
@resolved_settings = @settings.to_hash.symbolize_keys
|
58
|
+
@resolved = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'vayacondios-server'
|
2
|
+
|
3
|
+
module Vayacondios::Server
|
4
|
+
|
5
|
+
# Implements the Vayacondios server API.
|
6
|
+
#
|
7
|
+
# ## Setup
|
8
|
+
#
|
9
|
+
# Once the Goliath server has booted, this class is handed control
|
10
|
+
# to process web requests. It uses a set of Rack-aware and
|
11
|
+
# Goliath-friendly plugins to accomplish some of the edges stuff
|
12
|
+
# like routing, parsing params, validating, &c.
|
13
|
+
#
|
14
|
+
# ## Request Loop
|
15
|
+
#
|
16
|
+
# When handling an actual request, it has to do four things:
|
17
|
+
#
|
18
|
+
# * determine which handler class to instantiate to handle the request
|
19
|
+
# * determine the full set of params contained in the request
|
20
|
+
# * call the appropriate method on the new handler, passing in these params
|
21
|
+
# * handle any errors that bubble up
|
22
|
+
#
|
23
|
+
# ## Configuration
|
24
|
+
#
|
25
|
+
# Goliath is kind of weirdly hard to configure nicely. This class
|
26
|
+
# is also required to define an #options_parser method which is
|
27
|
+
# momentarily handed control at bootup time to interpret options
|
28
|
+
# passed to the `vcd-server` program.
|
29
|
+
#
|
30
|
+
# It **simultaneously** is required to read a configuration file
|
31
|
+
# from disk. This configuration file is aware of the Rack
|
32
|
+
# environment the code is running in so it can take
|
33
|
+
# environment-specific actions like creating single-connections in
|
34
|
+
# test/development but using a pool of shared connections in
|
35
|
+
# production mode. The default file is located in the Vayacondios
|
36
|
+
# source distribution at `config/vcd-server.rb`.
|
37
|
+
#
|
38
|
+
class Api < Goliath::API
|
39
|
+
include ApiOptions
|
40
|
+
|
41
|
+
plugin Goliath::Chimp::Plugin::ActivityMonitor, window: 30
|
42
|
+
|
43
|
+
use Goliath::Rack::Heartbeat
|
44
|
+
use Goliath::Chimp::Rack::Formatters::JSON
|
45
|
+
use Goliath::Chimp::Rack::ForceContentType, 'application/json'
|
46
|
+
use Goliath::Rack::Render
|
47
|
+
use Goliath::Rack::Params
|
48
|
+
use Goliath::Chimp::Rack::ApiVersion, Vayacondios::GEM_VERSION, api: 'Vayacondios'
|
49
|
+
use Goliath::Chimp::Rack::ServerMetrics, env_key: { 'routes' => :type }, default: 'other'
|
50
|
+
use Goliath::Rack::Validation::RequestMethod, %w[ GET POST PUT PATCH DELETE ]
|
51
|
+
use Goliath::Chimp::Rack::ControlMethods, 'POST' => :create,
|
52
|
+
'GET' => :retrieve,
|
53
|
+
'PATCH' => :update,
|
54
|
+
'PUT' => :update,
|
55
|
+
'DELETE' => :delete
|
56
|
+
use Goliath::Chimp::Rack::Validation::Routes, /^
|
57
|
+
\/#{Vayacondios::API_VERSION}
|
58
|
+
\/(?<organization>[a-z][-_\w]+)
|
59
|
+
\/(?<type>[-\.\w]+)
|
60
|
+
(\/(?<topic>[-\.\w]+)
|
61
|
+
(\/(?<id>([-\.\w+]\/?)+))?)?
|
62
|
+
$/ix,
|
63
|
+
"/#{Vayacondios::API_VERSION}/<organization>/<type>/<topic>/<id>"
|
64
|
+
use Goliath::Chimp::Rack::Validation::RouteHandler, :type, 'stash' => StashHandler,
|
65
|
+
'stashes' => StashesHandler,
|
66
|
+
'event' => EventHandler,
|
67
|
+
'events' => EventsHandler,
|
68
|
+
'stream' => StreamHandler
|
69
|
+
use Goliath::Chimp::Rack::Validation::RequiredRoutes, :type, 'stash' => :topic,
|
70
|
+
/^events?$/ => :topic,
|
71
|
+
'stream' => :topic
|
72
|
+
|
73
|
+
# The document part of the request, e.g. - params that came
|
74
|
+
# directly from its body.
|
75
|
+
#
|
76
|
+
# Goliath::Rack::Params dumps all non-Hash types that were JSON
|
77
|
+
# parsed under this header. By accessing the #document this way
|
78
|
+
# we allow for non-Hash bodies to be sent as requests.
|
79
|
+
#
|
80
|
+
# @return [Hash,Array,String,Fixnum,nil] any native JSON datatype
|
81
|
+
def document
|
82
|
+
params.has_key?('_json') ? params['_json'] : params
|
83
|
+
end
|
84
|
+
|
85
|
+
# Assign a callback to the stream endpoint. Some of the Rack
|
86
|
+
# logic is recreated because of the way streaming data works.
|
87
|
+
def open_stream(env, hndlr)
|
88
|
+
env[:subscription] = hndlr.stream_data{ |data| env.stream_send MultiJson.dump(data).concat("\n") }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Make sure to remove any outstanding streaming connections
|
92
|
+
# when the client disconnects
|
93
|
+
def on_close env
|
94
|
+
return unless env[:subscription]
|
95
|
+
env.delete(:subscription).close_stream!
|
96
|
+
end
|
97
|
+
|
98
|
+
# Deliver a response for the request.
|
99
|
+
#
|
100
|
+
# Uses the method set by Infochimps::Rack::ControlMethods to
|
101
|
+
# determine which action to call on the handler determined by
|
102
|
+
# Infochimps::Rack::Validation::RouteHandler
|
103
|
+
#
|
104
|
+
# Traps Goliath::Validation::Errors by returning the appropriate
|
105
|
+
# response.
|
106
|
+
#
|
107
|
+
# Traps all other errors by responding with a 500.
|
108
|
+
#
|
109
|
+
# @param [Hash] env the current request environment
|
110
|
+
def response env
|
111
|
+
h = handler.new(logger, db)
|
112
|
+
open_stream(env, h) if routes[:type] == 'stream'
|
113
|
+
body = h.call(control_method, routes, document)
|
114
|
+
[200, {}, body]
|
115
|
+
rescue Goliath::Validation::Error => e
|
116
|
+
return [e.status_code, {}, { error: e.message }]
|
117
|
+
rescue Document::Error => e
|
118
|
+
return [400, {}, { error: e.message }]
|
119
|
+
rescue => e
|
120
|
+
logger.error "#{e.class} -- #{e.message}"
|
121
|
+
e.backtrace.each{ |line| logger.error line }
|
122
|
+
return [500, {}, { error: "#{e.class} -- #{e.message}" }]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
module ApiOptions
|
3
|
+
|
4
|
+
def options_parser opts, options
|
5
|
+
opts.banner = <<-BANNER.gsub(/^ {8}/, '').strip
|
6
|
+
usage: vcd-server [--param=value|--param|-p value|-p]
|
7
|
+
|
8
|
+
Vayacondios server lets any system that can speak JSON over HTTP read
|
9
|
+
and write configuration and events.
|
10
|
+
|
11
|
+
It provides the following HTTP endpoints, all of which assume a
|
12
|
+
JSON-encoded request body.
|
13
|
+
|
14
|
+
Events:
|
15
|
+
GET /v2/ORG/event/TOPIC/ID
|
16
|
+
POST /v2/ORG/event/TOPIC[/ID] (announce)
|
17
|
+
DELETE /v2/ORG/event/TOPIC/ID
|
18
|
+
GET /v2/ORG/events/TOPIC (events)
|
19
|
+
DELETE /v2/ORG/events/TOPIC
|
20
|
+
|
21
|
+
Stashes:
|
22
|
+
GET /v2/ORG/stash/TOPIC[/ID] (get)
|
23
|
+
POST /v2/ORG/stash/TOPIC[/ID] (set!)
|
24
|
+
DELETE /v2/ORG/stash/TOPIC[/ID] (delete)
|
25
|
+
GET /v2/ORG/stashes (stashes)
|
26
|
+
DELETE /v2/ORG/stashes (delete_many)
|
27
|
+
BANNER
|
28
|
+
|
29
|
+
opts.separator ''
|
30
|
+
opts.separator 'Database options:'
|
31
|
+
|
32
|
+
options[:database] = {}
|
33
|
+
db_options = options[:database]
|
34
|
+
defaults = DbConfig.defaults[:development]
|
35
|
+
opts.on('-d', '--database.driver NAME', "Database driver (default: #{defaults[:driver]})") do |name|
|
36
|
+
db_options[:driver] = name
|
37
|
+
end
|
38
|
+
opts.on('-h', '--database.host HOST', "Database host (default: #{defaults[:host]})") do |host|
|
39
|
+
db_options[:host] = host
|
40
|
+
end
|
41
|
+
opts.on('-o', '--database.port PORT', Integer, "Database port (default: #{defaults[:port]})") do |port|
|
42
|
+
db_options[:port] = port
|
43
|
+
end
|
44
|
+
opts.on('-D', '--database.name NAME', "Database name (default: #{defaults[:name]})") do |name|
|
45
|
+
db_options[:name] = name
|
46
|
+
end
|
47
|
+
opts.on('-n', '--database.connections NUM', Integer, "Number of database connections to make (default: #{defaults[:connections]}). Production only") do |num|
|
48
|
+
db_options[:connections] = num
|
49
|
+
end
|
50
|
+
|
51
|
+
options[:config] = File.join(Vayacondios.library_dir, 'config/vcd-server.rb')
|
52
|
+
options[:port] = Vayacondios::DEFAULT_SERVER_PORT
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
class Configuration < Vayacondios::Configuration
|
3
|
+
|
4
|
+
def defaults
|
5
|
+
{
|
6
|
+
development: {
|
7
|
+
driver: 'mongo',
|
8
|
+
host: 'localhost',
|
9
|
+
port: 27017,
|
10
|
+
name: 'vayacondios_development',
|
11
|
+
connections: 20,
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def env(handle = nil)
|
17
|
+
handle ||= :development
|
18
|
+
resolved_settings[handle.to_sym] || {}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
DbConfig = Configuration.new('database.yml') unless defined? DbConfig
|
23
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
module Driver
|
3
|
+
|
4
|
+
Error = Class.new(StandardError) unless defined? Error
|
5
|
+
|
6
|
+
# Factory methods for drivers
|
7
|
+
class << self
|
8
|
+
def drivers
|
9
|
+
@list ||= {
|
10
|
+
mongo: MongoDriver,
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_driver handle
|
15
|
+
drivers = File.expand_path('../drivers', __FILE__)
|
16
|
+
driver_file = File.join(drivers, handle.to_s + '.rb')
|
17
|
+
load driver_file if File.exist? driver_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def retrieve handle
|
21
|
+
load_driver handle
|
22
|
+
drivers[handle.to_sym]
|
23
|
+
end
|
24
|
+
|
25
|
+
def included base
|
26
|
+
base.class_eval{ attr_reader :location, :log } if base.is_a? Class
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Main api entrance method
|
31
|
+
def call(name, request, *options)
|
32
|
+
send("base_#{name}", request)
|
33
|
+
set_location request.location
|
34
|
+
send(name, request.document, *options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def base_insert request
|
38
|
+
log.debug " Processing by #{self.class}#insert"
|
39
|
+
end
|
40
|
+
|
41
|
+
def base_retrieve request
|
42
|
+
log.debug " Processing by #{self.class}#retrieve"
|
43
|
+
end
|
44
|
+
|
45
|
+
def base_update request
|
46
|
+
log.debug " Processing by #{self.class}#update"
|
47
|
+
end
|
48
|
+
|
49
|
+
def base_search request
|
50
|
+
log.debug " Processing by #{self.class}#search"
|
51
|
+
end
|
52
|
+
|
53
|
+
def base_remove request
|
54
|
+
log.debug " Processing by #{self.class}#remove"
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_location loc
|
58
|
+
log.debug " Location: #{loc}"
|
59
|
+
@location = loc
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_log device
|
63
|
+
@log = device
|
64
|
+
end
|
65
|
+
|
66
|
+
# for testing only
|
67
|
+
def unset_location
|
68
|
+
@location = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
class MongoDriver
|
3
|
+
include Driver
|
4
|
+
|
5
|
+
def self.connect(options = {})
|
6
|
+
new(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@log = options[:log]
|
11
|
+
mongo = EM::Mongo::Connection.new(options[:host], options[:port], 1, reconnect_in: 1)
|
12
|
+
@connection = mongo.db options[:name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection
|
16
|
+
@connection.collection location
|
17
|
+
end
|
18
|
+
|
19
|
+
# Coerce objects into a BSON::ObjectId representation if possible.
|
20
|
+
#
|
21
|
+
# @param [BSON::ObjectId,Hash,#to_s] id the object to be coerced
|
22
|
+
# @return [BSON::ObjectId] the canonical representation of the ID
|
23
|
+
# @raise [Error] if `id` is a Hash and is missing the `$oid` parameter which is expected in this case
|
24
|
+
# @raise [Error] if the String representation of `id` is blank or empty
|
25
|
+
def format_id id
|
26
|
+
case
|
27
|
+
when id.is_a?(BSON::ObjectId)
|
28
|
+
id
|
29
|
+
when id.is_a?(Hash)
|
30
|
+
raise Error.new("When settings the ID of a #{self.class} with a Hash, an '$oid' key is required") if id['$oid'].nil?
|
31
|
+
format_id(id['$oid'])
|
32
|
+
when !id.to_s.empty?
|
33
|
+
id.to_s.match(/^[a-f0-9]{24}$/) ? BSON::ObjectId(id.to_s) : id.to_s
|
34
|
+
else
|
35
|
+
raise Error.new("A #{self} cannot have a blank or empty ID")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def mongo_prepare doc
|
40
|
+
doc[:_id] = format_id(doc[:_id]) if doc[:_id]
|
41
|
+
doc
|
42
|
+
end
|
43
|
+
|
44
|
+
def mongo_unprepare doc
|
45
|
+
doc['_id'] = doc['_id'].to_s
|
46
|
+
doc.symbolize_keys
|
47
|
+
end
|
48
|
+
|
49
|
+
def selector query
|
50
|
+
sel = { }.tap do |sel|
|
51
|
+
time = query.delete(:_t)
|
52
|
+
sel[:_t] = time.inject({}){ |t, (k,v)| t[('$' + k.to_s).to_sym] = v ; t } if time
|
53
|
+
data = query.delete(:_d)
|
54
|
+
sel.merge! to_dotted_hash(_d: data)
|
55
|
+
end
|
56
|
+
query.merge(sel).compact_blank
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_dotted_hash(hsh, key_string = '')
|
60
|
+
hsh.each_with_object({}) do |(k, v), ret|
|
61
|
+
key = key_string + k.to_s
|
62
|
+
if v.is_a? Hash
|
63
|
+
ret.merge! to_dotted_hash(v, key + '.')
|
64
|
+
else
|
65
|
+
ret[key] = v
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def projector query
|
71
|
+
if query[:sort] == 'time'
|
72
|
+
query[:sort] = '_t'
|
73
|
+
elsif query[:sort].present?
|
74
|
+
query[:sort] = '_d.' + query[:sort]
|
75
|
+
end
|
76
|
+
query[:_reverse] if query.delete(:order) == 'descending'
|
77
|
+
query
|
78
|
+
end
|
79
|
+
|
80
|
+
def search(request, filter, opts)
|
81
|
+
select = selector(filter)
|
82
|
+
log.debug " Selector doc: #{select}"
|
83
|
+
project = projector(opts)
|
84
|
+
log.debug " Projector doc: #{project}"
|
85
|
+
res = connection.find(select, project) || []
|
86
|
+
log.debug " Result: #{res}"
|
87
|
+
res.map{ |res| mongo_unprepare res }
|
88
|
+
end
|
89
|
+
|
90
|
+
def insert request
|
91
|
+
mongo_doc = mongo_prepare request
|
92
|
+
log.debug " Mongo doc: #{mongo_doc}"
|
93
|
+
res = connection.save mongo_doc
|
94
|
+
log.debug " Result: #{res}"
|
95
|
+
res = mongo_doc[:_id] if res == true
|
96
|
+
{ _id: format_id(res).to_s }
|
97
|
+
end
|
98
|
+
|
99
|
+
def retrieve request
|
100
|
+
mongo_doc = mongo_prepare request
|
101
|
+
log.debug " Mongo doc: #{mongo_doc}"
|
102
|
+
res = connection.find_one mongo_doc
|
103
|
+
log.debug " Result: #{res}"
|
104
|
+
return nil if res.nil?
|
105
|
+
mongo_unprepare res
|
106
|
+
end
|
107
|
+
|
108
|
+
def remove(request, filter)
|
109
|
+
mongo_doc = mongo_prepare(request)
|
110
|
+
mongo_doc.merge! selector(filter)
|
111
|
+
log.debug " Mongo doc: #{mongo_doc}"
|
112
|
+
res = connection.remove mongo_doc
|
113
|
+
log.debug " Result: #{res}"
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
# for testing only
|
118
|
+
def reset!
|
119
|
+
connection.drop
|
120
|
+
end
|
121
|
+
|
122
|
+
def count
|
123
|
+
connection.count
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
|
3
|
+
# Generic handler for all documents.
|
4
|
+
#
|
5
|
+
# Handlers link HTTP applications to document classes.
|
6
|
+
#
|
7
|
+
# @attr [Logger] log the log to use
|
8
|
+
# @attr [Driver] database the database driver
|
9
|
+
class DocumentHandler
|
10
|
+
include Goliath::Chimp::Handler
|
11
|
+
|
12
|
+
attr_reader :log, :database
|
13
|
+
|
14
|
+
# Create a new DocumentHandler.
|
15
|
+
#
|
16
|
+
# @param [Logger] log
|
17
|
+
def initialize(log, db)
|
18
|
+
@log = log
|
19
|
+
@database = db
|
20
|
+
end
|
21
|
+
|
22
|
+
# Search for matching documents.
|
23
|
+
#
|
24
|
+
# @param [Hash] query the search query
|
25
|
+
# @return [Array<Hash>] the matching documents
|
26
|
+
def base_search(params, query)
|
27
|
+
log.debug("Processing by #{self.class}#search")
|
28
|
+
log.debug(" Parameters: #{params.inspect}")
|
29
|
+
log.debug(" Query: #{query.inspect}")
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a document.
|
33
|
+
#
|
34
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
35
|
+
# @param [Hash] document the body of the document
|
36
|
+
# @return [Hash] the created document
|
37
|
+
def base_create(params, document)
|
38
|
+
log.debug("Processing by #{self.class}#create")
|
39
|
+
log.debug(" Parameters: #{params.inspect}")
|
40
|
+
log.debug(" Document: #{document.inspect}")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Find and show a particular document.
|
44
|
+
#
|
45
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
46
|
+
# @return [Object] the document (or part of a document) that was found
|
47
|
+
def base_retrieve(params, document)
|
48
|
+
log.debug("Processing by #{self.class}#retrieve")
|
49
|
+
log.debug(" Parameters: #{params.inspect}")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update a document.
|
53
|
+
#
|
54
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
55
|
+
# @param [Hash] document the body of the document
|
56
|
+
# @return [Object] the document (or part a document) that was updated
|
57
|
+
def base_update(params, document)
|
58
|
+
log.debug("Processing by #{self.class}#update")
|
59
|
+
log.debug(" Parameters: #{params.inspect}")
|
60
|
+
log.debug(" Document: #{document.inspect}")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Delete a document.
|
64
|
+
#
|
65
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
66
|
+
# @return [Hash] details about which documents were deleted
|
67
|
+
def base_delete(params, document)
|
68
|
+
log.debug("Processing by #{self.class}#delete")
|
69
|
+
log.debug(" Parameters: #{params.inspect}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def call(name, params, document)
|
73
|
+
send("base_#{name}", params, document)
|
74
|
+
send(name, params, document)
|
75
|
+
end
|
76
|
+
|
77
|
+
def action_successful
|
78
|
+
{ ok: true }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,33 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# This handler will accept requests to update Event for an organization. All
|
4
|
-
# updates will overwrite an existing document.
|
1
|
+
module Vayacondios::Server
|
2
|
+
class EventHandler < DocumentHandler
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def
|
11
|
-
|
4
|
+
# Create an event.
|
5
|
+
#
|
6
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
7
|
+
# @param [Hash] document the body of the document
|
8
|
+
def create(params, document)
|
9
|
+
Event.create(params, document) do |request|
|
10
|
+
database.call(:insert, request)
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
existing_document.body
|
14
|
+
# Find and show a particular event.
|
15
|
+
#
|
16
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
17
|
+
# @param [Hash] document the body of the document
|
18
|
+
# @raise [Goliath::Validation::Error] if no event is found. Returns a 404.
|
19
|
+
def retrieve(params, document)
|
20
|
+
Event.find(params) do |request|
|
21
|
+
database.call(:retrieve, request)
|
22
|
+
end or raise Goliath::Validation::NotFoundError.new("Event with topic <#{params[:topic]}> and ID <#{params[:id]}> not found")
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
# Delete a specific event.
|
26
|
+
#
|
27
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
28
|
+
# @param [Hash] document the body of the document
|
29
|
+
# @raise [Goliath::Validation::Error] if params do not have an id
|
30
|
+
def delete(params, document)
|
31
|
+
raise Goliath::Validation::BadRequestError.new('An <Id> is required to delete an Event') unless params[:id]
|
32
|
+
Event.destroy(params, {}) do |request, options|
|
33
|
+
database.call(:remove, request, options)
|
34
|
+
end
|
35
|
+
action_successful
|
31
36
|
end
|
32
37
|
end
|
33
|
-
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Vayacondios::Server
|
2
|
+
|
3
|
+
# Handles requests against multiple Events.
|
4
|
+
class EventsHandler < DocumentHandler
|
5
|
+
|
6
|
+
# Search for events matching a given query.
|
7
|
+
#
|
8
|
+
# @param [Hash] params routing information like `organization`, `topic,`, or `id`
|
9
|
+
# @param [Hash] query the search query
|
10
|
+
def search(params, query)
|
11
|
+
Event.search(params, query) do |request, filter, opts|
|
12
|
+
database.call(:search, request, filter, opts)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# FIXME
|
17
|
+
# Abstract this into method delegation
|
18
|
+
def base_retrieve(params, query)
|
19
|
+
base_search(params, query)
|
20
|
+
end
|
21
|
+
alias_method :retrieve, :search
|
22
|
+
|
23
|
+
def delete(params, query)
|
24
|
+
Event.destroy(params, query) do |request, opts|
|
25
|
+
database.call(:remove, request, opts)
|
26
|
+
end
|
27
|
+
action_successful
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|