loco-rails 4.0.0 → 6.0.0

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.
data/lib/loco/sender.rb CHANGED
@@ -2,43 +2,60 @@
2
2
 
3
3
  module Loco
4
4
  class Sender
5
- def initialize(recipient, data = {})
6
- @recipients = [*recipient]
7
- @data = data
5
+ class << self
6
+ def call(recipient_s, payload = {})
7
+ payload = with_idempotency_key(payload)
8
+ recipients = recipient_s.is_a?(Array) ? recipient_s : [recipient_s]
9
+ new.(recipients, payload)
10
+ end
11
+
12
+ private
13
+
14
+ def with_idempotency_key(payload)
15
+ hash = payload.clone
16
+ hash[:loco] ||= {}
17
+ hash[:loco][:idempotency_key] ||= hash[:idempotency_key] || SecureRandom.hex
18
+ hash.delete(:idempotency_key)
19
+ hash
20
+ end
21
+ end
22
+
23
+ def initialize
24
+ @uuids = []
8
25
  end
9
26
 
10
- def emit
11
- uuids.each do |uuid|
12
- NotificationCenterChannel.broadcast_to(uuid, payload)
27
+ def call(recipients, payload)
28
+ recipients.each do |recipient|
29
+ case recipient
30
+ when String then broadcast_to(recipient, payload)
31
+ when Hash then process_hash(recipient, payload)
32
+ else find_and_broadcast_to(recipient, payload)
33
+ end
13
34
  end
14
- @data[:loco][:idempotency_key]
35
+ payload[:loco][:idempotency_key]
15
36
  end
16
37
 
17
38
  private
18
39
 
19
- def uuids
20
- @recipients.map do |r|
21
- if r.is_a? String
22
- r
23
- elsif r.is_a? Hub
24
- recipients_from_hub r
25
- else
26
- WsConnectionManager.new(r).connected_uuids
27
- end
28
- end.flatten.uniq
40
+ def process_hash(recipient, payload)
41
+ if recipient.key?('token')
42
+ find_and_broadcast_to(recipient['token'], payload)
43
+ elsif recipient.key?('class')
44
+ find_and_broadcast_to(recipient['class'].constantize, payload)
45
+ end
29
46
  end
30
47
 
31
- def recipients_from_hub(hub)
32
- hub.raw_members.map do |m|
33
- WsConnectionManager.new(m).connected_uuids
34
- end.flatten.uniq
48
+ def find_and_broadcast_to(recipient, payload)
49
+ WsConnectionFinder.(recipient) do |uuid|
50
+ broadcast_to(uuid, payload)
51
+ end
35
52
  end
36
53
 
37
- def payload
38
- @data[:loco] ||= {}
39
- @data[:loco][:idempotency_key] ||= @data[:idempotency_key] || SecureRandom.hex
40
- @data.delete(:idempotency_key)
41
- @data
54
+ def broadcast_to(uuid, payload)
55
+ return if @uuids.include?(uuid)
56
+
57
+ @uuids << uuid
58
+ NotificationCenterChannel.broadcast_to(uuid, payload)
42
59
  end
43
60
  end
44
61
  end
data/lib/loco/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loco
4
- VERSION = '4.0.0'
4
+ VERSION = '6.0.0'
5
5
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Loco
4
+ module WsConnectionChecker
5
+ module_function
6
+
7
+ def call(identifier, skip: nil)
8
+ WsConnectionStorage.current.members(identifier).each do |uuid|
9
+ next if uuid == skip
10
+ next if WsConnectionStorage.current.get(uuid) == 'ok'
11
+
12
+ WsConnectionManager.new(identifier, identifier: true).del(uuid, skip_checker: true)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Loco
4
+ class WsConnectionFinder
5
+ class << self
6
+ def call(resources, &block)
7
+ storage = WsConnectionStorage.current
8
+ resources = [resources] unless resources.is_a?(Array)
9
+ resources.each do |resource|
10
+ case resource
11
+ when :all then storage.scan(all: true, &block)
12
+ when Hub then search_the_hub(resource, &block)
13
+ when Class
14
+ storage.scan(match: "#{WsConnectionIdentifier.(resource)}:*", &block)
15
+ else
16
+ storage.members(WsConnectionIdentifier.(resource)).each(&block)
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def search_the_hub(resource, &block)
24
+ WsConnectionStorage.current.members(resource.full_name).map do |serialized|
25
+ WsConnectionStorage.current.members(serialized).each(&block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Loco
4
+ module WsConnectionIdentifier
5
+ module_function
6
+
7
+ def call(resource)
8
+ case resource
9
+ when String then resource
10
+ when Class then resource.name.downcase
11
+ else "#{resource.class.name.downcase}:#{resource.id}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,92 +2,38 @@
2
2
 
3
3
  module Loco
4
4
  class WsConnectionManager
5
- def initialize(resource)
6
- @resource = resource
7
- end
8
-
9
- def identifier
10
- return @resource if @resource.is_a?(String)
11
-
12
- "#{@resource.class.name.downcase}:#{@resource.id}"
13
- end
14
-
15
- def connected?(uuid)
16
- connected_uuids.include? uuid
17
- end
5
+ EXPIRATION = 60 * 3
18
6
 
19
- def connected_uuids
20
- data.find_all { |_, v| v.is_a? String }.to_h.keys
7
+ def initialize(resource, opts = {})
8
+ if opts[:identifier]
9
+ @identifier = resource
10
+ else
11
+ @resource = resource
12
+ end
21
13
  end
22
14
 
23
15
  def add(uuid)
24
- update uuid
25
- check_connections
16
+ WsConnectionStorage.current.add(identifier, uuid)
17
+ WsConnectionStorage.current.add("uuid:#{uuid}", identifier)
18
+ update(uuid)
19
+ WsConnectionChecker.(identifier, skip: uuid)
26
20
  end
27
21
 
28
- def del(uuid)
29
- save(data.tap { |h| h.delete uuid })
30
- check_connections
22
+ def del(uuid, skip_checker: false)
23
+ WsConnectionStorage.current.rem(identifier, uuid)
24
+ WsConnectionStorage.current.rem("uuid:#{uuid}", identifier)
25
+ WsConnectionStorage.current.del(uuid)
26
+ WsConnectionChecker.(identifier) unless skip_checker
31
27
  end
32
28
 
33
29
  def update(uuid)
34
- save(data.tap { |h| h[uuid] = current_time })
30
+ WsConnectionStorage.current.set(uuid, 'ok', ex: EXPIRATION)
35
31
  end
36
32
 
37
- def destroy
38
- WsConnectionStorage.current.del identifier
39
- end
40
-
41
- protected
42
-
43
- def data
44
- serialized_uuids = WsConnectionStorage.current.get identifier
45
- return {} if serialized_uuids.blank?
46
-
47
- JSON.parse serialized_uuids
48
- end
49
-
50
- def uuids
51
- data.keys
52
- end
33
+ private
53
34
 
54
- def save(hash)
55
- WsConnectionStorage.current.set identifier, hash.to_json
56
- end
57
-
58
- def check_connections
59
- hash = data.to_a.map do |arr|
60
- uuid, val = check_connection arr.first, arr.last
61
- [uuid, val]
62
- end.to_h.compact
63
- save hash
64
- end
65
-
66
- def check_connection(uuid, val)
67
- case val
68
- when String
69
- val = check_connection_str uuid, val
70
- when Hash
71
- uuid, val = check_connection_hash uuid, val
72
- end
73
- [uuid, val]
74
- end
75
-
76
- def check_connection_str(uuid, val)
77
- return val if Time.zone.parse(val) >= 3.minutes.ago
78
-
79
- SenderJob.perform_later uuid, loco: { connection_check: true }
80
- { 'check' => current_time }
81
- end
82
-
83
- def check_connection_hash(uuid, val)
84
- return [uuid, val] if Time.zone.parse(val['check']) >= 5.seconds.ago
85
-
86
- [nil, nil]
87
- end
88
-
89
- def current_time
90
- Time.current.iso8601(6)
35
+ def identifier
36
+ @identifier ||= WsConnectionIdentifier.(@resource)
91
37
  end
92
38
  end
93
39
  end
@@ -13,37 +13,77 @@ module Loco
13
13
  end
14
14
 
15
15
  def initialize
16
- @storage = Config.redis_instance || {}
16
+ @storage = Config.redis_instance
17
17
  end
18
18
 
19
- def get(key)
20
- case @storage
21
- when Hash
22
- storage[proper_key(key)]
19
+ def type(key)
20
+ storage.type(proper_key(key))
21
+ end
22
+
23
+ def exists?(key)
24
+ storage.exists?(proper_key(key))
25
+ end
26
+
27
+ def get(key, hkey = nil)
28
+ if hkey.nil?
29
+ storage.get(proper_key("k:#{key}"))
23
30
  else
24
- storage.get proper_key(key)
31
+ storage.hget(proper_key("h:#{key}"), hkey)
25
32
  end
26
33
  end
27
34
 
28
- def set(key, val)
29
- case @storage
30
- when Hash
31
- storage[proper_key(key)] = val
35
+ def set(key, val, opts = {})
36
+ if val.is_a?(Hash)
37
+ storage.hset(proper_key("h:#{key}"), val)
32
38
  else
33
- storage.set proper_key(key), val
39
+ storage.set(proper_key("k:#{key}"), val, ex: opts[:ex])
34
40
  end
35
41
  end
36
42
 
37
- def del(key)
38
- case @storage
39
- when Hash
40
- storage.delete proper_key(key)
43
+ def del(key, hkey = nil)
44
+ if hkey.nil?
45
+ storage.del(proper_key("k:#{key}"))
41
46
  else
42
- storage.del proper_key(key)
47
+ storage.hdel(proper_key("h:#{key}"), hkey)
48
+ end
49
+ end
50
+
51
+ def scan(match: nil, all: false, &block)
52
+ match = 'uuid:*' if all
53
+ storage.scan_each(match: "#{proper_key('s:')}#{match}").each do |key|
54
+ if all
55
+ yield(key.split('uuid:').last)
56
+ else
57
+ storage.smembers(key).each(&block)
58
+ end
43
59
  end
44
60
  end
45
61
 
46
- protected
62
+ def scan_hash(key, &block)
63
+ storage.hscan_each(proper_key("h:#{key}"), &block)
64
+ end
65
+
66
+ def hlen(key)
67
+ storage.hlen(proper_key("h:#{key}"))
68
+ end
69
+
70
+ def add(key, val)
71
+ storage.sadd(proper_key("s:#{key}"), val)
72
+ end
73
+
74
+ def members(key)
75
+ storage.smembers(proper_key("s:#{key}"))
76
+ end
77
+
78
+ def member?(key, val)
79
+ storage.sismember(proper_key("s:#{key}"), val)
80
+ end
81
+
82
+ def rem(key, val)
83
+ storage.srem(proper_key("s:#{key}"), val)
84
+ end
85
+
86
+ private
47
87
 
48
88
  def proper_key(key)
49
89
  "#{Config.app_name}:#{key}"
data/lib/loco-rails.rb CHANGED
@@ -5,12 +5,15 @@ require 'loco-rails-core'
5
5
  require 'loco/broadcaster'
6
6
  require 'loco/config'
7
7
  require 'loco/emitter'
8
- require 'loco/engine'
8
+ require 'loco/rails/engine'
9
9
  require 'loco/helpers'
10
10
  require 'loco/hub'
11
+ require 'loco/permissions_presenter'
11
12
  require 'loco/sender'
13
+ require 'loco/ws_connection_checker'
12
14
  require 'loco/ws_connection_manager'
13
- require 'loco/ws_connected_resources_manager'
15
+ require 'loco/ws_connection_finder'
16
+ require 'loco/ws_connection_identifier'
14
17
  require 'loco/ws_connection_storage'
15
18
 
16
19
  module Loco
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loco-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zbigniew Humeniuk
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-26 00:00:00.000000000 Z
11
+ date: 2022-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: loco-rails-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.1
19
+ version: 0.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.1
26
+ version: 0.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,76 +44,70 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.1.12
47
+ version: 3.1.16
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.1.12
54
+ version: 3.1.16
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: capybara
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 3.28.0
61
+ version: 3.36.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 3.28.0
68
+ version: 3.36.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: database_cleaner
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.7.0
75
+ version: 2.0.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 1.7.0
82
+ version: 2.0.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: jbuilder
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 2.10.0
89
+ version: 2.11.5
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 2.10.0
96
+ version: 2.11.5
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: listen
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 3.1.5
104
- - - "<"
101
+ - - "~>"
105
102
  - !ruby/object:Gem::Version
106
- version: '3.2'
103
+ version: 3.7.1
107
104
  type: :development
108
105
  prerelease: false
109
106
  version_requirements: !ruby/object:Gem::Requirement
110
107
  requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- version: 3.1.5
114
- - - "<"
108
+ - - "~>"
115
109
  - !ruby/object:Gem::Version
116
- version: '3.2'
110
+ version: 3.7.1
117
111
  - !ruby/object:Gem::Dependency
118
112
  name: mysql2
119
113
  requirement: !ruby/object:Gem::Requirement
@@ -134,28 +128,56 @@ dependencies:
134
128
  requirements:
135
129
  - - "~>"
136
130
  - !ruby/object:Gem::Version
137
- version: '4.2'
131
+ version: 5.5.2
138
132
  type: :development
139
133
  prerelease: false
140
134
  version_requirements: !ruby/object:Gem::Requirement
141
135
  requirements:
142
136
  - - "~>"
143
137
  - !ruby/object:Gem::Version
144
- version: '4.2'
138
+ version: 5.5.2
145
139
  - !ruby/object:Gem::Dependency
146
140
  name: redis
147
141
  requirement: !ruby/object:Gem::Requirement
148
142
  requirements:
149
143
  - - "~>"
150
144
  - !ruby/object:Gem::Version
151
- version: 4.1.2
145
+ version: 4.5.1
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 4.5.1
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-expectations
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 3.10.2
152
160
  type: :development
153
161
  prerelease: false
154
162
  version_requirements: !ruby/object:Gem::Requirement
155
163
  requirements:
156
164
  - - "~>"
157
165
  - !ruby/object:Gem::Version
158
- version: 4.1.2
166
+ version: 3.10.2
167
+ - !ruby/object:Gem::Dependency
168
+ name: rspec-mocks
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 3.10.2
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 3.10.2
159
181
  - !ruby/object:Gem::Dependency
160
182
  name: rubocop
161
183
  requirement: !ruby/object:Gem::Requirement
@@ -190,42 +212,42 @@ dependencies:
190
212
  requirements:
191
213
  - - "~>"
192
214
  - !ruby/object:Gem::Version
193
- version: '3.142'
215
+ version: 4.1.0
194
216
  type: :development
195
217
  prerelease: false
196
218
  version_requirements: !ruby/object:Gem::Requirement
197
219
  requirements:
198
220
  - - "~>"
199
221
  - !ruby/object:Gem::Version
200
- version: '3.142'
222
+ version: 4.1.0
201
223
  - !ruby/object:Gem::Dependency
202
- name: source_maps_fixer
224
+ name: sprockets-rails
203
225
  requirement: !ruby/object:Gem::Requirement
204
226
  requirements:
205
- - - ">="
227
+ - - "~>"
206
228
  - !ruby/object:Gem::Version
207
- version: '0'
229
+ version: 3.4.2
208
230
  type: :development
209
231
  prerelease: false
210
232
  version_requirements: !ruby/object:Gem::Requirement
211
233
  requirements:
212
- - - ">="
234
+ - - "~>"
213
235
  - !ruby/object:Gem::Version
214
- version: '0'
236
+ version: 3.4.2
215
237
  - !ruby/object:Gem::Dependency
216
238
  name: will_paginate
217
239
  requirement: !ruby/object:Gem::Requirement
218
240
  requirements:
219
241
  - - "~>"
220
242
  - !ruby/object:Gem::Version
221
- version: 3.1.8
243
+ version: 3.3.1
222
244
  type: :development
223
245
  prerelease: false
224
246
  version_requirements: !ruby/object:Gem::Requirement
225
247
  requirements:
226
248
  - - "~>"
227
249
  - !ruby/object:Gem::Version
228
- version: 3.1.8
250
+ version: 3.3.1
229
251
  description: Rails is awesome, but modern web needs Loco-motive.
230
252
  email:
231
253
  - hello@artofcode.co
@@ -239,7 +261,6 @@ files:
239
261
  - app/controllers/loco/application_controller.rb
240
262
  - app/controllers/loco/notification_center_controller.rb
241
263
  - app/jobs/loco/sender_job.rb
242
- - app/jobs/loco/uuid_job.rb
243
264
  - app/models/loco/notification.rb
244
265
  - app/services/loco/notification/fetcher.rb
245
266
  - config/routes.rb
@@ -260,19 +281,23 @@ files:
260
281
  - lib/loco/broadcaster.rb
261
282
  - lib/loco/config.rb
262
283
  - lib/loco/emitter.rb
263
- - lib/loco/engine.rb
264
284
  - lib/loco/helpers.rb
265
285
  - lib/loco/hub.rb
286
+ - lib/loco/permissions_presenter.rb
287
+ - lib/loco/rails/engine.rb
266
288
  - lib/loco/sender.rb
267
289
  - lib/loco/version.rb
268
- - lib/loco/ws_connected_resources_manager.rb
290
+ - lib/loco/ws_connection_checker.rb
291
+ - lib/loco/ws_connection_finder.rb
292
+ - lib/loco/ws_connection_identifier.rb
269
293
  - lib/loco/ws_connection_manager.rb
270
294
  - lib/loco/ws_connection_storage.rb
271
295
  homepage: http://locoframework.org
272
296
  licenses:
273
297
  - MIT
274
- metadata: {}
275
- post_install_message:
298
+ metadata:
299
+ rubygems_mfa_required: 'true'
300
+ post_install_message:
276
301
  rdoc_options: []
277
302
  require_paths:
278
303
  - lib
@@ -280,15 +305,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
280
305
  requirements:
281
306
  - - ">="
282
307
  - !ruby/object:Gem::Version
283
- version: '0'
308
+ version: 2.7.0
284
309
  required_rubygems_version: !ruby/object:Gem::Requirement
285
310
  requirements:
286
311
  - - ">="
287
312
  - !ruby/object:Gem::Version
288
313
  version: '0'
289
314
  requirements: []
290
- rubygems_version: 3.1.2
291
- signing_key:
315
+ rubygems_version: 3.3.3
316
+ signing_key:
292
317
  specification_version: 4
293
318
  summary: Framework on top of Rails.
294
319
  test_files: []