hyper-mesh 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile +7 -2
- data/README.md +112 -87
- data/Rakefile +6 -1
- data/docs/action_cable_quickstart.md +20 -16
- data/docs/activerecord_api.md +23 -17
- data/docs/authorization-policies.md +45 -35
- data/docs/client_side_scoping.md +5 -5
- data/docs/configuration_details.md +6 -46
- data/docs/pusher_faker_quickstart.md +7 -68
- data/docs/pusher_quickstart.md +7 -68
- data/docs/simple_poller_quickstart.md +6 -67
- data/docs/todo-example.md +2 -2
- data/docs/word_game.md +3 -1
- data/docs/words-example.md +2 -3
- data/examples/action-cable/Gemfile +2 -1
- data/examples/action-cable/Gemfile.lock +73 -54
- data/examples/action-cable/config/initializers/{hyper_mesh.rb → hyperloop.rb} +1 -1
- data/examples/action-cable/config/routes.rb +1 -1
- data/hyper-mesh.gemspec +10 -4
- data/lib/active_record_base.rb +3 -3
- data/{examples/action-cable-production-mode/log/.keep → lib/acts_as_string.rb} +0 -0
- data/lib/hyper-mesh.rb +11 -19
- data/lib/hyper_mesh/version.rb +3 -0
- data/lib/hypermesh/version.rb +1 -1
- data/lib/reactive_record/active_record/class_methods.rb +10 -3
- data/lib/reactive_record/active_record/instance_methods.rb +8 -0
- data/lib/reactive_record/active_record/public_columns_hash.rb +8 -2
- data/lib/reactive_record/active_record/reactive_record/collection.rb +0 -1
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +2 -1
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +55 -63
- data/lib/reactive_record/active_record/reactive_record/operations.rb +51 -0
- data/lib/reactive_record/active_record/reactive_record/reactive_set_relationship_helpers.rb +3 -3
- data/lib/reactive_record/active_record/reactive_record/while_loading.rb +93 -84
- data/lib/reactive_record/broadcast.rb +183 -0
- data/lib/reactive_record/permissions.rb +2 -2
- data/reactive_record_test_app/Gemfile +6 -2
- data/reactive_record_test_app/Gemfile.lock +120 -60
- data/reactive_record_test_app/app/assets/javascripts/application.rb +3 -5
- data/reactive_record_test_app/app/assets/javascripts/bigdecimal.rb +1 -0
- data/reactive_record_test_app/app/assets/javascripts/reactive_record_config.js +2 -2
- data/reactive_record_test_app/app/controllers/application_controller.rb +3 -3
- data/reactive_record_test_app/app/controllers/home_controller.rb +1 -1
- data/reactive_record_test_app/app/models/models.rb.erb +6 -0
- data/reactive_record_test_app/config/application.rb +2 -0
- data/reactive_record_test_app/config/environments/development.rb +1 -1
- data/reactive_record_test_app/config/routes.rb +1 -2
- data/reactive_record_test_app/db/seeds.rb +6 -0
- data/reactive_record_test_app/script/rails +0 -0
- data/reactive_record_test_app/spec-opal/active-record/rendering_spec.rb +11 -2
- data/reactive_record_test_app/spec-opal/active-record/save_spec.rb +3 -4
- data/reactive_record_test_app/spec-opal/spec_helper.js.rb +1 -1
- data/reactive_record_test_app/spec-opal/test_spec.rb +7 -0
- data/reactive_record_test_app/spec_dont_run/README.md +7 -0
- data/reactive_record_test_app/{spec-opal/active-record → spec_dont_run/active_record_broken}/permissions_spec.rb +0 -0
- data/reactive_record_test_app/{spec-opal/active-record → spec_dont_run/active_record_broken}/prerendering_spec.rb +1 -0
- data/spec/{synchromesh/aaa-unit_tests/connection_spec.rb → batch1/aaa-unit_tests/connection_movedspec.rb} +0 -0
- data/spec/{synchromesh → batch1}/aaa-unit_tests/dummy_value_spec.rb +2 -2
- data/spec/{synchromesh → batch1}/column_types/column_type_spec.rb +2 -2
- data/spec/{synchromesh → batch1}/crud_access_regulation/broadcast_controls_access_spec.rb +1 -1
- data/spec/{synchromesh → batch1}/crud_access_regulation/model_policies_spec.rb +6 -6
- data/spec/batch1/misc/access_like_hash_spec.rb +43 -0
- data/spec/batch1/misc/while_loading_spec.rb +196 -0
- data/spec/{synchromesh → batch1}/policies/regulate_all_broadcasts_spec.rb +12 -12
- data/spec/{synchromesh → batch1}/policies/regulate_broadcast_spec.rb +25 -25
- data/spec/{synchromesh/integration → batch2}/authorization_spec.rb +8 -7
- data/spec/{synchromesh/integration → batch2}/default_scope_spec.rb +2 -2
- data/spec/{synchromesh/integration → batch2}/has_many_through_spec.rb +2 -2
- data/spec/{synchromesh/integration → batch2}/relationships_spec.rb +3 -3
- data/spec/{reactive_record → batch3}/auto_load_itself_spec.rb +1 -1
- data/spec/{reactive_record → batch3}/edge_cases_spec.rb +1 -1
- data/spec/{reactive_record → batch3}/finder_method_spec.rb +1 -1
- data/spec/{reactive_record → batch3}/many_to_many_spec.rb +2 -2
- data/spec/{reactive_record → batch3}/pry_rescue_xspec.rb +0 -0
- data/{examples/action-cable-production-mode/public/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css → spec/batch3/readme.txt} +0 -0
- data/spec/{reactive_record → batch3}/revert_spec.rb +2 -2
- data/spec/{reactive_record → batch3}/save_while_loading_spec.rb +1 -1
- data/spec/{reactive_record → batch3}/update_associations_spec.rb +2 -2
- data/spec/{reactive_record → batch3}/update_scopes_spec.rb +2 -2
- data/spec/{synchromesh/integration → batch4}/saving_during_commit_spec.rb +2 -2
- data/spec/{synchromesh/integration → batch4}/scope_spec.rb +30 -2
- data/spec/{synchromesh/examples → batch4}/scoped_todos_spec.rb +3 -3
- data/spec/{synchromesh/integration → batch4}/synchromesh_spec.rb +2 -2
- data/spec/{synchromesh/examples → examples}/dictionary.rb +2 -2
- data/spec/{synchromesh/examples → examples}/dictionary_with_client_scopes.rb +2 -2
- data/spec/{synchromesh/examples → examples}/random_examples.rb +1 -1
- data/spec/{reactive_record/play.rb → play_ground.rb} +0 -0
- data/spec/{reactive_record/factory.rb → reactive_record_factory.rb} +0 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/test_app/Gemfile +8 -3
- data/spec/test_app/Gemfile.lock +114 -64
- data/spec/test_app/app/views/components.rb +1 -2
- data/spec/test_app/config/application.rb +2 -0
- data/spec/test_app/config/routes.rb +1 -1
- data/spec/{synchromesh/integration/test_components.rb → test_components.rb} +0 -0
- metadata +144 -137
- data/app/controllers/reactive_record/application_controller.rb +0 -4
- data/app/controllers/reactive_record/reactive_record_controller.rb +0 -49
- data/config/routes.rb +0 -7
- data/examples/action-cable-production-mode/public/assets/application-90043e04e9e784054fd08159fa7aafe5e23d3ffb31584b1bea1e47043c9cfb5a.js +0 -50
- data/examples/action-cable-production-mode/public/assets/application-90043e04e9e784054fd08159fa7aafe5e23d3ffb31584b1bea1e47043c9cfb5a.js.gz +0 -0
- data/examples/action-cable-production-mode/public/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css.gz +0 -0
- data/examples/action-cable-production-mode/tmp/.keep +0 -0
- data/examples/action-cable/log/.keep +0 -0
- data/examples/action-cable/tmp/.keep +0 -0
- data/examples/pusher-fake/log/.keep +0 -0
- data/examples/pusher-fake/tmp/.keep +0 -0
- data/examples/pusher/log/.keep +0 -0
- data/examples/pusher/tmp/.keep +0 -0
- data/examples/simple-poller/log/.keep +0 -0
- data/examples/simple-poller/tmp/.keep +0 -0
- data/examples/word-game/log/.keep +0 -0
- data/examples/word-game/tmp/.keep +0 -0
- data/examples/words/log/.keep +0 -0
- data/examples/words/tmp/.keep +0 -0
- data/lib/reactive_record/version.rb +0 -3
- data/lib/sources/hyper-mesh/pusher.js +0 -98
- data/lib/synchromesh/action_cable.rb +0 -39
- data/lib/synchromesh/client_drivers.rb +0 -357
- data/lib/synchromesh/configuration.rb +0 -40
- data/lib/synchromesh/connection.rb +0 -170
- data/lib/synchromesh/policy.rb +0 -504
- data/lib/synchromesh/synchromesh.rb +0 -159
- data/lib/synchromesh/synchromesh_controller.rb +0 -162
- data/reactive_record_test_app/README.rdoc +0 -261
- data/reactive_record_test_app/app/assets/javascripts/components/another_component.rb +0 -24
- data/reactive_record_test_app/app/assets/javascripts/components/empty_component.rb +0 -6
- data/reactive_record_test_app/app/assets/javascripts/components/todo_item_component.js.rb +0 -16
- data/reactive_record_test_app/app/assets/javascripts/components/todos_component.js.rb +0 -42
- data/reactive_record_test_app/app/assets/javascripts/components/todos_main_component.rb +0 -49
- data/reactive_record_test_app/app/assets/javascripts/react_js_test_only.js +0 -21618
- data/reactive_record_test_app/app/assets/javascripts/spec/reactive_record_xspec.js.rb +0 -42
- data/reactive_record_test_app/app/controllers/test_controller.rb +0 -7
- data/reactive_record_test_app/app/mailers/.gitkeep +0 -0
- data/reactive_record_test_app/app/models/models.rb +0 -1
- data/reactive_record_test_app/app/policies/application_policy.rb +0 -5
- data/reactive_record_test_app/app/views/components.rb +0 -4
- data/reactive_record_test_app/app/views/components/test.rb +0 -18
- data/reactive_record_test_app/app/views/home/index.html.erb +0 -1
- data/reactive_record_test_app/app/views/layouts/application.html.erb +0 -17
- data/reactive_record_test_app/config/environments/production.rb +0 -70
- data/reactive_record_test_app/config/environments/test.rb +0 -41
- data/spec/synchromesh/integration/transports_spec.rb +0 -308
- data/spec/synchromesh/policies/auto_connect_spec.rb +0 -60
- data/spec/synchromesh/policies/auto_loader_spec.rb +0 -34
- data/spec/synchromesh/policies/policy_methods_spec.rb +0 -85
- data/spec/synchromesh/policies/regulate_class_connection_spec.rb +0 -50
- data/spec/synchromesh/policies/regulate_instance_connection_spec.rb +0 -66
- data/spec/test_app/log/.keep +0 -0
@@ -86,12 +86,12 @@ module ReactiveRecord
|
|
86
86
|
if value.nil?
|
87
87
|
current_value.attributes[inverse_attr].delete(@ar_instance) unless current_value.nil?
|
88
88
|
else
|
89
|
-
value.backing_record.push_onto_collection(association.inverse, @ar_instance)
|
89
|
+
value.backing_record.push_onto_collection(@model, association.inverse, @ar_instance)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
def push_onto_collection(association, ar_instance)
|
94
|
-
attributes[association.attribute] ||= Collection.new(
|
93
|
+
def push_onto_collection(model, association, ar_instance)
|
94
|
+
attributes[association.attribute] ||= Collection.new(model, @ar_instance, association)
|
95
95
|
attributes[association.attribute] << ar_instance
|
96
96
|
end
|
97
97
|
|
@@ -83,12 +83,12 @@ module ReactiveRecord
|
|
83
83
|
@while_loading_counter = 0
|
84
84
|
end
|
85
85
|
|
86
|
-
def get_next_while_loading_counter
|
86
|
+
def self.get_next_while_loading_counter
|
87
87
|
@while_loading_counter += 1
|
88
88
|
end
|
89
89
|
|
90
|
-
def preload_css(css)
|
91
|
-
@css_to_preload
|
90
|
+
def self.preload_css(css)
|
91
|
+
@css_to_preload += "#{css}\n"
|
92
92
|
end
|
93
93
|
|
94
94
|
def self.has_observers?
|
@@ -103,14 +103,14 @@ module ReactiveRecord
|
|
103
103
|
|
104
104
|
# I DONT THINK WE USE opal-jquery in this module anymore - require 'opal-jquery' if opal_client?
|
105
105
|
|
106
|
-
include
|
106
|
+
include Hyperloop::Component::Mixin
|
107
107
|
|
108
108
|
param :loading
|
109
109
|
param :loaded_children
|
110
110
|
param :loading_children
|
111
111
|
param :element_type
|
112
112
|
param :element_props
|
113
|
-
param :display, default:
|
113
|
+
param :display, default: ''
|
114
114
|
|
115
115
|
class << self
|
116
116
|
|
@@ -158,35 +158,37 @@ module ReactiveRecord
|
|
158
158
|
before_mount do
|
159
159
|
@uniq_id = WhileLoading.get_next_while_loading_counter
|
160
160
|
WhileLoading.preload_css(
|
161
|
-
".reactive_record_while_loading_container_#{@uniq_id} > :nth-child(1n+#{loaded_children.count+1}) {\n"+
|
161
|
+
".reactive_record_while_loading_container_#{@uniq_id} > :nth-child(1n+#{params.loaded_children.count+1}) {\n"+
|
162
162
|
" display: none;\n"+
|
163
163
|
"}\n"
|
164
164
|
)
|
165
165
|
end
|
166
166
|
|
167
167
|
after_mount do
|
168
|
-
@waiting_on_resources = loading
|
168
|
+
@waiting_on_resources = params.loading
|
169
169
|
WhileLoading.add_style_sheet
|
170
170
|
%x{
|
171
171
|
var node = #{dom_node};
|
172
|
-
$(node).children(':nth-child(-1n+'+#{loaded_children.count}+')').addClass('reactive_record_show_when_loaded');
|
173
|
-
$(node).children(':nth-child(1n+'+#{loaded_children.count+1}+')').addClass('reactive_record_show_while_loading');
|
172
|
+
$(node).children(':nth-child(-1n+'+#{params.loaded_children.count}+')').addClass('reactive_record_show_when_loaded');
|
173
|
+
$(node).children(':nth-child(1n+'+#{params.loaded_children.count+1}+')').addClass('reactive_record_show_while_loading');
|
174
174
|
}
|
175
175
|
end
|
176
176
|
|
177
177
|
after_update do
|
178
|
-
@waiting_on_resources = loading
|
178
|
+
@waiting_on_resources = params.loading
|
179
179
|
end
|
180
180
|
|
181
181
|
def render
|
182
|
-
props = element_props.dup
|
182
|
+
props = params.element_props.dup
|
183
183
|
classes = [props[:class], props[:className], "reactive_record_while_loading_container_#{@uniq_id}"].compact.join(" ")
|
184
184
|
props.merge!({
|
185
185
|
"data-reactive_record_while_loading_container_id" => @uniq_id,
|
186
186
|
"data-reactive_record_enclosing_while_loading_container_id" => @uniq_id,
|
187
187
|
class: classes
|
188
188
|
})
|
189
|
-
React.create_element(element_type, props)
|
189
|
+
React.create_element(params.element_type[0], props) do
|
190
|
+
params.loaded_children + params.loading_children
|
191
|
+
end.tap { |e| e.waiting_on_resources = params.loading }
|
190
192
|
end
|
191
193
|
|
192
194
|
end
|
@@ -204,22 +206,28 @@ module React
|
|
204
206
|
loaded_children = []
|
205
207
|
loaded_children = block.call.dup if block
|
206
208
|
|
207
|
-
|
209
|
+
if display.respond_to? :as_node
|
210
|
+
display = display.as_node
|
211
|
+
loading_display_block = lambda { display.render }
|
212
|
+
elsif !loading_display_block
|
213
|
+
loading_display_block = lambda { display }
|
214
|
+
end
|
208
215
|
loading_children = RenderingContext.build do |buffer|
|
209
216
|
result = loading_display_block.call
|
210
|
-
|
217
|
+
result = result.to_s if result.try :acts_as_string?
|
218
|
+
result.span.tap { |e| e.waiting_on_resources = RenderingContext.waiting_on_resources } if result.is_a? String
|
211
219
|
buffer.dup
|
212
|
-
end
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
220
|
+
end
|
221
|
+
|
222
|
+
new_element = React.create_element(
|
223
|
+
ReactiveRecord::WhileLoading,
|
224
|
+
loading: waiting_on_resources,
|
225
|
+
loading_children: loading_children,
|
226
|
+
loaded_children: loaded_children,
|
227
|
+
element_type: [type],
|
228
|
+
element_props: properties)
|
229
|
+
|
230
|
+
RenderingContext.replace(self, new_element)
|
223
231
|
end
|
224
232
|
|
225
233
|
def hide_while_loading
|
@@ -228,77 +236,78 @@ module React
|
|
228
236
|
|
229
237
|
end
|
230
238
|
|
231
|
-
module
|
239
|
+
module ::Hyperloop
|
240
|
+
class Component
|
241
|
+
module Mixin
|
232
242
|
|
233
|
-
|
243
|
+
alias_method :original_component_did_mount, :component_did_mount
|
234
244
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
245
|
+
def component_did_mount(*args)
|
246
|
+
original_component_did_mount(*args)
|
247
|
+
reactive_record_link_to_enclosing_while_loading_container
|
248
|
+
reactive_record_link_set_while_loading_container_class
|
249
|
+
end
|
240
250
|
|
241
|
-
|
251
|
+
alias_method :original_component_did_update, :component_did_update
|
242
252
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
253
|
+
def component_did_update(*args)
|
254
|
+
original_component_did_update(*args)
|
255
|
+
reactive_record_link_set_while_loading_container_class
|
256
|
+
end
|
247
257
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
258
|
+
def reactive_record_link_to_enclosing_while_loading_container
|
259
|
+
# Call after any component mounts - attaches the containers loading id to this component
|
260
|
+
# Fyi, the while_loading container is responsible for setting its own link to itself
|
261
|
+
|
262
|
+
%x{
|
263
|
+
var node = #{dom_node};
|
264
|
+
if (!$(node).is('[data-reactive_record_enclosing_while_loading_container_id]')) {
|
265
|
+
var while_loading_container = $(node).closest('[data-reactive_record_while_loading_container_id]')
|
266
|
+
if (while_loading_container.length > 0) {
|
267
|
+
var container_id = $(while_loading_container).attr('data-reactive_record_while_loading_container_id')
|
268
|
+
$(node).attr('data-reactive_record_enclosing_while_loading_container_id', container_id)
|
269
|
+
}
|
270
|
+
}
|
259
271
|
}
|
260
|
-
|
261
|
-
}
|
262
|
-
|
263
|
-
end
|
264
|
-
|
265
|
-
def reactive_record_link_set_while_loading_container_class
|
266
|
-
|
267
|
-
%x{
|
268
|
-
|
269
|
-
var node = #{dom_node};
|
270
|
-
var while_loading_container_id = $(node).attr('data-reactive_record_enclosing_while_loading_container_id');
|
271
|
-
if (while_loading_container_id) {
|
272
|
-
var while_loading_container = $('[data-reactive_record_while_loading_container_id='+while_loading_container_id+']');
|
273
|
-
var loading = (#{waiting_on_resources} == true);
|
274
|
-
if (loading) {
|
275
|
-
$(node).addClass('reactive_record_is_loading');
|
276
|
-
$(node).removeClass('reactive_record_is_loaded');
|
277
|
-
$(while_loading_container).addClass('reactive_record_is_loading');
|
278
|
-
$(while_loading_container).removeClass('reactive_record_is_loaded');
|
272
|
+
end
|
279
273
|
|
280
|
-
|
274
|
+
def reactive_record_link_set_while_loading_container_class
|
275
|
+
%x{
|
281
276
|
|
282
|
-
|
283
|
-
|
284
|
-
|
277
|
+
var node = #{dom_node};
|
278
|
+
var wl = #{!self.is_a?(ReactiveRecord::WhileLoading)}
|
279
|
+
if (#{!self.is_a?(ReactiveRecord::WhileLoading)} && $(node).is('[data-reactive_record_while_loading_container_id]')) {
|
280
|
+
return
|
285
281
|
}
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
$(
|
282
|
+
var while_loading_container_id = $(node).attr('data-reactive_record_enclosing_while_loading_container_id');
|
283
|
+
if (while_loading_container_id) {
|
284
|
+
var while_loading_container = $('[data-reactive_record_while_loading_container_id='+while_loading_container_id+']');
|
285
|
+
var loading = #{!!waiting_on_resources == true};
|
286
|
+
if (loading) {
|
287
|
+
$(node).addClass('reactive_record_is_loading');
|
288
|
+
$(node).removeClass('reactive_record_is_loaded');
|
289
|
+
$(while_loading_container).addClass('reactive_record_is_loading');
|
290
|
+
$(while_loading_container).removeClass('reactive_record_is_loaded');
|
291
|
+
|
292
|
+
} else if (!$(node).hasClass('reactive_record_is_loaded')) {
|
293
|
+
|
294
|
+
if (!$(node).attr('data-reactive_record_while_loading_container_id')) {
|
295
|
+
$(node).removeClass('reactive_record_is_loading');
|
296
|
+
$(node).addClass('reactive_record_is_loaded');
|
297
|
+
}
|
298
|
+
if (!$(while_loading_container).hasClass('reactive_record_is_loaded')) {
|
299
|
+
var loading_children = $(while_loading_container).
|
300
|
+
find('[data-reactive_record_enclosing_while_loading_container_id='+while_loading_container_id+'].reactive_record_is_loading')
|
301
|
+
if (loading_children.length == 0) {
|
302
|
+
$(while_loading_container).removeClass('reactive_record_is_loading')
|
303
|
+
$(while_loading_container).addClass('reactive_record_is_loaded')
|
304
|
+
}
|
305
|
+
}
|
292
306
|
}
|
293
307
|
}
|
294
|
-
|
295
308
|
}
|
296
|
-
|
297
|
-
|
298
|
-
}
|
299
|
-
|
309
|
+
end
|
310
|
+
end
|
300
311
|
end
|
301
|
-
|
302
312
|
end if RUBY_ENGINE == 'opal'
|
303
|
-
|
304
313
|
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module ReactiveRecord
|
2
|
+
class Broadcast
|
3
|
+
|
4
|
+
def self.after_commit(operation, model)
|
5
|
+
Hyperloop::InternalPolicy.regulate_broadcast(model) do |data|
|
6
|
+
if !Hyperloop.on_server? && Hyperloop::Connection.root_path
|
7
|
+
send_to_server(operation, data)
|
8
|
+
else
|
9
|
+
SendPacket.run(data, operation: operation)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
rescue ActiveRecord::StatementInvalid => e
|
13
|
+
raise e unless e.message == "Could not find table 'hyperloop_connections'"
|
14
|
+
end unless RUBY_ENGINE == 'opal'
|
15
|
+
|
16
|
+
def self.send_to_server(operation, data)
|
17
|
+
salt = SecureRandom.hex
|
18
|
+
authorization = Hyperloop.authorization(salt, data[:channel], data[:broadcast_id])
|
19
|
+
raise 'no server running' unless Hyperloop::Connection.root_path
|
20
|
+
SendPacket.remote(
|
21
|
+
Hyperloop::Connection.root_path,
|
22
|
+
data,
|
23
|
+
operation: operation,
|
24
|
+
salt: salt,
|
25
|
+
authorization: authorization
|
26
|
+
)
|
27
|
+
end unless RUBY_ENGINE == 'opal'
|
28
|
+
|
29
|
+
class SendPacket < Hyperloop::ServerOp
|
30
|
+
param authorization: nil, nils: true
|
31
|
+
param salt: nil
|
32
|
+
param :operation
|
33
|
+
param :broadcast_id
|
34
|
+
param :channel
|
35
|
+
param :channels
|
36
|
+
param :klass
|
37
|
+
param :record
|
38
|
+
param :operation
|
39
|
+
param :previous_changes
|
40
|
+
|
41
|
+
unless RUBY_ENGINE == 'opal'
|
42
|
+
validate do
|
43
|
+
params.authorization.nil? ||
|
44
|
+
Hyperloop.authorization(
|
45
|
+
params.salt, params.channel, params.broadcast_id
|
46
|
+
) == params.authorization
|
47
|
+
end
|
48
|
+
dispatch_to { params.channel }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
SendPacket.on_dispatch do |params|
|
53
|
+
in_transit[params.broadcast_id].receive(params) do |broadcast|
|
54
|
+
if params.operation == :destroy
|
55
|
+
ReactiveRecord::Collection.sync_scopes broadcast
|
56
|
+
else
|
57
|
+
ReactiveRecord::Base.when_not_saving(broadcast.klass) do
|
58
|
+
ReactiveRecord::Collection.sync_scopes broadcast
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.to_self(record, data = {})
|
65
|
+
# simulate incoming packet after a local save
|
66
|
+
operation = if record.new?
|
67
|
+
:create
|
68
|
+
elsif record.destroyed?
|
69
|
+
:destroy
|
70
|
+
else
|
71
|
+
:change
|
72
|
+
end
|
73
|
+
dummy_broadcast = new.local(operation, record, data)
|
74
|
+
record.backing_record.sync! data unless operation == :destroy
|
75
|
+
ReactiveRecord::Collection.sync_scopes dummy_broadcast
|
76
|
+
end
|
77
|
+
|
78
|
+
def record_with_current_values
|
79
|
+
ReactiveRecord::Base.load_data do
|
80
|
+
backing_record = @backing_record || klass.find(record[:id]).backing_record
|
81
|
+
if destroyed?
|
82
|
+
backing_record.ar_instance
|
83
|
+
else
|
84
|
+
merge_current_values(backing_record)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def record_with_new_values
|
90
|
+
klass._react_param_conversion(record).tap do |ar_instance|
|
91
|
+
if destroyed?
|
92
|
+
ar_instance.backing_record.destroy_associations
|
93
|
+
elsif new?
|
94
|
+
ar_instance.backing_record.initialize_collections
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def new?
|
100
|
+
@is_new
|
101
|
+
end
|
102
|
+
|
103
|
+
def destroyed?
|
104
|
+
@destroyed
|
105
|
+
end
|
106
|
+
|
107
|
+
def klass
|
108
|
+
Object.const_get(@klass)
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_s
|
112
|
+
"klass: #{klass} record: #{record} new?: #{new?} destroyed?: #{destroyed?}"
|
113
|
+
end
|
114
|
+
|
115
|
+
# private
|
116
|
+
|
117
|
+
attr_reader :record
|
118
|
+
|
119
|
+
def self.open_channels
|
120
|
+
@open_channels ||= Set.new
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.in_transit
|
124
|
+
@in_transit ||= Hash.new { |h, k| h[k] = new(k) }
|
125
|
+
end
|
126
|
+
|
127
|
+
def initialize(id)
|
128
|
+
@id = id
|
129
|
+
@received = Set.new
|
130
|
+
@record = {}
|
131
|
+
@previous_changes = {}
|
132
|
+
end
|
133
|
+
|
134
|
+
def local(operation, record, data)
|
135
|
+
@destroyed = operation == :destroy
|
136
|
+
@is_new = operation == :create
|
137
|
+
@klass = record.class.name
|
138
|
+
@record = data
|
139
|
+
record.backing_record.destroyed = false
|
140
|
+
@record.merge!(id: record.id) if record.id
|
141
|
+
record.backing_record.destroyed = @destroyed
|
142
|
+
@backing_record = record.backing_record
|
143
|
+
attributes = record.backing_record.attributes
|
144
|
+
data.each do |k, v|
|
145
|
+
next if klass.reflect_on_association(k) || attributes[k] == v
|
146
|
+
@previous_changes[k] = [attributes[k], v]
|
147
|
+
end
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def receive(params)
|
152
|
+
@destroyed = params.operation == :destroy
|
153
|
+
@is_new = params.operation == :create
|
154
|
+
@channels ||= Hyperloop::IncomingBroadcast.open_channels.intersection params.channels
|
155
|
+
#raise 'synchromesh security violation' unless @channels.include? params.channels
|
156
|
+
@received << params.channel
|
157
|
+
@klass ||= params.klass
|
158
|
+
@record.merge! params.record
|
159
|
+
@previous_changes.merge! params.previous_changes
|
160
|
+
@backing_record = ReactiveRecord::Base.exists?(klass, params.record[:id])
|
161
|
+
yield complete! if @channels == @received
|
162
|
+
end
|
163
|
+
|
164
|
+
def complete!
|
165
|
+
self.class.in_transit.delete @id
|
166
|
+
end
|
167
|
+
|
168
|
+
def merge_current_values(br)
|
169
|
+
current_values = Hash[*@previous_changes.collect do |attr, values|
|
170
|
+
value = attr == :id ? record[:id] : values.first
|
171
|
+
if br.attributes.key?(attr) &&
|
172
|
+
br.attributes[attr] != br.convert(attr, value) &&
|
173
|
+
br.attributes[attr] != br.convert(attr, values.last)
|
174
|
+
puts "warning #{attr} has changed locally - will force a reload.\n"\
|
175
|
+
"local value: #{br.attributes[attr]} remote value: #{br.convert(attr, value)}->#{br.convert(attr, values.last)}"
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
[attr, value]
|
179
|
+
end.compact.flatten].merge(br.attributes)
|
180
|
+
klass._react_param_conversion(current_values)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|