jason-rails 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +34 -0
- data/README.md +6 -9
- data/app/assets/config/jason_engine_manifest.js +1 -0
- data/app/assets/images/jason/engine/.keep +0 -0
- data/app/assets/stylesheets/jason/engine/application.css +15 -0
- data/app/controllers/jason/api_controller.rb +36 -0
- data/app/helpers/jason/engine/application_helper.rb +6 -0
- data/app/jobs/jason/engine/application_job.rb +6 -0
- data/app/mailers/jason/engine/application_mailer.rb +8 -0
- data/app/models/jason/engine/application_record.rb +7 -0
- data/app/views/layouts/jason/engine/application.html.erb +15 -0
- data/client/babel.config.js +13 -0
- data/client/lib/JasonProvider.d.ts +5 -4
- data/client/lib/JasonProvider.js +30 -3
- data/client/lib/actionFactory.js +1 -1
- data/client/lib/createActions.d.ts +1 -1
- data/client/lib/createActions.js +2 -27
- data/client/lib/createJasonReducers.js +1 -0
- data/client/lib/createOptDis.d.ts +1 -0
- data/client/lib/createOptDis.js +45 -0
- data/client/lib/createPayloadHandler.d.ts +1 -1
- data/client/lib/createPayloadHandler.js +23 -6
- data/client/lib/deepCamelizeKeys.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.js +23 -0
- data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.test.js +106 -0
- data/client/lib/index.d.ts +4 -4
- data/client/package.json +17 -4
- data/client/src/JasonProvider.tsx +33 -5
- data/client/src/actionFactory.ts +1 -1
- data/client/src/createActions.ts +2 -33
- data/client/src/createJasonReducers.ts +1 -0
- data/client/src/createOptDis.ts +47 -0
- data/client/src/createPayloadHandler.ts +26 -4
- data/client/src/deepCamelizeKeys.test.ts +113 -0
- data/client/src/deepCamelizeKeys.ts +17 -0
- data/client/yarn.lock +4539 -81
- data/config/routes.rb +4 -0
- data/jason-rails.gemspec +5 -0
- data/lib/jason.rb +7 -1
- data/lib/jason/api_model.rb +16 -0
- data/lib/jason/channel.rb +2 -2
- data/lib/jason/engine.rb +5 -0
- data/lib/jason/publisher.rb +38 -6
- data/lib/jason/subscription.rb +21 -24
- data/lib/jason/version.rb +1 -1
- metadata +81 -3
data/config/routes.rb
ADDED
data/jason-rails.gemspec
CHANGED
@@ -22,4 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
end
|
23
23
|
spec.executables = []
|
24
24
|
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency "rails", ">= 5"
|
27
|
+
spec.add_dependency "connection_pool", ">= 2.2.3"
|
28
|
+
spec.add_dependency "redis", ">= 4"
|
29
|
+
spec.add_dependency "jsondiff"
|
25
30
|
end
|
data/lib/jason.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
require 'redis'
|
3
|
+
require 'jsondiff'
|
4
|
+
|
1
5
|
require "jason/version"
|
2
6
|
require 'jason/api_model'
|
3
7
|
require 'jason/channel'
|
4
8
|
require 'jason/publisher'
|
5
9
|
require 'jason/subscription'
|
10
|
+
require 'jason/engine'
|
6
11
|
|
7
12
|
module Jason
|
8
13
|
class Error < StandardError; end
|
9
|
-
|
14
|
+
|
15
|
+
$redis_jason = ::ConnectionPool::Wrapper.new(size: 5, timeout: 3) { ::Redis.new(url: ENV['REDIS_URL']) }
|
10
16
|
end
|
data/lib/jason/api_model.rb
CHANGED
@@ -15,6 +15,10 @@ class Jason::ApiModel
|
|
15
15
|
model.allowed_params || []
|
16
16
|
end
|
17
17
|
|
18
|
+
def allowed_object_params
|
19
|
+
model.allowed_object_params || []
|
20
|
+
end
|
21
|
+
|
18
22
|
def include_models
|
19
23
|
model.include_models || []
|
20
24
|
end
|
@@ -35,6 +39,18 @@ class Jason::ApiModel
|
|
35
39
|
model.scope
|
36
40
|
end
|
37
41
|
|
42
|
+
def permit(params)
|
43
|
+
pp self
|
44
|
+
pp params
|
45
|
+
params = params.require(:payload).permit(allowed_params).tap do |allowed|
|
46
|
+
pp "ALLOWED"
|
47
|
+
pp allowed
|
48
|
+
allowed_object_params.each do |key|
|
49
|
+
allowed[key] = params[:payload][key].to_unsafe_h if params[:payload][key]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
38
54
|
def as_json_config
|
39
55
|
include_configs = include_models.map do |assoc|
|
40
56
|
reflection = name.classify.constantize.reflect_on_association(assoc.to_sym)
|
data/lib/jason/channel.rb
CHANGED
@@ -24,8 +24,8 @@ class Jason::Channel < ActionCable::Channel::Base
|
|
24
24
|
# stream_from s.channel
|
25
25
|
# end
|
26
26
|
elsif (data = message['getPayload'])
|
27
|
-
config = data
|
28
|
-
model = data
|
27
|
+
config = data['config']
|
28
|
+
model = data['model']
|
29
29
|
Jason::Subscription.new(config: config).get(model.to_s.underscore)
|
30
30
|
end
|
31
31
|
rescue => e
|
data/lib/jason/engine.rb
ADDED
data/lib/jason/publisher.rb
CHANGED
@@ -7,17 +7,16 @@ module Jason::Publisher
|
|
7
7
|
|
8
8
|
if self.persisted? && (scope.blank? || self.class.unscoped.send(scope).exists?(self.id))
|
9
9
|
payload = self.reload.as_json(as_json_config)
|
10
|
-
$
|
10
|
+
$redis_jason.hset("jason:#{self.class.name.underscore}:cache", self.id, payload.to_json)
|
11
11
|
else
|
12
|
-
$
|
12
|
+
$redis_jason.hdel("jason:#{self.class.name.underscore}:cache", self.id)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def publish_json
|
17
17
|
cache_json
|
18
18
|
return if skip_publish_json
|
19
|
-
|
20
|
-
subscriptions.each do |id, config_json|
|
19
|
+
self.class.jason_subscriptions.each do |id, config_json|
|
21
20
|
config = JSON.parse(config_json)
|
22
21
|
|
23
22
|
if (config['conditions'] || {}).all? { |field, value| self.send(field) == value }
|
@@ -33,7 +32,11 @@ module Jason::Publisher
|
|
33
32
|
|
34
33
|
class_methods do
|
35
34
|
def subscriptions
|
36
|
-
$
|
35
|
+
$redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
|
36
|
+
end
|
37
|
+
|
38
|
+
def jason_subscriptions
|
39
|
+
$redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
|
37
40
|
end
|
38
41
|
|
39
42
|
def publish_all(instances)
|
@@ -45,7 +48,7 @@ module Jason::Publisher
|
|
45
48
|
end
|
46
49
|
|
47
50
|
def flush_cache
|
48
|
-
$
|
51
|
+
$redis_jason.del("jason:#{self.name.underscore}:cache")
|
49
52
|
end
|
50
53
|
|
51
54
|
def setup_json
|
@@ -69,6 +72,35 @@ module Jason::Publisher
|
|
69
72
|
}
|
70
73
|
end
|
71
74
|
end
|
75
|
+
|
76
|
+
def find_or_create_by_id(params)
|
77
|
+
object = find_by(id: params[:id])
|
78
|
+
|
79
|
+
if object
|
80
|
+
object.update(params)
|
81
|
+
elsif params[:hidden]
|
82
|
+
return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
|
83
|
+
else
|
84
|
+
object = create!(params)
|
85
|
+
end
|
86
|
+
|
87
|
+
object
|
88
|
+
end
|
89
|
+
|
90
|
+
def find_or_create_by_id!(params)
|
91
|
+
object = find_by(id: params[:id])
|
92
|
+
|
93
|
+
if object
|
94
|
+
object.update!(params)
|
95
|
+
elsif params[:hidden]
|
96
|
+
## 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.
|
97
|
+
return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
|
98
|
+
else
|
99
|
+
object = create!(params)
|
100
|
+
end
|
101
|
+
|
102
|
+
object
|
103
|
+
end
|
72
104
|
end
|
73
105
|
|
74
106
|
included do
|
data/lib/jason/subscription.rb
CHANGED
@@ -4,7 +4,7 @@ class Jason::Subscription
|
|
4
4
|
def initialize(id: nil, config: nil)
|
5
5
|
if id
|
6
6
|
@id = id
|
7
|
-
raw_config = $
|
7
|
+
raw_config = $redis_jason.hgetall("jason:subscriptions:#{id}").map { |k,v| [k, JSON.parse(v)] }.to_h.with_indifferent_access
|
8
8
|
set_config(raw_config)
|
9
9
|
else
|
10
10
|
@id = Digest::MD5.hexdigest(config.to_json)
|
@@ -18,30 +18,28 @@ class Jason::Subscription
|
|
18
18
|
|
19
19
|
def configure(raw_config)
|
20
20
|
set_config(raw_config)
|
21
|
-
$
|
21
|
+
$redis_jason.hmset("jason:subscriptions:#{id}", *config.map { |k,v| [k, v.to_json]}.flatten)
|
22
22
|
end
|
23
23
|
|
24
24
|
def destroy
|
25
25
|
config.each do |model, value|
|
26
|
-
$
|
26
|
+
$redis_jason.srem("jason:#{model.to_s.underscore}:subscriptions", id)
|
27
27
|
end
|
28
|
-
$
|
28
|
+
$redis_jason.del("jason:subscriptions:#{id}")
|
29
29
|
end
|
30
30
|
|
31
31
|
def add_consumer(consumer_id)
|
32
32
|
before_consumer_count = consumer_count
|
33
|
-
$
|
34
|
-
$
|
33
|
+
$redis_jason.sadd("jason:subscriptions:#{id}:consumers", consumer_id)
|
34
|
+
$redis_jason.hset("jason:consumers", consumer_id, Time.now.utc)
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
publish_all
|
39
|
-
end
|
36
|
+
add_subscriptions
|
37
|
+
publish_all
|
40
38
|
end
|
41
39
|
|
42
40
|
def remove_consumer(consumer_id)
|
43
|
-
$
|
44
|
-
$
|
41
|
+
$redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
|
42
|
+
$redis_jason.hdel("jason:consumers", consumer_id)
|
45
43
|
|
46
44
|
if consumer_count == 0
|
47
45
|
remove_subscriptions
|
@@ -49,7 +47,7 @@ class Jason::Subscription
|
|
49
47
|
end
|
50
48
|
|
51
49
|
def consumer_count
|
52
|
-
$
|
50
|
+
$redis_jason.scard("jason:subscriptions:#{id}:consumers")
|
53
51
|
end
|
54
52
|
|
55
53
|
def channel
|
@@ -67,14 +65,14 @@ class Jason::Subscription
|
|
67
65
|
|
68
66
|
def add_subscriptions
|
69
67
|
config.each do |model, value|
|
70
|
-
$
|
68
|
+
$redis_jason.hset("jason:#{model.to_s.underscore}:subscriptions", id, value.to_json)
|
71
69
|
update(model)
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
75
73
|
def remove_subscriptions
|
76
74
|
config.each do |model, _|
|
77
|
-
$
|
75
|
+
$redis_jason.hdel("jason:#{model.to_s.underscore}:subscriptions", id)
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
@@ -86,8 +84,8 @@ class Jason::Subscription
|
|
86
84
|
end
|
87
85
|
|
88
86
|
def get(model)
|
89
|
-
value = JSON.parse($
|
90
|
-
idx = $
|
87
|
+
value = JSON.parse($redis_jason.get("#{channel}:#{model}:value") || '[]')
|
88
|
+
idx = $redis_jason.get("#{channel}:#{model}:idx").to_i
|
91
89
|
|
92
90
|
{
|
93
91
|
type: 'payload',
|
@@ -113,7 +111,7 @@ class Jason::Subscription
|
|
113
111
|
def get_throttle
|
114
112
|
if !$throttle_rate || !$throttle_timeout || Time.now.utc > $throttle_timeout
|
115
113
|
$throttle_timeout = Time.now.utc + 5.seconds
|
116
|
-
$throttle_rate = (
|
114
|
+
$throttle_rate = ($redis_jason.get('global_throttle_rate') || 0).to_i
|
117
115
|
else
|
118
116
|
$throttle_rate
|
119
117
|
end
|
@@ -124,15 +122,15 @@ class Jason::Subscription
|
|
124
122
|
start_time = Time.now.utc
|
125
123
|
conditions = config[model]['conditions']
|
126
124
|
|
127
|
-
value = $
|
125
|
+
value = $redis_jason.hgetall("jason:#{model}:cache")
|
128
126
|
.values.map { |v| JSON.parse(v) }
|
129
127
|
.select { |v| (conditions || {}).all? { |field, value| v[field] == value } }
|
130
128
|
.sort_by { |v| v['id'] }
|
131
129
|
|
132
130
|
# lfsa = last finished, started at
|
133
131
|
# If another job that started after this one, finished before this one, skip sending this state update
|
134
|
-
if Time.parse(
|
135
|
-
|
132
|
+
if Time.parse($redis_jason.get("jason:#{channel}:lfsa") || '1970-01-01 00:00:00 UTC') < start_time
|
133
|
+
$redis_jason.set("jason:#{channel}:lfsa", start_time)
|
136
134
|
else
|
137
135
|
return
|
138
136
|
end
|
@@ -149,12 +147,11 @@ class Jason::Subscription
|
|
149
147
|
end
|
150
148
|
LUA
|
151
149
|
|
152
|
-
result = $
|
150
|
+
result = $redis_jason.eval cmd, [], ["#{channel}:#{model}", value.to_json]
|
153
151
|
return if result.blank?
|
154
152
|
|
155
153
|
idx = result[0]
|
156
|
-
old_value = JSON.parse(result[1] || '
|
157
|
-
|
154
|
+
old_value = JSON.parse(result[1] || '[]')
|
158
155
|
diff = get_diff(old_value, value)
|
159
156
|
|
160
157
|
end_time = Time.now.utc
|
data/lib/jason/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jason-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Rees
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
12
|
-
dependencies:
|
11
|
+
date: 2020-12-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: connection_pool
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.2.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.2.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: redis
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jsondiff
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
13
69
|
description:
|
14
70
|
email:
|
15
71
|
- jarees@gmail.com
|
@@ -22,11 +78,22 @@ files:
|
|
22
78
|
- ".travis.yml"
|
23
79
|
- CODE_OF_CONDUCT.md
|
24
80
|
- Gemfile
|
81
|
+
- Gemfile.lock
|
25
82
|
- LICENSE.txt
|
26
83
|
- README.md
|
27
84
|
- Rakefile
|
85
|
+
- app/assets/config/jason_engine_manifest.js
|
86
|
+
- app/assets/images/jason/engine/.keep
|
87
|
+
- app/assets/stylesheets/jason/engine/application.css
|
88
|
+
- app/controllers/jason/api_controller.rb
|
89
|
+
- app/helpers/jason/engine/application_helper.rb
|
90
|
+
- app/jobs/jason/engine/application_job.rb
|
91
|
+
- app/mailers/jason/engine/application_mailer.rb
|
92
|
+
- app/models/jason/engine/application_record.rb
|
93
|
+
- app/views/layouts/jason/engine/application.html.erb
|
28
94
|
- bin/console
|
29
95
|
- bin/setup
|
96
|
+
- client/babel.config.js
|
30
97
|
- client/lib/JasonContext.d.ts
|
31
98
|
- client/lib/JasonContext.js
|
32
99
|
- client/lib/JasonProvider.d.ts
|
@@ -37,8 +104,14 @@ files:
|
|
37
104
|
- client/lib/createActions.js
|
38
105
|
- client/lib/createJasonReducers.d.ts
|
39
106
|
- client/lib/createJasonReducers.js
|
107
|
+
- client/lib/createOptDis.d.ts
|
108
|
+
- client/lib/createOptDis.js
|
40
109
|
- client/lib/createPayloadHandler.d.ts
|
41
110
|
- client/lib/createPayloadHandler.js
|
111
|
+
- client/lib/deepCamelizeKeys.d.ts
|
112
|
+
- client/lib/deepCamelizeKeys.js
|
113
|
+
- client/lib/deepCamelizeKeys.test.d.ts
|
114
|
+
- client/lib/deepCamelizeKeys.test.js
|
42
115
|
- client/lib/index.d.ts
|
43
116
|
- client/lib/index.js
|
44
117
|
- client/lib/makeEager.d.ts
|
@@ -53,17 +126,22 @@ files:
|
|
53
126
|
- client/src/actionFactory.ts
|
54
127
|
- client/src/createActions.ts
|
55
128
|
- client/src/createJasonReducers.ts
|
129
|
+
- client/src/createOptDis.ts
|
56
130
|
- client/src/createPayloadHandler.ts
|
131
|
+
- client/src/deepCamelizeKeys.test.ts
|
132
|
+
- client/src/deepCamelizeKeys.ts
|
57
133
|
- client/src/index.ts
|
58
134
|
- client/src/makeEager.ts
|
59
135
|
- client/src/useAct.ts
|
60
136
|
- client/src/useSub.ts
|
61
137
|
- client/tsconfig.json
|
62
138
|
- client/yarn.lock
|
139
|
+
- config/routes.rb
|
63
140
|
- jason-rails.gemspec
|
64
141
|
- lib/jason.rb
|
65
142
|
- lib/jason/api_model.rb
|
66
143
|
- lib/jason/channel.rb
|
144
|
+
- lib/jason/engine.rb
|
67
145
|
- lib/jason/publisher.rb
|
68
146
|
- lib/jason/subscription.rb
|
69
147
|
- lib/jason/version.rb
|