volt 0.9.3.pre3 → 0.9.3.pre4
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/CHANGELOG.md +6 -2
- data/app/volt/models/user.rb +5 -0
- data/app/volt/tasks/store_tasks.rb +2 -2
- data/app/volt/tasks/user_tasks.rb +1 -1
- data/lib/volt/cli/asset_compile.rb +0 -2
- data/lib/volt/cli/generate.rb +8 -3
- data/lib/volt/cli.rb +3 -9
- data/lib/volt/controllers/actions.rb +6 -1
- data/lib/volt/controllers/http_controller.rb +16 -7
- data/lib/volt/controllers/model_controller.rb +21 -0
- data/lib/volt/models/array_model.rb +26 -3
- data/lib/volt/models/model.rb +18 -19
- data/lib/volt/models/persistors/array_store.rb +2 -10
- data/lib/volt/models/root_models/store_root.rb +17 -4
- data/lib/volt/models/validations/validations.rb +1 -1
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/models.rb +1 -1
- data/lib/volt/page/bindings/attribute_binding.rb +5 -4
- data/lib/volt/page/bindings/base_binding.rb +17 -0
- data/lib/volt/page/bindings/content_binding.rb +7 -5
- data/lib/volt/page/bindings/each_binding.rb +62 -51
- data/lib/volt/page/bindings/event_binding.rb +14 -0
- data/lib/volt/page/bindings/view_binding.rb +1 -1
- data/lib/volt/reactive/computation.rb +22 -13
- data/lib/volt/reactive/dependency.rb +0 -24
- data/lib/volt/router/routes.rb +35 -0
- data/lib/volt/server/forking_server.rb +26 -3
- data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +1 -1
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
- data/lib/volt/server/message_bus/peer_to_peer.rb +28 -21
- data/lib/volt/server/middleware/default_middleware_stack.rb +67 -0
- data/lib/volt/server/middleware/middleware_stack.rb +58 -0
- data/lib/volt/server/rack/http_request.rb +1 -1
- data/lib/volt/server/rack/http_resource.rb +7 -0
- data/lib/volt/server/rack/keep_alive.rb +20 -0
- data/lib/volt/server/socket_connection_handler.rb +10 -1
- data/lib/volt/server.rb +6 -76
- data/lib/volt/utils/promise_extensions.rb +5 -1
- data/lib/volt/utils/set_patch.rb +25 -0
- data/lib/volt/utils/timers.rb +12 -0
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +13 -1
- data/lib/volt/volt/server_setup/app.rb +19 -1
- data/lib/volt/volt/users.rb +11 -22
- data/lib/volt.rb +1 -0
- data/spec/apps/kitchen_sink/Gemfile +1 -1
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +22 -0
- data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +10 -0
- data/spec/apps/kitchen_sink/app/main/views/main/store_demo.html +9 -0
- data/spec/controllers/http_controller_spec.rb +27 -0
- data/spec/integration/bindings_spec.rb +29 -0
- data/spec/integration/store_spec.rb +7 -7
- data/spec/models/associations_spec.rb +1 -1
- data/spec/models/model_spec.rb +10 -0
- data/spec/models/permissions_spec.rb +7 -4
- data/spec/reactive/computation_spec.rb +33 -5
- data/spec/router/routes_spec.rb +69 -0
- data/spec/server/middleware/middleware_handler.rb +24 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/tasks/user_tasks_spec.rb +3 -2
- data/templates/project/Gemfile.tt +2 -2
- data/templates/project/config/base/index.html +5 -1
- metadata +10 -5
- data/spec/apps/kitchen_sink/app/main/views/main/store.html +0 -9
- data/templates/project/app/main/models/.empty_directory +0 -0
@@ -19,13 +19,20 @@ module Volt
|
|
19
19
|
value = @context.instance_eval(&@getter)
|
20
20
|
rescue => e
|
21
21
|
Volt.logger.error("EachBinding Error: #{e.inspect}")
|
22
|
+
if RUBY_PLATFORM == 'opal'
|
23
|
+
Volt.logger.error(`#{@getter}`)
|
24
|
+
else
|
25
|
+
Volt.logger.error(e.backtrace.join("\n"))
|
26
|
+
end
|
27
|
+
|
22
28
|
value = []
|
23
29
|
end
|
24
30
|
|
25
31
|
value
|
26
|
-
end.watch_and_resolve!
|
27
|
-
update
|
28
|
-
|
32
|
+
end.watch_and_resolve!(
|
33
|
+
method(:update),
|
34
|
+
method(:getter_fail)
|
35
|
+
)
|
29
36
|
end
|
30
37
|
|
31
38
|
# When a changed event happens, we update to the new size.
|
@@ -64,69 +71,73 @@ module Volt
|
|
64
71
|
end
|
65
72
|
|
66
73
|
def item_removed(position)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@templates[position].context.locals["_#{@item_name}_dependency".to_sym].remove
|
74
|
+
# Remove dependency
|
75
|
+
@templates[position].context.locals[:_index_dependency].remove
|
76
|
+
@templates[position].context.locals["_#{@item_name}_dependency".to_sym].remove
|
71
77
|
|
72
|
-
|
73
|
-
|
74
|
-
|
78
|
+
@templates[position].remove_anchors
|
79
|
+
@templates[position].remove
|
80
|
+
@templates.delete_at(position)
|
75
81
|
|
76
|
-
|
77
|
-
|
78
|
-
end
|
82
|
+
# Removed at the position, update context for every item after this position
|
83
|
+
update_indexes_after(position)
|
79
84
|
end
|
80
85
|
|
81
86
|
def item_added(position)
|
82
|
-
|
83
|
-
binding_name = @@binding_number
|
84
|
-
@@binding_number += 1
|
85
|
-
|
86
|
-
if position >= @templates.size
|
87
|
-
# Setup new bindings in the spot we want to insert the item
|
88
|
-
dom_section.insert_anchor_before_end(binding_name)
|
89
|
-
else
|
90
|
-
# Insert the item before an existing item
|
91
|
-
dom_section.insert_anchor_before(binding_name, @templates[position].binding_name)
|
92
|
-
end
|
87
|
+
item_context = nil
|
93
88
|
|
94
|
-
|
95
|
-
|
96
|
-
item_context.locals[@item_name.to_sym] = proc { @value[item_context.locals[:_index_value]] }
|
89
|
+
binding_name = @@binding_number
|
90
|
+
@@binding_number += 1
|
97
91
|
|
98
|
-
|
99
|
-
|
92
|
+
if position >= @templates.size
|
93
|
+
# Setup new bindings in the spot we want to insert the item
|
94
|
+
dom_section.insert_anchor_before_end(binding_name)
|
95
|
+
else
|
96
|
+
# Insert the item before an existing item
|
97
|
+
dom_section.insert_anchor_before(binding_name, @templates[position].binding_name)
|
98
|
+
end
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
100
|
+
# TODORW: :parent => @value may change
|
101
|
+
item_context = SubContext.new({ _index_value: position, parent: @value }, @context)
|
102
|
+
item_context.locals[@item_name.to_sym] = proc do
|
103
|
+
# Fetch only whats there currently, no promises.
|
104
|
+
Volt.run_in_mode(:no_model_promises) do
|
105
|
+
# puts "GET AT: #{item_context.locals[:_index_value]}"
|
106
|
+
@value[item_context.locals[:_index_value]]
|
105
107
|
end
|
108
|
+
end
|
106
109
|
|
107
|
-
|
108
|
-
|
109
|
-
item_context.locals["_#{@item_name}_dependency".to_sym] = value_dependency
|
110
|
+
position_dependency = Dependency.new
|
111
|
+
item_context.locals[:_index_dependency] = position_dependency
|
110
112
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
113
|
+
# Get and set index
|
114
|
+
item_context.locals[:_index=] = proc do |val|
|
115
|
+
position_dependency.changed!
|
116
|
+
item_context.locals[:_index_value] = val
|
117
|
+
end
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
item_context.locals[@index_name.to_sym] = proc do
|
120
|
-
position_dependency.depend
|
121
|
-
item_context.locals[:_index_value]
|
122
|
-
end
|
123
|
-
end
|
119
|
+
# Get and set value
|
120
|
+
value_dependency = Dependency.new
|
121
|
+
item_context.locals["_#{@item_name}_dependency".to_sym] = value_dependency
|
124
122
|
|
125
|
-
|
126
|
-
|
123
|
+
item_context.locals["#{@item_name}=".to_sym] = proc do |val|
|
124
|
+
value_dependency.changed!
|
125
|
+
@value[item_context.locals[:_index_value]] = val
|
126
|
+
end
|
127
127
|
|
128
|
-
|
128
|
+
# If the user provides an each_with_index, we can assign the lookup for the index
|
129
|
+
# variable here.
|
130
|
+
if @index_name
|
131
|
+
item_context.locals[@index_name.to_sym] = proc do
|
132
|
+
position_dependency.depend
|
133
|
+
item_context.locals[:_index_value]
|
134
|
+
end
|
129
135
|
end
|
136
|
+
|
137
|
+
item_template = TemplateRenderer.new(@volt_app, @target, item_context, binding_name, @template_name)
|
138
|
+
@templates.insert(position, item_template)
|
139
|
+
|
140
|
+
update_indexes_after(position)
|
130
141
|
end
|
131
142
|
|
132
143
|
# When items are added or removed in the middle of the list, we need
|
@@ -40,6 +40,20 @@ module Volt
|
|
40
40
|
# Call the proc the user setup for the event in context,
|
41
41
|
# pass in the wrapper for the JS event
|
42
42
|
result = @context.instance_exec(event, &call_proc)
|
43
|
+
|
44
|
+
# The following doesn't work due to the promise already chained issue.
|
45
|
+
# # Ignore native objects.
|
46
|
+
# result = nil unless BasicObject === result
|
47
|
+
|
48
|
+
# # if the result is a promise, log an exception if it failed and wasn't
|
49
|
+
# # handled
|
50
|
+
# if result.is_a?(Promise) && !result.next
|
51
|
+
# result.fail do |err|
|
52
|
+
# Volt.logger.error("EventBinding Error: promise returned from event binding #{@event_name} was rejected")
|
53
|
+
# Volt.logger.error(err)
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
|
43
57
|
end
|
44
58
|
|
45
59
|
@listener = page.events.add(event_name, self, handler)
|
@@ -225,7 +225,7 @@ module Volt
|
|
225
225
|
def call_ready
|
226
226
|
if @controller
|
227
227
|
# Set the current section on the controller if it wants so it can manipulate
|
228
|
-
# the dom if needed
|
228
|
+
# the dom if needed.
|
229
229
|
# Only assign sections for action's, so we don't get AttributeSections bound
|
230
230
|
# also.
|
231
231
|
if @controller.respond_to?(:section=)
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Volt
|
2
4
|
class Computation
|
3
5
|
@@current = nil
|
4
|
-
@@flush_queue =
|
6
|
+
@@flush_queue = Set.new
|
5
7
|
|
6
8
|
def self.current=(val)
|
7
9
|
@@current = val
|
@@ -111,7 +113,7 @@ module Volt
|
|
111
113
|
@@timer = nil
|
112
114
|
|
113
115
|
computations = @@flush_queue
|
114
|
-
@@flush_queue =
|
116
|
+
@@flush_queue = Set.new
|
115
117
|
|
116
118
|
computations.each(&:compute!)
|
117
119
|
|
@@ -171,16 +173,12 @@ class Proc
|
|
171
173
|
end
|
172
174
|
|
173
175
|
# Does an watch and if the result is a promise, resolves the promise.
|
174
|
-
# #watch_and_resolve! takes
|
175
|
-
#
|
176
|
+
# #watch_and_resolve! takes two procs, one for the promise resolution (then), and
|
177
|
+
# one for promise rejection (fail).
|
176
178
|
#
|
177
179
|
# Example:
|
178
180
|
# -> { }
|
179
|
-
def watch_and_resolve!(yield_nil_for_unresolved_promise=false)
|
180
|
-
unless block_given?
|
181
|
-
fail 'watch_and_resolve! requires a block to call when the value is resolved or another value other than a promise is returned in the watch.'
|
182
|
-
end
|
183
|
-
|
181
|
+
def watch_and_resolve!(success, failure=nil, yield_nil_for_unresolved_promise=false)
|
184
182
|
# Keep results between runs
|
185
183
|
result = nil
|
186
184
|
|
@@ -194,24 +192,35 @@ class Proc
|
|
194
192
|
# Often you want a to be alerted that an unresolved promise is waiting
|
195
193
|
# to be resolved.
|
196
194
|
if yield_nil_for_unresolved_promise && !result.resolved?
|
197
|
-
|
195
|
+
success.call(nil)
|
198
196
|
end
|
199
197
|
|
200
|
-
|
198
|
+
# The handler gets called once the promise resolves or is rejected.
|
199
|
+
handler = lambda do |&after_handle|
|
201
200
|
# Check to make sure that a new value didn't get reactively pushed
|
202
201
|
# before the promise resolved.
|
203
202
|
if last_promise.is_a?(Promise) && last_promise == result
|
204
203
|
# Don't resolve if the computation was stopped
|
205
204
|
unless comp.stopped?
|
206
|
-
|
205
|
+
# Call the passed in proc
|
206
|
+
after_handle.call
|
207
207
|
end
|
208
208
|
|
209
209
|
# Clear result for GC
|
210
210
|
result = nil
|
211
211
|
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
result.then do |final|
|
216
|
+
# Call the success proc passing in the resolved value
|
217
|
+
handler.call { success.call(final) }
|
218
|
+
end.fail do |err|
|
219
|
+
# call the fail callback, passing in the error
|
220
|
+
handler.call { failure.call(err) if failure }
|
212
221
|
end
|
213
222
|
else
|
214
|
-
|
223
|
+
success.call(result)
|
215
224
|
|
216
225
|
# Clear result for GC
|
217
226
|
result = nil
|
@@ -1,29 +1,5 @@
|
|
1
|
-
# Temp until https://github.com/opal/opal/pull/596
|
2
1
|
require 'set'
|
3
2
|
|
4
|
-
class Set
|
5
|
-
def delete(o)
|
6
|
-
if include?(o)
|
7
|
-
@hash.delete(o)
|
8
|
-
true
|
9
|
-
else
|
10
|
-
nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def delete_if
|
15
|
-
block_given? or return enum_for(__method__)
|
16
|
-
# @hash.delete_if should be faster, but using it breaks the order
|
17
|
-
# of enumeration in subclasses.
|
18
|
-
select { |o| yield o }.each { |o| @hash.delete(o) }
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_a
|
23
|
-
@hash.keys
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
3
|
module Volt
|
28
4
|
# Dependencies are used to track the current computation so it can be re-run
|
29
5
|
# at a later point if this dependency changes.
|
data/lib/volt/router/routes.rb
CHANGED
@@ -68,6 +68,7 @@ module Volt
|
|
68
68
|
end
|
69
69
|
|
70
70
|
# Add server side routes
|
71
|
+
|
71
72
|
def get(path, params)
|
72
73
|
create_route(:get, path, params)
|
73
74
|
end
|
@@ -88,6 +89,35 @@ module Volt
|
|
88
89
|
create_route(:delete, path, params)
|
89
90
|
end
|
90
91
|
|
92
|
+
#Create rest endpoints
|
93
|
+
def rest(path, params)
|
94
|
+
endpoints = (params.delete(:only) || [:index, :show, :create, :update, :destroy]).to_a
|
95
|
+
endpoints = endpoints - params.delete(:except).to_a
|
96
|
+
endpoints.each do |endpoint|
|
97
|
+
self.send(('restful_' + endpoint.to_s).to_sym, path, params)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def restful_index(base_path, params)
|
102
|
+
get(base_path, params.merge(action: 'index'))
|
103
|
+
end
|
104
|
+
|
105
|
+
def restful_create(base_path, params)
|
106
|
+
post(base_path, params.merge(action: 'create'))
|
107
|
+
end
|
108
|
+
|
109
|
+
def restful_show(base_path, params)
|
110
|
+
get(path_with_id(base_path), params.merge(action: 'show'))
|
111
|
+
end
|
112
|
+
|
113
|
+
def restful_update(base_path, params)
|
114
|
+
put(path_with_id(base_path), params.merge(action: 'update'))
|
115
|
+
end
|
116
|
+
|
117
|
+
def restful_destroy(base_path, params)
|
118
|
+
delete(path_with_id(base_path), params.merge(action: 'destroy'))
|
119
|
+
end
|
120
|
+
|
91
121
|
# Takes in params and generates a path and the remaining params
|
92
122
|
# that should be shown in the url. The extra "unused" params
|
93
123
|
# will be tacked onto the end of the url ?param1=value1, etc...
|
@@ -296,5 +326,10 @@ module Volt
|
|
296
326
|
def has_binding?(string)
|
297
327
|
string.index('{{') && string.index('}}')
|
298
328
|
end
|
329
|
+
|
330
|
+
#Append an id to a given path
|
331
|
+
def path_with_id(base_path)
|
332
|
+
base_path + '/{{ id }}'
|
333
|
+
end
|
299
334
|
end
|
300
335
|
end
|
@@ -59,7 +59,7 @@ module Volt
|
|
59
59
|
@reader.close
|
60
60
|
|
61
61
|
volt_app = @server.boot_volt
|
62
|
-
@rack_app =
|
62
|
+
@rack_app = volt_app.middleware
|
63
63
|
|
64
64
|
# Set the drb object locally
|
65
65
|
@dispatcher = Dispatcher.new(volt_app)
|
@@ -110,7 +110,19 @@ module Volt
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
|
113
|
+
# When passing an object, Drb will not marshal it if any of its subobjects
|
114
|
+
# are not marshalable. So we split the marshable and not marshalbe objects
|
115
|
+
# then re-merge them so we get real copies of most values (which are
|
116
|
+
# needed in some cases) Then we merge them back into a new hash.
|
117
|
+
def call_on_child(env_base, env_other)
|
118
|
+
env = env_base
|
119
|
+
|
120
|
+
# TODO: this requires quite a few trips, there's probably a faster way
|
121
|
+
# to handle this.
|
122
|
+
env_other.each_pair do |key, value|
|
123
|
+
env[key] = value
|
124
|
+
end
|
125
|
+
|
114
126
|
status, headers, body = @rack_app.call(env)
|
115
127
|
|
116
128
|
# Extract the body to pass as a string. We need to do this
|
@@ -138,7 +150,18 @@ module Volt
|
|
138
150
|
if @exiting
|
139
151
|
[500, {}, 'Server Exiting']
|
140
152
|
else
|
141
|
-
|
153
|
+
env_base = {}
|
154
|
+
env_other = {}
|
155
|
+
|
156
|
+
env.each_pair do |key, value|
|
157
|
+
if [String, TrueClass, FalseClass, Array].include?(value.class)
|
158
|
+
env_base.merge!(key => value)
|
159
|
+
else
|
160
|
+
env_other.merge!(key => value)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
status, headers, body_str = @server_proxy.call_on_child(env_base, env_other)
|
142
165
|
|
143
166
|
[status, headers, StringIO.new(body_str)]
|
144
167
|
end
|
@@ -91,7 +91,7 @@ module Volt
|
|
91
91
|
begin
|
92
92
|
@message_encoder.send_message(@socket, message)
|
93
93
|
# 'Error: closed stream' comes in sometimes
|
94
|
-
rescue Errno::ECONNREFUSED, Errno::EPIPE,
|
94
|
+
rescue Errno::ECONNREFUSED, Errno::EPIPE, IOError => e # was also rescuing Error
|
95
95
|
if reconnect!
|
96
96
|
retry
|
97
97
|
else
|
@@ -34,7 +34,7 @@ module Volt
|
|
34
34
|
# Register this server as active with the database
|
35
35
|
def register
|
36
36
|
instances = @page.store._active_volt_instances
|
37
|
-
instances.where(server_id: @server_id).
|
37
|
+
instances.where(server_id: @server_id).first.then do |item|
|
38
38
|
ips = local_ips.join(',')
|
39
39
|
time = Time.now.to_i
|
40
40
|
if item
|
@@ -58,22 +58,26 @@ module Volt
|
|
58
58
|
attr_reader :server_id, :page
|
59
59
|
|
60
60
|
def initialize(volt_app)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
if Volt::DataStore.fetch.connected?
|
62
|
+
# Generate a guid
|
63
|
+
@server_id = SecureRandom.uuid
|
64
|
+
# The PeerConnection's to peers
|
65
|
+
@peer_connections = {}
|
66
|
+
# The server id's for each peer we're connected to
|
67
|
+
@peer_server_ids = {}
|
67
68
|
|
68
|
-
|
69
|
+
@page = volt_app.page
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
setup_peer_server
|
72
|
+
start_tracker
|
72
73
|
|
73
|
-
|
74
|
-
|
74
|
+
Thread.new do
|
75
|
+
sleep 1
|
75
76
|
|
76
|
-
|
77
|
+
connect_to_peers
|
78
|
+
end
|
79
|
+
else
|
80
|
+
Volt.logger.error('Unable to connect to the database. Volt will still run, but the message bus requires a database connection to setup connections between nodes, so the message bus has been disabled. This means updates will not be propigated between instances (server, console, runners, etc...)')
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
@@ -110,7 +114,7 @@ module Volt
|
|
110
114
|
def peers
|
111
115
|
instances = @page.store._active_volt_instances
|
112
116
|
|
113
|
-
instances.where(server_id: {'$ne' => @server_id}).
|
117
|
+
instances.where(server_id: {'$ne' => @server_id}).all.sync
|
114
118
|
end
|
115
119
|
|
116
120
|
def connect_to_peers
|
@@ -118,13 +122,16 @@ module Volt
|
|
118
122
|
# Start connecting to all at the same time. Since most will connect or
|
119
123
|
# timeout, this is the desired behaviour.
|
120
124
|
Thread.new do
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
125
|
+
# sometimes we get nil peers for some reason
|
126
|
+
if peer
|
127
|
+
peer_connection = PeerConnection.connect_to(self, peer._ips, peer._port)
|
128
|
+
|
129
|
+
if peer_connection
|
130
|
+
add_peer_connection(peer_connection)
|
131
|
+
else
|
132
|
+
# remove if not alive anymore.
|
133
|
+
still_alive?(peer._server_id)
|
134
|
+
end
|
128
135
|
end
|
129
136
|
end
|
130
137
|
end
|
@@ -177,7 +184,7 @@ module Volt
|
|
177
184
|
# Unable to write to the socket, retry until the instance is no
|
178
185
|
# longer marking its self as active in the database
|
179
186
|
peer_table = @page.store._active_volt_instances
|
180
|
-
peer = peer_table.where(server_id: peer_server_id).
|
187
|
+
peer = peer_table.where(server_id: peer_server_id).first.sync
|
181
188
|
if peer
|
182
189
|
# Found the peer, retry if it has reported in in the last 2
|
183
190
|
# minutes.
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Responsible for setting up all "out of the box" middleware on a Volt app.
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'volt/server/rack/keep_alive'
|
5
|
+
require 'volt/server/rack/quiet_common_logger'
|
6
|
+
require 'volt/server/rack/opal_files'
|
7
|
+
require 'volt/server/rack/index_files'
|
8
|
+
require 'volt/server/rack/http_resource'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
module Volt
|
13
|
+
class DefaultMiddlewareStack
|
14
|
+
# Setup on the middleware we can setup before booting components
|
15
|
+
def self.preboot_setup(volt_app, rack_app)
|
16
|
+
# Should only be used in production
|
17
|
+
if Volt.config.deflate
|
18
|
+
rack_app.use Rack::Deflater
|
19
|
+
rack_app.use Rack::Chunked
|
20
|
+
end
|
21
|
+
|
22
|
+
rack_app.use Rack::ContentLength
|
23
|
+
rack_app.use Rack::KeepAlive
|
24
|
+
rack_app.use Rack::ConditionalGet
|
25
|
+
rack_app.use Rack::ETag
|
26
|
+
|
27
|
+
rack_app.use Rack::Session::Cookie, {
|
28
|
+
:key => 'rack.session',
|
29
|
+
# :domain => 'localhost.com',
|
30
|
+
:path => '/',
|
31
|
+
:expire_after => 2592000,
|
32
|
+
:secret => Volt.config.app_secret
|
33
|
+
}
|
34
|
+
|
35
|
+
rack_app.use QuietCommonLogger
|
36
|
+
rack_app.use Rack::ShowExceptions
|
37
|
+
end
|
38
|
+
|
39
|
+
# Setup the middleware that we need to wait for components to boot before we
|
40
|
+
# can set them up.
|
41
|
+
def self.postboot_setup(volt_app, rack_app)
|
42
|
+
component_paths = volt_app.component_paths
|
43
|
+
rack_app.map '/components' do
|
44
|
+
run ComponentHandler.new(component_paths)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Serve the opal files
|
48
|
+
opal_files = OpalFiles.new(rack_app, volt_app.app_path, volt_app.component_paths)
|
49
|
+
|
50
|
+
# Serve the main html files from public, also figure out
|
51
|
+
# which JS/CSS files to serve.
|
52
|
+
rack_app.use IndexFiles, volt_app, volt_app.component_paths, opal_files
|
53
|
+
|
54
|
+
rack_app.use HttpResource, volt_app, volt_app.router
|
55
|
+
|
56
|
+
rack_app.use Rack::Static,
|
57
|
+
urls: ['/'],
|
58
|
+
root: 'config/base',
|
59
|
+
index: '',
|
60
|
+
header_rules: [
|
61
|
+
[:all, { 'Cache-Control' => 'public, max-age=86400' }]
|
62
|
+
]
|
63
|
+
|
64
|
+
rack_app.run lambda { |env| [404, { 'Content-Type' => 'text/html; charset=utf-8' }, ['404 - page not found']] }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Volt::MiddlewareStack provides an interface where app code can add custom
|
2
|
+
# rack middleware. Volt.current_app.middleware returns an instance of
|
3
|
+
# Volt::MiddlewareStack, and apps can call #use to add in more middleware.
|
4
|
+
|
5
|
+
module Volt
|
6
|
+
class MiddlewareStack
|
7
|
+
attr_reader :middlewares
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
# Setup the next app
|
11
|
+
@middlewares = []
|
12
|
+
@maps = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Set the app that gets called after the middleware runs
|
16
|
+
# def set_app(app)
|
17
|
+
# @app = app
|
18
|
+
# end
|
19
|
+
|
20
|
+
def use(*args, &block)
|
21
|
+
@middlewares << [args, block]
|
22
|
+
|
23
|
+
# invalidate builder, so it gets built again
|
24
|
+
@builder = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def map(path, &block)
|
28
|
+
@maps << [path, block]
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(app)
|
32
|
+
@app = app
|
33
|
+
end
|
34
|
+
|
35
|
+
# Builds a new Rack::Builder with the middleware and the app
|
36
|
+
def build
|
37
|
+
@builder = Rack::Builder.new
|
38
|
+
|
39
|
+
@maps.each do |path, block|
|
40
|
+
@builder.map(path, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
@middlewares.each do |middleware|
|
44
|
+
@builder.use(*middleware[0], &middleware[1])
|
45
|
+
end
|
46
|
+
|
47
|
+
@builder.run(@app)
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(env)
|
51
|
+
unless @builder
|
52
|
+
build
|
53
|
+
end
|
54
|
+
|
55
|
+
@builder.call(env)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -5,7 +5,7 @@ module Volt
|
|
5
5
|
# A request object for a HttpController. See Rack::Request for more details
|
6
6
|
class HttpRequest < Rack::Request
|
7
7
|
# Returns the request format
|
8
|
-
# /
|
8
|
+
# /acticles/index.html => html
|
9
9
|
# Defaults to the media_type of the request
|
10
10
|
def format
|
11
11
|
path_format || media_type
|
@@ -40,6 +40,13 @@ module Volt
|
|
40
40
|
namespace_module = Object.const_get(namespace.camelize.to_sym)
|
41
41
|
klass = namespace_module.const_get(controller_name.camelize.to_sym)
|
42
42
|
controller = klass.new(@volt_app, params, request)
|
43
|
+
|
44
|
+
# Use the 'meta' thread local to set the user_id for Volt.current_user
|
45
|
+
meta_data = {}
|
46
|
+
user_id = request.cookies['user_id']
|
47
|
+
meta_data['user_id'] = user_id if user_id
|
48
|
+
Thread.current['meta'] = meta_data
|
49
|
+
|
43
50
|
controller.perform(action)
|
44
51
|
end
|
45
52
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rack
|
2
|
+
# TODO: For some reason in Rack (or maybe thin), 304 headers close
|
3
|
+
# the http connection. We might need to make this check if keep
|
4
|
+
# alive was in the request.
|
5
|
+
class KeepAlive
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
status, headers, body = @app.call(env)
|
12
|
+
|
13
|
+
if status == 304 && env['HTTP_CONNECTION'] && env['HTTP_CONNECTION'].downcase == 'keep-alive'
|
14
|
+
headers['Connection'] = 'keep-alive'
|
15
|
+
end
|
16
|
+
|
17
|
+
[status, headers, body]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|