jason-rails 0.6.6 → 0.7.2
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 +41 -0
- data/Gemfile.lock +11 -4
- data/README.md +9 -15
- data/app/controllers/jason/{api_controller.rb → jason_controller.rb} +27 -5
- data/app/controllers/jason/{api/pusher_controller.rb → pusher_controller.rb} +1 -1
- data/app/workers/jason/outbound_message_queue_worker.rb +21 -0
- 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/config/routes.rb +6 -6
- data/jason-rails.gemspec +1 -0
- data/lib/jason.rb +6 -1
- data/lib/jason/api_model.rb +0 -4
- data/lib/jason/broadcaster.rb +2 -1
- 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 +42 -38
- data/lib/jason/subscription.rb +63 -18
- data/lib/jason/version.rb +1 -1
- metadata +29 -7
- 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/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
|