volt 0.9.6 → 0.9.7.pre2
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile +6 -1
- data/README.md +2 -0
- data/Rakefile +1 -0
- data/app/volt/models/active_volt_instance.rb +8 -6
- data/app/volt/models/user.rb +11 -2
- data/app/volt/models/volt_app_property.rb +8 -0
- data/app/volt/tasks/query_tasks.rb +23 -31
- data/app/volt/tasks/store_tasks.rb +2 -2
- data/app/volt/tasks/volt_admin_tasks.rb +24 -0
- data/docs/UPGRADE_GUIDE.md +6 -0
- data/lib/volt.rb +19 -12
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli.rb +19 -8
- data/lib/volt/cli/console.rb +0 -1
- data/lib/volt/cli/generators.rb +14 -3
- data/lib/volt/cli/migrate.rb +26 -0
- data/lib/volt/config.rb +17 -4
- data/lib/volt/controllers/http_controller.rb +12 -0
- data/lib/volt/data_stores/base_adaptor_client.rb +2 -2
- data/lib/volt/data_stores/base_adaptor_server.rb +2 -0
- data/lib/volt/data_stores/data_store.rb +20 -14
- data/lib/volt/extra_core/class.rb +28 -14
- data/lib/volt/extra_core/hash.rb +5 -0
- data/lib/volt/extra_core/string.rb +3 -1
- data/lib/volt/helpers/time.rb +9 -43
- data/lib/volt/helpers/time/calculations.rb +204 -0
- data/lib/volt/helpers/time/distance.rb +63 -0
- data/lib/volt/helpers/time/duration.rb +71 -0
- data/lib/volt/helpers/time/local_calculations.rb +49 -0
- data/lib/volt/helpers/time/local_volt_time.rb +23 -0
- data/lib/volt/helpers/time/numeric.rb +59 -0
- data/lib/volt/helpers/time/volt_time.rb +170 -0
- data/lib/volt/models.rb +5 -0
- data/lib/volt/models/array_model.rb +33 -6
- data/lib/volt/models/associations.rb +146 -23
- data/lib/volt/models/buffer.rb +38 -41
- data/lib/volt/models/cursor.rb +15 -0
- data/lib/volt/models/errors.rb +11 -0
- data/lib/volt/models/field_helpers.rb +108 -68
- data/lib/volt/models/helpers/array_model.rb +4 -0
- data/lib/volt/models/helpers/base.rb +8 -1
- data/lib/volt/models/helpers/change_helpers.rb +31 -12
- data/lib/volt/models/helpers/defaults.rb +15 -0
- data/lib/volt/models/location.rb +20 -6
- data/lib/volt/models/migrations/migration.rb +23 -0
- data/lib/volt/models/migrations/migration_runner.rb +146 -0
- data/lib/volt/models/model.rb +38 -1
- data/lib/volt/models/permissions.rb +8 -1
- data/lib/volt/models/persistors/array_store.rb +87 -8
- data/lib/volt/models/persistors/base.rb +19 -0
- data/lib/volt/models/persistors/model_store.rb +1 -1
- data/lib/volt/models/persistors/page.rb +4 -1
- data/lib/volt/models/persistors/query/query_identifier.rb +102 -0
- data/lib/volt/models/persistors/query/query_listener.rb +57 -12
- data/lib/volt/models/root_models/root_models.rb +19 -0
- data/lib/volt/models/url.rb +11 -2
- data/lib/volt/models/validations/validations.rb +5 -2
- data/lib/volt/models/validators/type_validator.rb +11 -0
- data/lib/volt/models/validators/unique_validator.rb +2 -2
- data/lib/volt/page/bindings/attribute_binding.rb +23 -1
- data/lib/volt/page/targets/attribute_section.rb +7 -0
- data/lib/volt/page/targets/binding_document/component_node.rb +44 -18
- data/lib/volt/page/targets/binding_document/tag_node.rb +41 -0
- data/lib/volt/page/tasks.rb +16 -8
- data/lib/volt/queries/live_query.rb +109 -0
- data/lib/volt/queries/live_query_pool.rb +58 -0
- data/lib/volt/queries/live_subquery.rb +0 -0
- data/lib/volt/queries/query_association_splitter.rb +31 -0
- data/lib/volt/queries/query_diff.rb +100 -0
- data/lib/volt/queries/query_runner.rb +110 -0
- data/lib/volt/queries/query_subscription.rb +80 -0
- data/lib/volt/queries/query_subscription_pool.rb +37 -0
- data/lib/volt/reactive/eventable.rb +8 -0
- data/lib/volt/reactive/reactive_array.rb +0 -4
- data/lib/volt/router/routes.rb +81 -31
- data/lib/volt/server/message_bus/base_message_bus.rb +9 -3
- data/lib/volt/server/message_bus/peer_to_peer.rb +6 -6
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
- data/lib/volt/server/middleware/default_middleware_stack.rb +12 -8
- data/lib/volt/server/rack/component_paths.rb +31 -4
- data/lib/volt/server/rack/http_content_types.rb +62 -0
- data/lib/volt/server/rack/http_resource.rb +1 -1
- data/lib/volt/server/rack/index_files.rb +8 -1
- data/lib/volt/server/rack/opal_files.rb +16 -1
- data/lib/volt/server/rack/sprockets_helpers_setup.rb +32 -1
- data/lib/volt/server/socket_connection_handler.rb +16 -7
- data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -3
- data/lib/volt/spec/capybara.rb +4 -3
- data/lib/volt/spec/setup.rb +5 -0
- data/lib/volt/tasks/dispatcher.rb +3 -1
- data/lib/volt/utils/data_transformer.rb +4 -4
- data/lib/volt/utils/ejson.rb +19 -6
- data/lib/volt/utils/promise_extensions.rb +1 -1
- data/lib/volt/utils/time_opal_patch.rb +749 -0
- data/lib/volt/utils/time_patch.rb +11 -4
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +19 -11
- data/lib/volt/volt/properties.rb +24 -0
- data/lib/volt/volt/server_setup/app.rb +30 -7
- data/lib/volt/volt/users.rb +15 -3
- data/spec/apps/kitchen_sink/Gemfile +5 -1
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/save_controller.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +4 -2
- data/spec/apps/kitchen_sink/app/main/models/post.rb +0 -1
- data/spec/apps/kitchen_sink/app/main/models/todo.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/views/mailers/reset_password.html +10 -0
- data/spec/apps/kitchen_sink/app/main/views/todos/index.html +2 -0
- data/spec/apps/kitchen_sink/config/app.rb +2 -0
- data/spec/apps/migrations/config/db/migrations/1445111704_migration1.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445113517_migration2.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445115200_migration3.rb +7 -0
- data/spec/extra_core/class_spec.rb +10 -0
- data/spec/helpers/distance_spec.rb +35 -0
- data/spec/helpers/duration_spec.rb +160 -0
- data/spec/helpers/volt_time_spec.rb +275 -0
- data/spec/integration/callbacks_spec.rb +2 -1
- data/spec/integration/http_endpoints_spec.rb +4 -0
- data/spec/integration/save_spec.rb +1 -1
- data/spec/integration/todos_spec.rb +7 -5
- data/spec/models/array_model_spec.rb +17 -3
- data/spec/models/associations_spec.rb +48 -1
- data/spec/models/field_helpers_spec.rb +7 -3
- data/spec/models/migrations/migration_runner_spec.rb +69 -0
- data/spec/models/model_spec.rb +42 -8
- data/spec/models/permissions_spec.rb +20 -8
- data/spec/models/persistors/array_store_spec.rb +18 -0
- data/spec/models/persistors/page_spec.rb +15 -10
- data/spec/models/persistors/store_spec.rb +13 -3
- data/spec/models/url_spec.rb +4 -3
- data/spec/models/user_spec.rb +6 -3
- data/spec/models/user_validation_spec.rb +3 -3
- data/spec/models/validations_spec.rb +4 -0
- data/spec/models/validators/block_validations_spec.rb +9 -5
- data/spec/models/validators/email_validator_spec.rb +2 -0
- data/spec/models/validators/lifecycle_callbacks_spec.rb +86 -0
- data/spec/models/validators/unique_validator_spec.rb +1 -0
- data/spec/page/path_string_renderer_spec.rb +5 -0
- data/spec/queries/live_query_spec.rb +16 -0
- data/spec/queries/query_association_splitter_spec.rb +14 -0
- data/spec/queries/query_diff_spec.rb +132 -0
- data/spec/queries/query_identifier_spec.rb +98 -0
- data/spec/queries/query_runner_spec.rb +63 -0
- data/spec/queries/query_tracker_spec.rb +141 -0
- data/spec/router/routes_spec.rb +52 -21
- data/spec/server/middleware/rack_content_types_spec.rb +78 -0
- data/spec/server/rack/asset_files_spec.rb +38 -30
- data/spec/spec_helper.rb +8 -0
- data/spec/utils/ejson_spec.rb +9 -8
- data/spec/utils/ejson_volt_time_spec.rb +65 -0
- data/templates/migration/migration.rb.tt +9 -0
- data/templates/newgem/gitignore.tt +1 -0
- data/templates/project/Gemfile.tt +19 -2
- data/templates/project/README.md.tt +6 -1
- data/templates/project/app/main/config/dependencies.rb +6 -0
- data/templates/project/config/app.rb.tt +18 -4
- data/volt.gemspec +2 -2
- metadata +73 -16
- data/app/volt/tasks/live_query/live_query_pool.rb +0 -48
- data/app/volt/tasks/live_query/query_tracker.rb +0 -92
- data/spec/tasks/live_query_spec.rb +0 -18
- data/spec/tasks/query_tasks.rb +0 -7
- data/spec/tasks/query_tracker_spec.rb +0 -145
data/lib/volt/router/routes.rb
CHANGED
|
@@ -5,38 +5,38 @@ module Volt
|
|
|
5
5
|
# a url to params, and params to url.
|
|
6
6
|
# routes do
|
|
7
7
|
# client "/about", _view: 'about'
|
|
8
|
-
# client "/blog/{id}/edit",
|
|
9
|
-
# client "/blog/{id}",
|
|
10
|
-
# client "/blog",
|
|
11
|
-
# client "/blog/new",
|
|
12
|
-
# client "/cool/{
|
|
8
|
+
# client "/blog/{{ id }}/edit", view: 'blog/edit', action: 'edit'
|
|
9
|
+
# client "/blog/{{ id }}", view: 'blog/show', action: 'show'
|
|
10
|
+
# client "/blog", view: 'blog'
|
|
11
|
+
# client "/blog/new", view: 'blog/new', action: 'new'
|
|
12
|
+
# client "/cool/{{ name }}", view: 'cool'
|
|
13
13
|
# end
|
|
14
14
|
#
|
|
15
15
|
# Using the routes above, we would generate the following:
|
|
16
16
|
#
|
|
17
17
|
# @direct_routes = {
|
|
18
|
-
# '/about' => {
|
|
19
|
-
# '/blog' => {
|
|
20
|
-
# '/blog/new' => {
|
|
18
|
+
# '/about' => {view: 'about'},
|
|
19
|
+
# '/blog' => {view: 'blog'}
|
|
20
|
+
# '/blog/new' => {view: 'blog/new', action: 'new'}
|
|
21
21
|
# }
|
|
22
22
|
#
|
|
23
23
|
# -- nil represents a terminal
|
|
24
|
-
# -- * represents any match
|
|
24
|
+
# -- * represents any match (in that section (between / and /))
|
|
25
25
|
# -- a number for a parameter means use the value in that number section
|
|
26
26
|
#
|
|
27
27
|
# @indirect_routes = {
|
|
28
28
|
# '*' => {
|
|
29
29
|
# 'edit' => {
|
|
30
|
-
# nil => {id: 1,
|
|
30
|
+
# nil => {id: 1, view: 'blog/edit', action: 'edit'}
|
|
31
31
|
# }
|
|
32
|
-
# nil => {id: 1,
|
|
32
|
+
# nil => {id: 1, view: 'blog/show', action: 'show'}
|
|
33
33
|
# }
|
|
34
34
|
# }
|
|
35
35
|
# }
|
|
36
36
|
#
|
|
37
37
|
# Match for params
|
|
38
38
|
# @param_matches = [
|
|
39
|
-
# {id: nil,
|
|
39
|
+
# {id: nil, view: 'blog/edit', action: 'edit'} => Proc.new {|params| "/blog/#{params.id}/edit", params.reject {|k,v| k == :id }}
|
|
40
40
|
# ]
|
|
41
41
|
class Routes
|
|
42
42
|
def initialize
|
|
@@ -68,7 +68,7 @@ module Volt
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
# Add server side routes
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
def get(path, params)
|
|
73
73
|
create_route(:get, path, params)
|
|
74
74
|
end
|
|
@@ -190,17 +190,29 @@ module Volt
|
|
|
190
190
|
if part.nil?
|
|
191
191
|
if node[part]
|
|
192
192
|
# We found a match, replace the bindings and return
|
|
193
|
-
# TODO:
|
|
193
|
+
# TODO: Handle nested
|
|
194
194
|
setup_bindings_in_params(original_parts, node[part])
|
|
195
195
|
else
|
|
196
196
|
false
|
|
197
197
|
end
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
else
|
|
199
|
+
if (new_node = node[part])
|
|
200
|
+
# Direct match for section, continue
|
|
201
|
+
result = match_path(original_parts, parts, new_node)
|
|
202
|
+
return result if result
|
|
203
|
+
end
|
|
204
|
+
if (new_node = node['*'])
|
|
205
|
+
# Match on binding single section
|
|
206
|
+
result = match_path(original_parts, parts, new_node)
|
|
207
|
+
return result if result
|
|
208
|
+
end
|
|
209
|
+
if ((params = node['**']) && params && (params = params[nil]))
|
|
210
|
+
# Match on binding multiple sections
|
|
211
|
+
result = setup_bindings_in_params(original_parts, params)
|
|
212
|
+
return result if result
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
return false
|
|
204
216
|
end
|
|
205
217
|
end
|
|
206
218
|
|
|
@@ -214,6 +226,10 @@ module Volt
|
|
|
214
226
|
if value.is_a?(Fixnum)
|
|
215
227
|
# Lookup the param's value in the original url parts
|
|
216
228
|
params[key] = original_parts[value]
|
|
229
|
+
elsif value.is_a?(Range)
|
|
230
|
+
# When doing multiple section bindings, we lookup the parts as a range
|
|
231
|
+
# then join them with /
|
|
232
|
+
params[key] = original_parts[value].join('/')
|
|
217
233
|
end
|
|
218
234
|
end
|
|
219
235
|
|
|
@@ -231,10 +247,24 @@ module Volt
|
|
|
231
247
|
parts.each_with_index do |part, index|
|
|
232
248
|
if has_binding?(part)
|
|
233
249
|
# Strip off {{ and }}
|
|
234
|
-
|
|
250
|
+
section_matcher, multipart = binding_extract(part)
|
|
251
|
+
|
|
252
|
+
if multipart
|
|
253
|
+
# Match anything for the rest of the url (multiple sections)
|
|
254
|
+
|
|
255
|
+
# check that the splat is at the end of the url
|
|
256
|
+
if index != (parts.size-1)
|
|
257
|
+
raise "The splat (*) operator can only be used at the end of a url"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
part = '**'
|
|
261
|
+
index = (index..-1)
|
|
262
|
+
else
|
|
263
|
+
# Match anything in a single section, set the part to be '*'
|
|
264
|
+
part = '*'
|
|
265
|
+
end
|
|
235
266
|
|
|
236
|
-
|
|
237
|
-
part = '*'
|
|
267
|
+
params[section_matcher] = index
|
|
238
268
|
end
|
|
239
269
|
|
|
240
270
|
node = (node[part] ||= {})
|
|
@@ -251,7 +281,8 @@ module Volt
|
|
|
251
281
|
if has_binding?(part)
|
|
252
282
|
# Setup a nil param that can match anything, but gets
|
|
253
283
|
# assigned into the url
|
|
254
|
-
|
|
284
|
+
section_matcher, _ = binding_extract(part)
|
|
285
|
+
params[section_matcher] = nil
|
|
255
286
|
end
|
|
256
287
|
end
|
|
257
288
|
|
|
@@ -269,12 +300,12 @@ module Volt
|
|
|
269
300
|
|
|
270
301
|
url = parts.map do |part|
|
|
271
302
|
val = if has_binding?(part)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
303
|
+
# Get the
|
|
304
|
+
binding, _ = binding_extract(part)
|
|
305
|
+
input_params.delete(binding)
|
|
306
|
+
else
|
|
307
|
+
part
|
|
308
|
+
end
|
|
278
309
|
|
|
279
310
|
val
|
|
280
311
|
end.join('/')
|
|
@@ -319,7 +350,9 @@ module Volt
|
|
|
319
350
|
end
|
|
320
351
|
|
|
321
352
|
def url_parts(path)
|
|
322
|
-
|
|
353
|
+
# Remove start and end / and then split, keeping any blanks between
|
|
354
|
+
# sections (so // would get rejoined with the double)
|
|
355
|
+
path.gsub(/^\//, '').chomp('/').split('/', -1)
|
|
323
356
|
end
|
|
324
357
|
|
|
325
358
|
# Check if a string has a binding in it
|
|
@@ -331,5 +364,22 @@ module Volt
|
|
|
331
364
|
def path_with_id(base_path)
|
|
332
365
|
base_path + '/{{ id }}'
|
|
333
366
|
end
|
|
367
|
+
|
|
368
|
+
# @param: The binding part of the url eg: "{{ binding }} or {{ *binding }}"
|
|
369
|
+
# @return: a symbol for the binding variable eg: :binding, and a boolean for
|
|
370
|
+
# if the binding matches multiple sections.
|
|
371
|
+
def binding_extract(part)
|
|
372
|
+
section_matcher = part[2...-2].strip
|
|
373
|
+
|
|
374
|
+
multipart_matcher = false
|
|
375
|
+
|
|
376
|
+
if section_matcher[0] == '*'
|
|
377
|
+
# Match anything for the rest of the url (multiple sections)
|
|
378
|
+
section_matcher = section_matcher[1..-1]
|
|
379
|
+
multipart_matcher = true
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
return section_matcher.to_sym, multipart_matcher
|
|
383
|
+
end
|
|
334
384
|
end
|
|
335
385
|
end
|
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
#
|
|
6
6
|
# MessageBus instances inherit from MessageBus::BaseMessageBus and provide
|
|
7
7
|
# two methods 'publish' and 'subscribe'. They should be inside of
|
|
8
|
-
# Volt::MessageBus.
|
|
8
|
+
# Volt::MessageBus. Be sure to
|
|
9
|
+
# ```require 'volt/server/message_bus/base_message_bus'```
|
|
9
10
|
#
|
|
10
11
|
# publish should take a channel name and a message and deliver the message to
|
|
11
12
|
# any subscried listeners.
|
|
12
13
|
#
|
|
13
14
|
# subscribe should take a channel name and a block. It should yield a message
|
|
14
|
-
# to the block if a message is published to the channel.
|
|
15
|
+
# to the block if a message is published to the channel. It should return an
|
|
16
|
+
# object with a ```remove``` method that will remove the subscription.
|
|
15
17
|
#
|
|
16
18
|
# The implementation details of the pub/sub connection are left to the
|
|
17
19
|
# implemntation. If the user needs to configure server addresses, Volt.config
|
|
@@ -29,9 +31,13 @@
|
|
|
29
31
|
# NOTE: in the future, we plan to add support for round robbin message receiving
|
|
30
32
|
# and other patterns.
|
|
31
33
|
|
|
34
|
+
require 'volt/reactive/eventable'
|
|
35
|
+
|
|
32
36
|
module Volt
|
|
33
37
|
module MessageBus
|
|
34
38
|
class BaseMessageBus
|
|
39
|
+
include Eventable
|
|
40
|
+
|
|
35
41
|
# MessagesBus's should take an instance of a Volt::App
|
|
36
42
|
def initialize(volt_app)
|
|
37
43
|
raise "Not implemented"
|
|
@@ -54,4 +60,4 @@ module Volt
|
|
|
54
60
|
end
|
|
55
61
|
end
|
|
56
62
|
end
|
|
57
|
-
end
|
|
63
|
+
end
|
|
@@ -40,6 +40,7 @@ require 'volt/server/message_bus/peer_to_peer/server_tracker'
|
|
|
40
40
|
require 'volt/server/message_bus/peer_to_peer/peer_server'
|
|
41
41
|
require 'volt/server/message_bus/peer_to_peer/peer_connection'
|
|
42
42
|
require 'volt/server/message_bus/base_message_bus'
|
|
43
|
+
require_relative '../../../../app/volt/models/active_volt_instance'
|
|
43
44
|
|
|
44
45
|
# TODO: Right now the message bus uses threads, we should switch it to use a
|
|
45
46
|
# single thread and some form of select:
|
|
@@ -50,7 +51,6 @@ module Volt
|
|
|
50
51
|
class PeerToPeer < BaseMessageBus
|
|
51
52
|
# How long without an update before we mark an instance as dead (in seconds)
|
|
52
53
|
DEAD_TIME = 20
|
|
53
|
-
include Eventable
|
|
54
54
|
|
|
55
55
|
# Use subscribe instead of on provided in Eventable
|
|
56
56
|
alias_method :subscribe, :on
|
|
@@ -60,7 +60,7 @@ module Volt
|
|
|
60
60
|
def initialize(volt_app)
|
|
61
61
|
@volt_app = volt_app
|
|
62
62
|
|
|
63
|
-
if Volt::DataStore.fetch.connected?
|
|
63
|
+
if Volt::DataStore.fetch(volt_app).connected?
|
|
64
64
|
# Generate a guid
|
|
65
65
|
@server_id = SecureRandom.uuid
|
|
66
66
|
# The PeerConnection's to peers
|
|
@@ -112,9 +112,9 @@ module Volt
|
|
|
112
112
|
|
|
113
113
|
# Return an array of peer records.
|
|
114
114
|
def peers
|
|
115
|
-
instances = @volt_app.store.
|
|
115
|
+
instances = @volt_app.store.active_volt_instances
|
|
116
116
|
|
|
117
|
-
instances.where
|
|
117
|
+
instances.where {|svr| svr.server_id !~ @server_id }.all.sync
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def connect_to_peers
|
|
@@ -186,7 +186,7 @@ module Volt
|
|
|
186
186
|
if peer
|
|
187
187
|
# Found the peer, retry if it has reported in in the last 2
|
|
188
188
|
# minutes.
|
|
189
|
-
if peer._time > (Time.now.to_i - DEAD_TIME)
|
|
189
|
+
if peer._time.to_i > (Time.now.to_i - DEAD_TIME)
|
|
190
190
|
# Peer reported in less than 2 minutes ago
|
|
191
191
|
return true
|
|
192
192
|
else
|
|
@@ -200,4 +200,4 @@ module Volt
|
|
|
200
200
|
|
|
201
201
|
end
|
|
202
202
|
end
|
|
203
|
-
end
|
|
203
|
+
end
|
|
@@ -36,7 +36,7 @@ module Volt
|
|
|
36
36
|
instances = @volt_app.store.active_volt_instances
|
|
37
37
|
instances.where(server_id: @server_id).first.then do |item|
|
|
38
38
|
ips = local_ips.join(',')
|
|
39
|
-
time = Time.now
|
|
39
|
+
time = Time.now
|
|
40
40
|
if item
|
|
41
41
|
item.assign_attributes(ips: ips, time: time, port: @port)
|
|
42
42
|
else
|
|
@@ -7,6 +7,7 @@ require 'volt/server/rack/opal_files'
|
|
|
7
7
|
require 'volt/server/rack/index_files'
|
|
8
8
|
require 'volt/server/rack/http_resource'
|
|
9
9
|
require 'volt/server/rack/sprockets_helpers_setup'
|
|
10
|
+
require 'volt/server/rack/http_content_types'
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
@@ -14,16 +15,17 @@ module Volt
|
|
|
14
15
|
class DefaultMiddlewareStack
|
|
15
16
|
# Setup on the middleware we can setup before booting components
|
|
16
17
|
def self.preboot_setup(volt_app, rack_app)
|
|
18
|
+
rack_app.use Rack::Chunked
|
|
17
19
|
# Should only be used in production
|
|
18
20
|
if Volt.config.deflate
|
|
19
21
|
rack_app.use Rack::Deflater
|
|
20
|
-
rack_app.use Rack::Chunked
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
rack_app.use Rack::ContentLength
|
|
24
25
|
rack_app.use Rack::KeepAlive
|
|
25
26
|
rack_app.use Rack::ConditionalGet
|
|
26
27
|
rack_app.use Rack::ETag
|
|
28
|
+
rack_app.use Rack::HttpContentTypes
|
|
27
29
|
|
|
28
30
|
rack_app.use Rack::Session::Cookie, {
|
|
29
31
|
key: 'rack.session',
|
|
@@ -42,6 +44,7 @@ module Volt
|
|
|
42
44
|
# Setup the middleware that we need to wait for components to boot before we
|
|
43
45
|
# can set them up.
|
|
44
46
|
def self.postboot_setup(volt_app, rack_app)
|
|
47
|
+
|
|
45
48
|
# Serve the opal files
|
|
46
49
|
opal_files = OpalFiles.new(rack_app, volt_app.app_url, volt_app.app_path, volt_app.component_paths)
|
|
47
50
|
volt_app.opal_files = opal_files
|
|
@@ -55,16 +58,17 @@ module Volt
|
|
|
55
58
|
|
|
56
59
|
rack_app.use HttpResource, volt_app, volt_app.router
|
|
57
60
|
|
|
61
|
+
|
|
58
62
|
# serve assets from public
|
|
59
63
|
rack_app.use Rack::Static,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
urls: [''],
|
|
65
|
+
root: ['public'],
|
|
66
|
+
index: 'index.html',
|
|
67
|
+
header_rules: [
|
|
68
|
+
[:all, { 'Cache-Control' => 'public, max-age=86400' }]
|
|
69
|
+
]
|
|
66
70
|
|
|
67
71
|
rack_app.run lambda { |env| [404, { 'Content-Type' => 'text/html; charset=utf-8' }, ['404 - page not found']] }
|
|
68
72
|
end
|
|
69
73
|
end
|
|
70
|
-
end
|
|
74
|
+
end
|
|
@@ -12,13 +12,16 @@ module Volt
|
|
|
12
12
|
# Find all app folders
|
|
13
13
|
@app_folders ||= begin
|
|
14
14
|
volt_app = File.expand_path(File.join(File.dirname(__FILE__), '../../../../app'))
|
|
15
|
-
app_folders = [volt_app, "#{@root}/app", "#{@root}/vendor/app"].map { |f| File.expand_path(f) }
|
|
16
15
|
|
|
17
16
|
# Gem folders with volt in them
|
|
18
17
|
# TODO: we should probably qualify this a bit more
|
|
19
|
-
app_folders
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
app_folders = [volt_app]
|
|
19
|
+
app_folders += Gem.loaded_specs.values.
|
|
20
|
+
select {|gem| gem.name =~ /^volt/ }.
|
|
21
|
+
sort { |a, b| dependent_sort(a, b) }.
|
|
22
|
+
map {|gem| "#{gem.full_gem_path}/app" }
|
|
23
|
+
|
|
24
|
+
app_folders += ["#{@root}/app", "#{@root}/vendor/app"].map { |f| File.expand_path(f) }
|
|
22
25
|
|
|
23
26
|
app_folders.uniq
|
|
24
27
|
end
|
|
@@ -77,6 +80,7 @@ module Volt
|
|
|
77
80
|
|
|
78
81
|
# Delay the loading of views
|
|
79
82
|
volt_app.templates.template_loader = -> { load_views_and_routes(volt_app) }
|
|
83
|
+
volt_app.url.routes_loader = -> { load_views_and_routes(volt_app) }
|
|
80
84
|
end
|
|
81
85
|
end
|
|
82
86
|
|
|
@@ -95,6 +99,10 @@ module Volt
|
|
|
95
99
|
# Evaluate returned code, the ```volt_app``` variable is set for access.
|
|
96
100
|
eval(code)
|
|
97
101
|
end
|
|
102
|
+
|
|
103
|
+
# Clear template loader
|
|
104
|
+
volt_app.templates.template_loader = nil
|
|
105
|
+
volt_app.url.routes_loader = nil
|
|
98
106
|
end
|
|
99
107
|
|
|
100
108
|
# Returns all paths for a specific component
|
|
@@ -119,5 +127,24 @@ module Volt
|
|
|
119
127
|
|
|
120
128
|
folders.flatten
|
|
121
129
|
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
# Determine if Gem::Specification b dependes on a
|
|
134
|
+
def dependent?(a, b)
|
|
135
|
+
name = a.name
|
|
136
|
+
b.dependencies.any? {|dep| dep.type == :runtime && dep.name == a.name }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def dependent_sort(a, b)
|
|
140
|
+
if dependent?(a, b)
|
|
141
|
+
-1
|
|
142
|
+
elsif dependent?(b, a)
|
|
143
|
+
1
|
|
144
|
+
else
|
|
145
|
+
0
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
122
149
|
end
|
|
123
150
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Middleware for parsing params of different restful content in HTTP endpoints.
|
|
2
|
+
# Content-type: application/json - is supported out of the box
|
|
3
|
+
#
|
|
4
|
+
# Much thanks to @achiu (https://github.com/achiu) for original version of this middleware
|
|
5
|
+
#
|
|
6
|
+
# New Parsers can be added in your app's config:
|
|
7
|
+
# Volt.setup do |config|
|
|
8
|
+
# config.http_content_types = {
|
|
9
|
+
# parsers: {
|
|
10
|
+
# 'application/roll' => proc { |body| {'rick_says' => 'never gonna give you up'}}
|
|
11
|
+
# }
|
|
12
|
+
# }
|
|
13
|
+
# end
|
|
14
|
+
|
|
15
|
+
module Rack
|
|
16
|
+
class HttpContentTypes
|
|
17
|
+
|
|
18
|
+
POST_BODY = 'rack.input'.freeze
|
|
19
|
+
FORM_INPUT = 'rack.request.form_input'.freeze
|
|
20
|
+
FORM_HASH = 'rack.request.form_hash'.freeze
|
|
21
|
+
|
|
22
|
+
JSON_PARSER = proc { |data| JSON.parse data }
|
|
23
|
+
ERROR_HANDLER = proc { |err, type| [400, {}, ['']] }
|
|
24
|
+
|
|
25
|
+
attr_reader :parsers, :handlers, :logger
|
|
26
|
+
|
|
27
|
+
def initialize(app, options = {})
|
|
28
|
+
@app = app
|
|
29
|
+
@options = Volt.config.http_content_types ? Volt.config.http_content_types.dup : {}
|
|
30
|
+
@options.merge!(options)
|
|
31
|
+
@parsers = @options[:parsers] || {}
|
|
32
|
+
@handlers = @options[:handlers] || {}
|
|
33
|
+
unless parsers.detect { |content_type, _| 'json'.match(content_type) }
|
|
34
|
+
@parsers.merge!({ %r{json} => JSON_PARSER })
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def call(env)
|
|
39
|
+
type = Rack::Request.new(env).media_type
|
|
40
|
+
parser = parsers.detect { |content_type, _| type.match(content_type) } if type
|
|
41
|
+
return @app.call(env) unless parser
|
|
42
|
+
body = env[POST_BODY].read ; env[POST_BODY].rewind
|
|
43
|
+
return @app.call(env) unless body && !body.empty?
|
|
44
|
+
begin
|
|
45
|
+
parsed = parser.last.call body
|
|
46
|
+
env.update FORM_HASH => parsed, FORM_INPUT => env[POST_BODY]
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
warn! e, type
|
|
49
|
+
handler = handlers.detect { |content_type, _| type.match(content_type) }
|
|
50
|
+
handler ||= ['default', ERROR_HANDLER]
|
|
51
|
+
return handler.last.call(e, type)
|
|
52
|
+
end
|
|
53
|
+
@app.call env
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def warn!(error, content_type)
|
|
57
|
+
return unless Volt.logger
|
|
58
|
+
message = "[Rack::HttpContentType] Error on %s : %s" % [content_type, error.to_s]
|
|
59
|
+
Volt.logger.warn message
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|