jason-rails 0.6.7 → 0.7.3
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 +38 -0
- data/Gemfile.lock +6 -4
- data/README.md +16 -14
- data/app/controllers/jason/jason_controller.rb +26 -4
- data/app/workers/jason/outbound_message_queue_worker.rb +1 -1
- data/client/lib/JasonProvider.d.ts +2 -1
- data/client/lib/JasonProvider.js +2 -2
- data/client/lib/addRelations.d.ts +1 -0
- data/client/lib/addRelations.js +39 -0
- data/client/lib/createJasonReducers.js +4 -2
- data/client/lib/createOptDis.d.ts +1 -1
- data/client/lib/createOptDis.js +9 -8
- data/client/lib/createServerActionQueue.d.ts +3 -2
- data/client/lib/createServerActionQueue.js +32 -6
- data/client/lib/createServerActionQueue.test.js +61 -6
- data/client/lib/createThenable.d.ts +1 -0
- data/client/lib/createThenable.js +5 -0
- data/client/lib/index.d.ts +7 -1
- data/client/lib/index.js +3 -1
- data/client/lib/transportAdapters/actionCableAdapter.js +24 -4
- data/client/lib/transportAdapters/pusherAdapter.js +1 -1
- data/client/lib/useDraft.d.ts +1 -0
- data/client/lib/useDraft.js +13 -0
- data/client/lib/useEager.d.ts +1 -1
- data/client/lib/useEager.js +10 -5
- data/client/lib/useJason.d.ts +2 -1
- data/client/lib/useJason.js +4 -6
- data/client/package.json +1 -1
- data/client/src/JasonProvider.tsx +2 -2
- data/client/src/addRelations.ts +33 -0
- data/client/src/createJasonReducers.ts +4 -2
- data/client/src/createOptDis.ts +10 -8
- data/client/src/createServerActionQueue.test.ts +60 -6
- data/client/src/createServerActionQueue.ts +41 -6
- data/client/src/index.ts +2 -0
- data/client/src/transportAdapters/actionCableAdapter.ts +24 -5
- data/client/src/transportAdapters/pusherAdapter.ts +1 -2
- data/client/src/useDraft.ts +17 -0
- data/client/src/useEager.ts +9 -6
- data/client/src/useJason.ts +3 -6
- data/lib/jason.rb +4 -1
- data/lib/jason/api_model.rb +0 -4
- data/lib/jason/channel.rb +0 -7
- data/lib/jason/conditions_matcher.rb +88 -0
- data/lib/jason/consistency_checker.rb +65 -0
- data/lib/jason/graph_helper.rb +4 -0
- data/lib/jason/publisher.rb +39 -37
- data/lib/jason/subscription.rb +63 -18
- data/lib/jason/version.rb +1 -1
- metadata +12 -5
- data/client/src/makeEager.ts +0 -46
- data/lib/jason/publisher_old.rb +0 -112
- data/lib/jason/subscription_old.rb +0 -171
data/lib/jason/subscription.rb
CHANGED
@@ -48,15 +48,31 @@ class Jason::Subscription
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
def self.all_for_model(model_name)
|
52
|
+
$redis_jason.smembers("jason:models:#{model_name}:all:subscriptions")
|
53
|
+
end
|
54
|
+
|
51
55
|
def self.for_instance(model_name, id, include_all = true)
|
52
56
|
subs = $redis_jason.smembers("jason:models:#{model_name}:#{id}:subscriptions")
|
53
57
|
if include_all
|
54
|
-
subs +=
|
58
|
+
subs += all_for_model(model_name)
|
55
59
|
end
|
56
|
-
|
57
60
|
subs
|
58
61
|
end
|
59
62
|
|
63
|
+
# returns [
|
64
|
+
# { condition: { post_id: 123 }, subscription_ids: [] }
|
65
|
+
# ]
|
66
|
+
def self.conditions_for_model(model_name)
|
67
|
+
rows = $redis_jason.smembers("jason:models:#{model_name}:conditions").map do |row|
|
68
|
+
JSON.parse(row)
|
69
|
+
end
|
70
|
+
conditions = rows.group_by { |row| row['conditions'] }
|
71
|
+
conditions.map do |conditions, rows|
|
72
|
+
{ 'conditions' => conditions, 'subscription_ids' => rows.map { |row| row['subscription_id'] } }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
60
76
|
def self.for_model(model_name)
|
61
77
|
|
62
78
|
end
|
@@ -163,10 +179,14 @@ class Jason::Subscription
|
|
163
179
|
subscription.apply_id_changeset(id_changeset)
|
164
180
|
subscription.broadcast_id_changeset(id_changeset)
|
165
181
|
end
|
182
|
+
|
183
|
+
#########
|
184
|
+
# ---> Join the community
|
185
|
+
# Subs where changed is parent + parent is an _all_ or _condition_ subscription
|
186
|
+
|
166
187
|
end
|
167
188
|
|
168
189
|
def self.remove_ids(model_name, ids)
|
169
|
-
# td: finish this
|
170
190
|
ids.each do |instance_id|
|
171
191
|
for_instance(model_name, instance_id, false).each do |sub_id|
|
172
192
|
subscription = find_by_id(sub_id)
|
@@ -176,11 +196,13 @@ class Jason::Subscription
|
|
176
196
|
subscription.broadcast_id_changeset(id_changeset)
|
177
197
|
end
|
178
198
|
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Add ID to any _all_ subscriptions
|
182
|
-
def self.add_id(model_name, id)
|
183
199
|
|
200
|
+
all_for_model(model_name).each do |sub_id|
|
201
|
+
subscription = find_by_id(sub_id)
|
202
|
+
ids.each do |id|
|
203
|
+
subscription.destroy(model_name, id)
|
204
|
+
end
|
205
|
+
end
|
184
206
|
end
|
185
207
|
|
186
208
|
def self.all
|
@@ -203,6 +225,28 @@ class Jason::Subscription
|
|
203
225
|
end
|
204
226
|
end
|
205
227
|
|
228
|
+
def remove_id(model_name, id)
|
229
|
+
id_changeset = graph_helper.apply_remove_node("#{model_name}:#{id}")
|
230
|
+
apply_id_changeset(id_changeset)
|
231
|
+
broadcast_id_changeset(id_changeset)
|
232
|
+
end
|
233
|
+
|
234
|
+
def add_id(model_name, id)
|
235
|
+
id_changeset = graph_helper.apply_update({
|
236
|
+
add: [
|
237
|
+
{
|
238
|
+
model_names: [model_name],
|
239
|
+
instance_ids: [[id]]
|
240
|
+
},
|
241
|
+
# Add IDs of child models
|
242
|
+
load_ids_for_sub_models(model_name, id)
|
243
|
+
]
|
244
|
+
})
|
245
|
+
|
246
|
+
apply_id_changeset(id_changeset)
|
247
|
+
broadcast_id_changeset(id_changeset)
|
248
|
+
end
|
249
|
+
|
206
250
|
def remove_ids(model_name, ids)
|
207
251
|
$redis_jason.srem("jason:subscriptions:#{id}:ids:#{model_name}", ids)
|
208
252
|
ids.each do |instance_id|
|
@@ -238,13 +282,18 @@ class Jason::Subscription
|
|
238
282
|
all_models = includes_helper.all_models(model_name)
|
239
283
|
|
240
284
|
relation = model_name.classify.constantize.all.eager_load(includes_tree)
|
241
|
-
|
242
285
|
if model_name == model
|
243
286
|
if conditions.blank?
|
244
287
|
$redis_jason.sadd("jason:models:#{model_name}:all:subscriptions", id)
|
245
288
|
all_models -= [model_name]
|
246
|
-
|
289
|
+
elsif conditions.keys == ['id']
|
247
290
|
relation = relation.where(conditions)
|
291
|
+
else
|
292
|
+
$redis_jason.sadd("jason:models:#{model_name}:conditions", {
|
293
|
+
'conditions' => conditions,
|
294
|
+
'subscription_id' => self.id
|
295
|
+
}.to_json)
|
296
|
+
relation = Jason::ConditionsMatcher.new(relation.klass).apply_conditions(relation, conditions)
|
248
297
|
end
|
249
298
|
else
|
250
299
|
raise "Must supply IDs for sub models" if ids.nil?
|
@@ -257,7 +306,7 @@ class Jason::Subscription
|
|
257
306
|
|
258
307
|
# pluck returns only a 1D array if only 1 arg passed
|
259
308
|
if all_models.size == 1
|
260
|
-
instance_ids = [
|
309
|
+
instance_ids = instance_ids.map { |id| [id] }
|
261
310
|
end
|
262
311
|
|
263
312
|
return { model_names: all_models, instance_ids: instance_ids }
|
@@ -266,12 +315,12 @@ class Jason::Subscription
|
|
266
315
|
# 'posts', [post#1, post#2,...]
|
267
316
|
def set_ids_for_sub_models(model_name = model, ids = nil, enforce: false)
|
268
317
|
edge_set = load_ids_for_sub_models(model_name, ids)
|
269
|
-
|
270
318
|
# Build the tree
|
271
319
|
id_changeset = graph_helper.apply_update({
|
272
320
|
add: [edge_set],
|
273
321
|
enforce: enforce
|
274
322
|
})
|
323
|
+
|
275
324
|
apply_id_changeset(id_changeset)
|
276
325
|
end
|
277
326
|
|
@@ -287,6 +336,7 @@ class Jason::Subscription
|
|
287
336
|
end
|
288
337
|
$redis_jason.del("jason:subscriptions:#{id}:ids:#{model_name}")
|
289
338
|
end
|
339
|
+
$redis_jason.del("jason:subscriptions:#{id}:graph")
|
290
340
|
end
|
291
341
|
|
292
342
|
def ids(model_name = model)
|
@@ -328,10 +378,6 @@ class Jason::Subscription
|
|
328
378
|
def remove_consumer(consumer_id)
|
329
379
|
$redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
|
330
380
|
$redis_jason.hdel("jason:consumers", consumer_id)
|
331
|
-
|
332
|
-
if consumer_count == 0
|
333
|
-
clear_all_ids
|
334
|
-
end
|
335
381
|
end
|
336
382
|
|
337
383
|
def consumer_count
|
@@ -344,8 +390,8 @@ class Jason::Subscription
|
|
344
390
|
|
345
391
|
def user_can_access?(user)
|
346
392
|
# td: implement the authorization logic here
|
347
|
-
return true if Jason.
|
348
|
-
Jason.
|
393
|
+
return true if Jason.subscription_authorization_service.blank?
|
394
|
+
Jason.subscription_authorization_service.call(user, model, conditions, includes_helper.all_models - [model])
|
349
395
|
end
|
350
396
|
|
351
397
|
def get
|
@@ -381,7 +427,6 @@ class Jason::Subscription
|
|
381
427
|
# Remove subscription state
|
382
428
|
if hard
|
383
429
|
clear_all_ids
|
384
|
-
$redis_jason.del("jason:subscriptions:#{id}:graph")
|
385
430
|
end
|
386
431
|
|
387
432
|
set_ids_for_sub_models(enforce: true)
|
data/lib/jason/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jason-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Rees
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -152,6 +152,8 @@ files:
|
|
152
152
|
- client/lib/JasonProvider.js
|
153
153
|
- client/lib/actionFactory.d.ts
|
154
154
|
- client/lib/actionFactory.js
|
155
|
+
- client/lib/addRelations.d.ts
|
156
|
+
- client/lib/addRelations.js
|
155
157
|
- client/lib/createActions.d.ts
|
156
158
|
- client/lib/createActions.js
|
157
159
|
- client/lib/createJasonReducers.d.ts
|
@@ -164,6 +166,8 @@ files:
|
|
164
166
|
- client/lib/createServerActionQueue.js
|
165
167
|
- client/lib/createServerActionQueue.test.d.ts
|
166
168
|
- client/lib/createServerActionQueue.test.js
|
169
|
+
- client/lib/createThenable.d.ts
|
170
|
+
- client/lib/createThenable.js
|
167
171
|
- client/lib/createTransportAdapter.d.ts
|
168
172
|
- client/lib/createTransportAdapter.js
|
169
173
|
- client/lib/deepCamelizeKeys.d.ts
|
@@ -184,6 +188,8 @@ files:
|
|
184
188
|
- client/lib/transportAdapters/pusherAdapter.js
|
185
189
|
- client/lib/useAct.d.ts
|
186
190
|
- client/lib/useAct.js
|
191
|
+
- client/lib/useDraft.d.ts
|
192
|
+
- client/lib/useDraft.js
|
187
193
|
- client/lib/useEager.d.ts
|
188
194
|
- client/lib/useEager.js
|
189
195
|
- client/lib/useJason.d.ts
|
@@ -196,6 +202,7 @@ files:
|
|
196
202
|
- client/src/JasonContext.ts
|
197
203
|
- client/src/JasonProvider.tsx
|
198
204
|
- client/src/actionFactory.ts
|
205
|
+
- client/src/addRelations.ts
|
199
206
|
- client/src/createActions.ts
|
200
207
|
- client/src/createJasonReducers.ts
|
201
208
|
- client/src/createOptDis.ts
|
@@ -206,12 +213,12 @@ files:
|
|
206
213
|
- client/src/deepCamelizeKeys.test.ts
|
207
214
|
- client/src/deepCamelizeKeys.ts
|
208
215
|
- client/src/index.ts
|
209
|
-
- client/src/makeEager.ts
|
210
216
|
- client/src/pruneIdsMiddleware.ts
|
211
217
|
- client/src/restClient.ts
|
212
218
|
- client/src/transportAdapters/actionCableAdapter.ts
|
213
219
|
- client/src/transportAdapters/pusherAdapter.ts
|
214
220
|
- client/src/useAct.ts
|
221
|
+
- client/src/useDraft.ts
|
215
222
|
- client/src/useEager.ts
|
216
223
|
- client/src/useJason.test.ts
|
217
224
|
- client/src/useJason.ts
|
@@ -224,14 +231,14 @@ files:
|
|
224
231
|
- lib/jason/api_model.rb
|
225
232
|
- lib/jason/broadcaster.rb
|
226
233
|
- lib/jason/channel.rb
|
234
|
+
- lib/jason/conditions_matcher.rb
|
235
|
+
- lib/jason/consistency_checker.rb
|
227
236
|
- lib/jason/engine.rb
|
228
237
|
- lib/jason/graph_helper.rb
|
229
238
|
- lib/jason/includes_helper.rb
|
230
239
|
- lib/jason/lua_generator.rb
|
231
240
|
- lib/jason/publisher.rb
|
232
|
-
- lib/jason/publisher_old.rb
|
233
241
|
- lib/jason/subscription.rb
|
234
|
-
- lib/jason/subscription_old.rb
|
235
242
|
- lib/jason/version.rb
|
236
243
|
homepage: https://github.com/jamesr2323/jason
|
237
244
|
licenses:
|
data/client/src/makeEager.ts
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
import pluralize from 'pluralize'
|
2
|
-
import _ from 'lodash'
|
3
|
-
import { useSelector } from 'react-redux'
|
4
|
-
|
5
|
-
export default function (schema) {
|
6
|
-
function addRelations(s, objects, objectType, relations) {
|
7
|
-
// first find out relation name
|
8
|
-
if (_.isArray(relations)) {
|
9
|
-
relations.forEach(relation => {
|
10
|
-
objects = addRelations(s, objects, objectType, relation)
|
11
|
-
})
|
12
|
-
} else if (typeof(relations) === 'object') {
|
13
|
-
const relation = Object.keys(relations)[0]
|
14
|
-
const subRelations = relations[relation]
|
15
|
-
|
16
|
-
objects = addRelations(s, objects, objectType, relation)
|
17
|
-
objects[relation] = addRelations(s, objects[relation], pluralize(relation), subRelations)
|
18
|
-
// #
|
19
|
-
} else if (typeof(relations) === 'string') {
|
20
|
-
const relation = relations
|
21
|
-
if (_.isArray(objects)) {
|
22
|
-
objects = objects.map(obj => addRelations(s, obj, objectType, relation))
|
23
|
-
} else {
|
24
|
-
const relatedObjects = _.values(s[pluralize(relation)].entities)
|
25
|
-
|
26
|
-
if(pluralize.isSingular(relation)) {
|
27
|
-
objects = { ...objects, [relation]: _.find(relatedObjects, { id: objects[relation + 'Id'] }) }
|
28
|
-
} else {
|
29
|
-
objects = { ...objects, [relation]: relatedObjects.filter(e => e[pluralize.singular(objectType) + 'Id'] === objects.id) }
|
30
|
-
}
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
return objects
|
35
|
-
}
|
36
|
-
|
37
|
-
function useEager(entity, id = null, relations = []) {
|
38
|
-
if (id) {
|
39
|
-
return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations), _.isEqual)
|
40
|
-
} else {
|
41
|
-
return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations), _.isEqual)
|
42
|
-
}
|
43
|
-
}
|
44
|
-
|
45
|
-
return useEager
|
46
|
-
}
|
data/lib/jason/publisher_old.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
module Jason::PublisherOld
|
2
|
-
extend ActiveSupport::Concern
|
3
|
-
|
4
|
-
def cache_json
|
5
|
-
as_json_config = api_model.as_json_config
|
6
|
-
scope = api_model.scope
|
7
|
-
|
8
|
-
if self.persisted? && (scope.blank? || self.class.unscoped.send(scope).exists?(self.id))
|
9
|
-
payload = self.reload.as_json(as_json_config)
|
10
|
-
$redis_jason.hset("jason:#{self.class.name.underscore}:cache", self.id, payload.to_json)
|
11
|
-
else
|
12
|
-
$redis_jason.hdel("jason:#{self.class.name.underscore}:cache", self.id)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def publish_json
|
17
|
-
cache_json
|
18
|
-
return if skip_publish_json
|
19
|
-
|
20
|
-
self.class.jason_subscriptions.each do |id, config_json|
|
21
|
-
config = JSON.parse(config_json)
|
22
|
-
|
23
|
-
if (config['conditions'] || {}).all? { |field, value| self.send(field) == value }
|
24
|
-
Jason::Subscription.new(id: id).update(self.class.name.underscore)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def publish_json_if_changed
|
30
|
-
subscribed_fields = api_model.subscribed_fields
|
31
|
-
publish_json if (self.previous_changes.keys.map(&:to_sym) & subscribed_fields).present? || !self.persisted?
|
32
|
-
end
|
33
|
-
|
34
|
-
class_methods do
|
35
|
-
def subscriptions
|
36
|
-
$redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
|
37
|
-
end
|
38
|
-
|
39
|
-
def jason_subscriptions
|
40
|
-
$redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
|
41
|
-
end
|
42
|
-
|
43
|
-
def publish_all(instances)
|
44
|
-
instances.each(&:cache_json)
|
45
|
-
|
46
|
-
subscriptions.each do |id, config_json|
|
47
|
-
Jason::Subscription.new(id: id).update(self.name.underscore)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def flush_cache
|
52
|
-
$redis_jason.del("jason:#{self.name.underscore}:cache")
|
53
|
-
end
|
54
|
-
|
55
|
-
def setup_json
|
56
|
-
self.after_initialize -> {
|
57
|
-
@api_model = Jason::ApiModel.new(self.class.name.underscore)
|
58
|
-
}
|
59
|
-
self.after_commit :publish_json_if_changed
|
60
|
-
|
61
|
-
include_models = Jason::ApiModel.new(self.name.underscore).include_models
|
62
|
-
|
63
|
-
include_models.map do |assoc|
|
64
|
-
puts assoc
|
65
|
-
reflection = self.reflect_on_association(assoc.to_sym)
|
66
|
-
reflection.klass.after_commit -> {
|
67
|
-
subscribed_fields = Jason::ApiModel.new(self.class.name.underscore).subscribed_fields
|
68
|
-
puts subscribed_fields.inspect
|
69
|
-
|
70
|
-
if (self.previous_changes.keys.map(&:to_sym) & subscribed_fields).present?
|
71
|
-
self.send(reflection.inverse_of.name)&.publish_json
|
72
|
-
end
|
73
|
-
}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def find_or_create_by_id(params)
|
78
|
-
object = find_by(id: params[:id])
|
79
|
-
|
80
|
-
if object
|
81
|
-
object.update(params)
|
82
|
-
elsif params[:hidden]
|
83
|
-
return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
|
84
|
-
else
|
85
|
-
object = create!(params)
|
86
|
-
end
|
87
|
-
|
88
|
-
object
|
89
|
-
end
|
90
|
-
|
91
|
-
def find_or_create_by_id!(params)
|
92
|
-
object = find_by(id: params[:id])
|
93
|
-
|
94
|
-
if object
|
95
|
-
object.update!(params)
|
96
|
-
elsif params[:hidden]
|
97
|
-
## TODO: We're diverging from semantics of the Rails bang! methods here, which would normally either raise or return an object. Find a way to make this better.
|
98
|
-
return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
|
99
|
-
else
|
100
|
-
object = create!(params)
|
101
|
-
end
|
102
|
-
|
103
|
-
object
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
included do
|
108
|
-
attr_accessor :skip_publish_json, :api_model
|
109
|
-
|
110
|
-
setup_json
|
111
|
-
end
|
112
|
-
end
|
@@ -1,171 +0,0 @@
|
|
1
|
-
class Jason::SubscriptionOld
|
2
|
-
attr_accessor :id, :config
|
3
|
-
|
4
|
-
def initialize(id: nil, config: nil)
|
5
|
-
if id
|
6
|
-
@id = id
|
7
|
-
raw_config = $redis_jason.hgetall("jason:subscriptions:#{id}").map { |k,v| [k, JSON.parse(v)] }.to_h
|
8
|
-
set_config(raw_config)
|
9
|
-
else
|
10
|
-
@id = Digest::MD5.hexdigest(config.to_json)
|
11
|
-
configure(config)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def set_config(raw_config)
|
16
|
-
@config = raw_config.with_indifferent_access.map { |k,v| [k.underscore.to_s, v] }.to_h
|
17
|
-
end
|
18
|
-
|
19
|
-
def configure(raw_config)
|
20
|
-
set_config(raw_config)
|
21
|
-
$redis_jason.hmset("jason:subscriptions:#{id}", *config.map { |k,v| [k, v.to_json]}.flatten)
|
22
|
-
end
|
23
|
-
|
24
|
-
def destroy
|
25
|
-
config.each do |model, value|
|
26
|
-
$redis_jason.srem("jason:#{model.to_s.underscore}:subscriptions", id)
|
27
|
-
end
|
28
|
-
$redis_jason.del("jason:subscriptions:#{id}")
|
29
|
-
end
|
30
|
-
|
31
|
-
def add_consumer(consumer_id)
|
32
|
-
before_consumer_count = consumer_count
|
33
|
-
$redis_jason.sadd("jason:subscriptions:#{id}:consumers", consumer_id)
|
34
|
-
$redis_jason.hset("jason:consumers", consumer_id, Time.now.utc)
|
35
|
-
|
36
|
-
add_subscriptions
|
37
|
-
publish_all
|
38
|
-
end
|
39
|
-
|
40
|
-
def remove_consumer(consumer_id)
|
41
|
-
$redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
|
42
|
-
$redis_jason.hdel("jason:consumers", consumer_id)
|
43
|
-
|
44
|
-
if consumer_count == 0
|
45
|
-
remove_subscriptions
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def consumer_count
|
50
|
-
$redis_jason.scard("jason:subscriptions:#{id}:consumers")
|
51
|
-
end
|
52
|
-
|
53
|
-
def channel
|
54
|
-
"jason:#{id}"
|
55
|
-
end
|
56
|
-
|
57
|
-
def publish_all
|
58
|
-
config.each do |model, model_config|
|
59
|
-
klass = model.to_s.classify.constantize
|
60
|
-
conditions = model_config['conditions'] || {}
|
61
|
-
klass.where(conditions).find_each(&:cache_json)
|
62
|
-
update(model)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def add_subscriptions
|
67
|
-
config.each do |model, value|
|
68
|
-
$redis_jason.hset("jason:#{model.to_s.underscore}:subscriptions", id, value.to_json)
|
69
|
-
update(model)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def remove_subscriptions
|
74
|
-
config.each do |model, _|
|
75
|
-
$redis_jason.hdel("jason:#{model.to_s.underscore}:subscriptions", id)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.publish_all
|
80
|
-
JASON_API_MODEL.each do |model, _v|
|
81
|
-
klass = model.to_s.classify.constantize
|
82
|
-
klass.publish_all(klass.all) if klass.respond_to?(:publish_all)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def get(model_name)
|
87
|
-
LuaGenerator.new.index_hash_by_set("jason:cache:#{model_name}", "")
|
88
|
-
|
89
|
-
value = JSON.parse($redis_jason.get("#{channel}:#{model}:value") || '[]')
|
90
|
-
idx = $redis_jason.get("#{channel}:#{model}:idx").to_i
|
91
|
-
|
92
|
-
{
|
93
|
-
type: 'payload',
|
94
|
-
md5Hash: id,
|
95
|
-
model: model,
|
96
|
-
value: value,
|
97
|
-
idx: idx
|
98
|
-
}
|
99
|
-
end
|
100
|
-
|
101
|
-
def get_diff(old_value, value)
|
102
|
-
JsonDiff.generate(old_value, value)
|
103
|
-
end
|
104
|
-
|
105
|
-
def deep_stringify(value)
|
106
|
-
if value.is_a?(Hash)
|
107
|
-
value.deep_stringify_keys
|
108
|
-
elsif value.is_a?(Array)
|
109
|
-
value.map { |x| x.deep_stringify_keys }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def get_throttle
|
114
|
-
if !$throttle_rate || !$throttle_timeout || Time.now.utc > $throttle_timeout
|
115
|
-
$throttle_timeout = Time.now.utc + 5.seconds
|
116
|
-
$throttle_rate = ($redis_jason.get('global_throttle_rate') || 0).to_i
|
117
|
-
else
|
118
|
-
$throttle_rate
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Atomically update and return patch
|
123
|
-
def update(model)
|
124
|
-
start_time = Time.now.utc
|
125
|
-
conditions = config[model]['conditions']
|
126
|
-
|
127
|
-
value = $redis_jason.hgetall("jason:#{model}:cache")
|
128
|
-
.values.map { |v| JSON.parse(v) }
|
129
|
-
.select { |v| (conditions || {}).all? { |field, value| v[field] == value } }
|
130
|
-
.sort_by { |v| v['id'] }
|
131
|
-
|
132
|
-
# lfsa = last finished, started at
|
133
|
-
# If another job that started after this one, finished before this one, skip sending this state update
|
134
|
-
if Time.parse($redis_jason.get("jason:#{channel}:lfsa") || '1970-01-01 00:00:00 UTC') < start_time
|
135
|
-
$redis_jason.set("jason:#{channel}:lfsa", start_time)
|
136
|
-
else
|
137
|
-
return
|
138
|
-
end
|
139
|
-
|
140
|
-
value = deep_stringify(value)
|
141
|
-
|
142
|
-
# If value has changed, return old value and new idx. Otherwise do nothing.
|
143
|
-
cmd = <<~LUA
|
144
|
-
local old_val=redis.call('get', ARGV[1] .. ':value')
|
145
|
-
if old_val ~= ARGV[2] then
|
146
|
-
redis.call('set', ARGV[1] .. ':value', ARGV[2])
|
147
|
-
local new_idx = redis.call('incr', ARGV[1] .. ':idx')
|
148
|
-
return { new_idx, old_val }
|
149
|
-
end
|
150
|
-
LUA
|
151
|
-
|
152
|
-
result = $redis_jason.eval cmd, [], ["#{channel}:#{model}", value.to_json]
|
153
|
-
return if result.blank?
|
154
|
-
|
155
|
-
idx = result[0]
|
156
|
-
old_value = JSON.parse(result[1] || '[]')
|
157
|
-
diff = get_diff(old_value, value)
|
158
|
-
|
159
|
-
end_time = Time.now.utc
|
160
|
-
|
161
|
-
payload = {
|
162
|
-
model: model,
|
163
|
-
md5Hash: id,
|
164
|
-
diff: diff,
|
165
|
-
idx: idx.to_i,
|
166
|
-
latency: ((end_time - start_time)*1000).round
|
167
|
-
}
|
168
|
-
|
169
|
-
ActionCable.server.broadcast("jason:#{id}", payload)
|
170
|
-
end
|
171
|
-
end
|