vayacondios-server 0.2.11 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/.gitignore +3 -1
  2. data/.travis.yml +2 -0
  3. data/Gemfile +15 -9
  4. data/LICENSE.md +2 -6
  5. data/Procfile +1 -1
  6. data/README.md +656 -111
  7. data/Rakefile +89 -6
  8. data/bin/vcd +10 -0
  9. data/bin/vcd-server +8 -0
  10. data/config/database.yml +6 -0
  11. data/config/spec.example.yml +18 -0
  12. data/config/vayacondios.example.yml +15 -0
  13. data/config/vcd-server.rb +37 -0
  14. data/examples/configuration.rb +56 -0
  15. data/examples/event_stream.rb +19 -0
  16. data/examples/simple.rb +61 -0
  17. data/features/event.feature +319 -0
  18. data/features/events.feature +208 -0
  19. data/features/stash.feature +840 -0
  20. data/features/stashes.feature +492 -0
  21. data/features/step_definitions/stash_steps.rb +113 -0
  22. data/features/stream.feature +30 -0
  23. data/features/support/em.rb +14 -0
  24. data/features/support/env.rb +13 -0
  25. data/lib/vayacondios/configuration.rb +63 -0
  26. data/lib/vayacondios/server/api.rb +126 -0
  27. data/lib/vayacondios/server/api_options.rb +56 -0
  28. data/lib/vayacondios/server/configuration.rb +23 -0
  29. data/lib/vayacondios/server/driver.rb +71 -0
  30. data/lib/vayacondios/server/drivers/mongo.rb +126 -0
  31. data/lib/vayacondios/server/handlers/document_handler.rb +81 -0
  32. data/lib/vayacondios/server/handlers/event_handler.rb +31 -26
  33. data/lib/vayacondios/server/handlers/events_handler.rb +31 -0
  34. data/lib/vayacondios/server/handlers/stash_handler.rb +69 -0
  35. data/lib/vayacondios/server/handlers/stashes_handler.rb +49 -0
  36. data/lib/vayacondios/server/handlers/stream_handler.rb +39 -0
  37. data/lib/vayacondios/server/models/document.rb +87 -0
  38. data/lib/vayacondios/server/models/event.rb +198 -0
  39. data/lib/vayacondios/server/models/stash.rb +100 -0
  40. data/lib/vayacondios/server.rb +35 -0
  41. data/lib/vayacondios-server.rb +19 -13
  42. data/lib/vayacondios.rb +22 -0
  43. data/pom.xml +124 -4
  44. data/spec/configuration_spec.rb +41 -0
  45. data/spec/server/api_options_spec.rb +32 -0
  46. data/spec/server/api_spec.rb +279 -0
  47. data/spec/server/configuration_spec.rb +27 -0
  48. data/spec/server/drivers/mongo_spec.rb +107 -0
  49. data/spec/server/handlers/event_handler_spec.rb +62 -0
  50. data/spec/server/handlers/events_handler_spec.rb +51 -0
  51. data/spec/server/handlers/stash_handler_spec.rb +68 -0
  52. data/spec/server/handlers/stashes_handler_spec.rb +50 -0
  53. data/spec/server/handlers/stream_handler_spec.rb +5 -0
  54. data/spec/server/models/document_spec.rb +9 -0
  55. data/spec/server/models/event_spec.rb +185 -0
  56. data/spec/server/models/stash_spec.rb +95 -0
  57. data/spec/spec_helper.rb +23 -3
  58. data/spec/support/database_helper.rb +42 -0
  59. data/spec/support/log_helper.rb +19 -0
  60. data/spec/support/shared_context_for_events.rb +22 -0
  61. data/spec/support/shared_context_for_stashes.rb +24 -0
  62. data/spec/support/shared_examples_for_handlers.rb +32 -0
  63. data/src/main/java/com/infochimps/vayacondios/BaseClient.java +342 -0
  64. data/src/main/java/com/infochimps/vayacondios/HTTPClient.java +426 -0
  65. data/src/main/java/com/infochimps/vayacondios/VayacondiosClient.java +487 -65
  66. data/src/main/java/com/infochimps/vayacondios/test/IntegrationTest.java +3 -0
  67. data/src/test/java/com/infochimps/vayacondios/BaseClientTest.java +50 -0
  68. data/src/test/java/com/infochimps/vayacondios/HTTPClientIT.java +267 -0
  69. data/vayacondios-server.gemspec +9 -9
  70. metadata +127 -122
  71. checksums.yaml +0 -15
  72. data/.rspec +0 -2
  73. data/.yardopts +0 -10
  74. data/Guardfile +0 -41
  75. data/app/http_shim.rb +0 -71
  76. data/bin/vcd.sh +0 -27
  77. data/config/http_shim.rb +0 -43
  78. data/config/vayacondios.example.yaml +0 -7
  79. data/config/vayacondios.yaml +0 -7
  80. data/examples/java/ItemSetTest.java +0 -76
  81. data/lib/tasks/publish.rake +0 -23
  82. data/lib/tasks/spec.rake +0 -11
  83. data/lib/tasks/yard.rake +0 -2
  84. data/lib/vayacondios/client/config.rb +0 -7
  85. data/lib/vayacondios/client/configliere.rb +0 -38
  86. data/lib/vayacondios/client/cube_client.rb +0 -39
  87. data/lib/vayacondios/client/http_client.rb +0 -49
  88. data/lib/vayacondios/client/itemset.rb +0 -130
  89. data/lib/vayacondios/client/legacy_switch.rb +0 -43
  90. data/lib/vayacondios/client/notifier.rb +0 -123
  91. data/lib/vayacondios/client/zabbix_client.rb +0 -148
  92. data/lib/vayacondios/legacy_switch.rb +0 -43
  93. data/lib/vayacondios/server/errors/bad_request.rb +0 -6
  94. data/lib/vayacondios/server/errors/not_found.rb +0 -6
  95. data/lib/vayacondios/server/handlers/config_handler.rb +0 -32
  96. data/lib/vayacondios/server/handlers/itemset_handler.rb +0 -60
  97. data/lib/vayacondios/server/legacy_switch.rb +0 -43
  98. data/lib/vayacondios/server/model/config_document.rb +0 -89
  99. data/lib/vayacondios/server/model/document.rb +0 -25
  100. data/lib/vayacondios/server/model/event_document.rb +0 -94
  101. data/lib/vayacondios/server/model/itemset_document.rb +0 -126
  102. data/lib/vayacondios/server/rack/extract_methods.rb +0 -35
  103. data/lib/vayacondios/server/rack/jsonize.rb +0 -43
  104. data/lib/vayacondios/server/rack/params.rb +0 -50
  105. data/lib/vayacondios/server/rack/path.rb +0 -23
  106. data/lib/vayacondios/server/rack/path_validation.rb +0 -22
  107. data/lib/vayacondios/version.rb +0 -3
  108. data/lib/vayacondios-client.rb +0 -22
  109. data/scripts/hadoop_monitor/configurable.rb +0 -66
  110. data/scripts/hadoop_monitor/hadoop_attempt_scraper.rb +0 -45
  111. data/scripts/hadoop_monitor/hadoop_client.rb +0 -273
  112. data/scripts/hadoop_monitor/hadoop_monitor.rb +0 -101
  113. data/scripts/hadoop_monitor/hadoopable.rb +0 -65
  114. data/scripts/hadoop_monitor/machine_monitor.rb +0 -115
  115. data/scripts/s3_cataloger/buckets +0 -33
  116. data/scripts/s3_cataloger/foreach_bucket +0 -88
  117. data/scripts/s3_cataloger/parse_ls.py +0 -391
  118. data/spec/client/itemset_legacy_spec.rb +0 -55
  119. data/spec/client/itemset_spec.rb +0 -60
  120. data/spec/client/notifier_spec.rb +0 -120
  121. data/spec/server/config_spec.rb +0 -113
  122. data/spec/server/event_spec.rb +0 -103
  123. data/spec/server/itemset_legacy_spec.rb +0 -320
  124. data/spec/server/itemset_spec.rb +0 -317
  125. data/spec/server/rack/extract_methods_spec.rb +0 -60
  126. data/spec/server/rack/path_spec.rb +0 -36
  127. data/spec/server/rack/path_validation_spec.rb +0 -22
  128. data/spec/server/server_spec.rb +0 -20
  129. data/spec/support/mongo_cleaner.rb +0 -32
  130. data/src/main/java/ItemSetTest.java +0 -76
  131. data/src/main/java/com/infochimps/util/CurrentClass.java +0 -26
  132. data/src/main/java/com/infochimps/util/DebugUtil.java +0 -38
  133. data/src/main/java/com/infochimps/util/HttpHelper.java +0 -181
  134. data/src/main/java/com/infochimps/vayacondios/ItemSets.java +0 -373
  135. data/src/main/java/com/infochimps/vayacondios/LinkToVCD.java +0 -18
  136. data/src/main/java/com/infochimps/vayacondios/MemoryVCDShim.java +0 -84
  137. data/src/main/java/com/infochimps/vayacondios/Organization.java +0 -62
  138. data/src/main/java/com/infochimps/vayacondios/PathBuilder.java +0 -13
  139. data/src/main/java/com/infochimps/vayacondios/StandardVCDLink.java +0 -218
  140. data/src/main/java/com/infochimps/vayacondios/VCDIntegrationTest.java +0 -108
  141. data/src/test/java/com/infochimps/vayacondios/TestVayacondiosInMemory.java +0 -78
  142. 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
- # Vayacondios::EventHandler
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
- class Vayacondios
7
-
8
- class EventHandler
9
-
10
- def initialize(mongodb)
11
- @mongo = mongodb
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
- def update(document, options={})
15
- raise Error::BadRequest.new unless options[:topic]
16
- raise Error::BadRequest.new if options[:id] && /\W/ =~ options[:id]
17
-
18
- existing_document = EventDocument.find(@mongo, options)
19
- if existing_document
20
- existing_document.update(document)
21
- else
22
- existing_document = EventDocument.create(@mongo, document, options)
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
- def self.find(mongodb, options)
28
- existing_document = EventDocument.find(mongodb, options)
29
- raise Error::NotFound.new unless existing_document
30
- existing_document
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