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.
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