Module: ArSync
- Defined in:
- lib/ar_sync.rb,
lib/ar_sync/core.rb,
lib/ar_sync/rails.rb,
lib/ar_sync/config.rb,
lib/ar_sync/version.rb,
lib/generators/ar_sync/types/types_generator.rb,
lib/generators/ar_sync/install/install_generator.rb
Defined Under Namespace
Modules: ApiControllerConcern, ClassMethodsBase, GraphSync, Rails, StaticJsonConcern, TreeSync, TypeScript
Classes: ApiNotFound, Collection, CollectionField, CollectionWithOrder, Config, DataField, Field, HasManyField, HasOneField, InstallGenerator, TypesGenerator
Constant Summary
collapse
- VERSION =
'1.0.1'
Class Method Summary
collapse
-
._extract_paths(args) ⇒ Object
-
.config ⇒ Object
-
.configure {|config| ... } ⇒ Object
-
.on_notification(&block) ⇒ Object
-
.serialize(record_or_records, query, user: nil) ⇒ Object
-
.signed_key(key, time) ⇒ Object
-
.skip_notification? ⇒ Boolean
-
.sync_api(model, current_user, args) ⇒ Object
-
.sync_collection_api(collection, current_user, args) ⇒ Object
-
.sync_graph_key(model, to_user = nil, signature: true) ⇒ Object
-
.sync_graph_keys(model, user) ⇒ Object
-
.sync_graph_send(to:, action:, model:, path: nil, to_user: nil) ⇒ Object
-
.sync_key(model, path, to_user = nil, signature: true) ⇒ Object
-
.sync_tree_send(to:, action:, path:, data:, to_user: nil, ordering: nil) ⇒ Object
-
.use(mode, klass: ActiveRecord::Base) ⇒ Object
-
.validate_expiration(signed_key) ⇒ Object
-
.with_compact_notification ⇒ Object
-
.without_notification ⇒ Object
Class Method Details
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# File 'lib/ar_sync/core.rb', line 119
def self.(args)
parsed = ArSerializer::Serializer.parse_args args
paths = []
= lambda do |path, attributes|
paths << path
attributes.each do |key, value|
sub_attributes = value[:attributes]
next unless sub_attributes
sub_path = [*path, key]
.call sub_path, sub_attributes
end
end
.call [], parsed[:attributes]
paths
end
|
.config ⇒ Object
11
12
13
|
# File 'lib/ar_sync/config.rb', line 11
def self.config
@config ||= Config.new :current_user, nil, nil
end
|
15
16
17
|
# File 'lib/ar_sync/config.rb', line 15
def self.configure
yield config
end
|
.on_notification(&block) ⇒ Object
17
18
19
|
# File 'lib/ar_sync/core.rb', line 17
def self.on_notification(&block)
@sync_send_block = block
end
|
.serialize(record_or_records, query, user: nil) ⇒ Object
135
136
137
|
# File 'lib/ar_sync/core.rb', line 135
def self.serialize(record_or_records, query, user: nil)
ArSerializer.serialize record_or_records, query, context: user, include_id: true, use: :sync
end
|
.signed_key(key, time) ⇒ Object
93
94
95
|
# File 'lib/ar_sync/core.rb', line 93
def self.signed_key(key, time)
"#{key};#{time};#{Digest::SHA256.hexdigest("#{config.key_secret}#{key};#{time}")[0, 16]}"
end
|
.skip_notification? ⇒ Boolean
31
32
33
|
# File 'lib/ar_sync/core.rb', line 31
def self.skip_notification?
Thread.current[:ar_sync_skip_notification]
end
|
.sync_api(model, current_user, args) ⇒ Object
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/ar_sync/core.rb', line 108
def self.sync_api(model, current_user, args)
paths = args
keys = paths.flat_map do |path|
[sync_key(model, path), sync_key(model, path, current_user)]
end
{
keys: keys,
data: serialize(model, args, user: current_user)
}
end
|
.sync_collection_api(collection, current_user, args) ⇒ Object
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/ar_sync/core.rb', line 97
def self.sync_collection_api(collection, current_user, args)
paths = args
keys = paths.flat_map do |path|
[sync_key(collection, path), sync_key(collection, path, current_user)]
end
{
keys: keys,
data: serialize(collection.to_a, args, user: current_user)
}
end
|
.sync_graph_key(model, to_user = nil, signature: true) ⇒ Object
66
67
68
|
# File 'lib/ar_sync/core.rb', line 66
def self.sync_graph_key(model, to_user = nil, signature: true)
sync_key(model, :graph_sync, to_user, signature: signature) + ';/'
end
|
.sync_graph_keys(model, user) ⇒ Object
70
71
72
|
# File 'lib/ar_sync/core.rb', line 70
def self.sync_graph_keys(model, user)
[sync_graph_key(model), sync_graph_key(model, user)]
end
|
.sync_graph_send(to:, action:, model:, path: nil, to_user: nil) ⇒ Object
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/ar_sync/core.rb', line 55
def self.sync_graph_send(to:, action:, model:, path: nil, to_user: nil)
key = sync_graph_key to, to_user, signature: false
event = ["#{key}#{path}", action: action, class_name: model.class.base_class.name, id: model.id]
buffer = Thread.current[:ar_sync_compact_notifications]
if buffer
buffer << event
else
@sync_send_block&.call [event]
end
end
|
.sync_key(model, path, to_user = nil, signature: true) ⇒ Object
74
75
76
77
78
79
80
81
82
83
|
# File 'lib/ar_sync/core.rb', line 74
def self.sync_key(model, path, to_user = nil, signature: true)
if model.is_a? ArSync::Collection
key = [to_user&.id, model.klass.name, model.name, path].join '/'
else
key = [to_user&.id, model.class.name, model.id, path].join '/'
end
key = Digest::SHA256.hexdigest("#{config.key_secret}#{key}")[0, 32] if config.key_secret
key = "#{config.key_prefix}#{key}" if config.key_prefix
signature && config.key_expires_in ? signed_key(key, Time.now.to_i.to_s) : key
end
|
.sync_tree_send(to:, action:, path:, data:, to_user: nil, ordering: nil) ⇒ Object
44
45
46
47
48
49
50
51
52
53
|
# File 'lib/ar_sync/core.rb', line 44
def self.sync_tree_send(to:, action:, path:, data:, to_user: nil, ordering: nil)
key = sync_key to, path.grep(Symbol), to_user, signature: false
event = [key, action: action, path: path, data: data, ordering: ordering]
buffer = Thread.current[:ar_sync_compact_notifications]
if buffer
buffer << event
else
@sync_send_block&.call [event]
end
end
|
.use(mode, klass: ActiveRecord::Base) ⇒ Object
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# File 'lib/ar_sync.rb', line 4
def self.use(mode, klass: ActiveRecord::Base)
case mode
when :tree
if klass.ancestors.include? ArSync::GraphSync
raise ArgumentError, 'already activated ArSync::GraphSync'
end
klass.include ArSync::TreeSync
when :graph
if klass.ancestors.include? ArSync::TreeSync
raise ArgumentError, 'already activated ArSync::TreeSync'
end
klass.include ArSync::GraphSync
else
raise ArgumentError, 'argument should be :tree or :graph'
end
end
|
.validate_expiration(signed_key) ⇒ Object
85
86
87
88
89
90
91
|
# File 'lib/ar_sync/core.rb', line 85
def self.validate_expiration(signed_key)
signed_key = signed_key.to_s
return signed_key unless config.key_expires_in
key, time, signature, other = signed_key.split ';', 4
return unless signed_key(key, time) == [key, time, signature].join(';')
[key, other].compact.join ';' if Time.now.to_i - time.to_i < config.key_expires_in
end
|
.with_compact_notification ⇒ Object
21
22
23
24
25
26
27
28
29
|
# File 'lib/ar_sync/core.rb', line 21
def self.with_compact_notification
key = :ar_sync_compact_notifications
Thread.current[key] = []
yield
ensure
events = Thread.current[key]
Thread.current[key] = nil
@sync_send_block&.call events if events.present?
end
|
.without_notification ⇒ Object
35
36
37
38
39
40
41
42
|
# File 'lib/ar_sync/core.rb', line 35
def self.without_notification
key = :ar_sync_skip_notification
flag_was = Thread.current[key]
Thread.current[key] = true
yield
ensure
Thread.current[key] = flag_was
end
|