hyper-mesh 0.5.3 → 0.5.4
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/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
|