loco-rails 4.1.1 → 5.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.
- checksums.yaml +4 -4
- data/app/channels/loco/notification_center_channel.rb +17 -41
- data/app/controllers/loco/notification_center_controller.rb +6 -31
- data/app/jobs/loco/sender_job.rb +1 -1
- data/app/models/loco/notification.rb +31 -30
- data/app/services/loco/notification/fetcher.rb +12 -25
- data/lib/generators/loco/file_injector/templates/connection.rb +1 -0
- data/lib/loco-rails.rb +4 -1
- data/lib/loco/broadcaster.rb +34 -82
- data/lib/loco/emitter.rb +11 -6
- data/lib/loco/hub.rb +33 -40
- data/lib/loco/permissions_presenter.rb +27 -0
- data/lib/loco/sender.rb +42 -25
- data/lib/loco/version.rb +1 -1
- data/lib/loco/ws_connection_checker.rb +16 -0
- data/lib/loco/ws_connection_finder.rb +30 -0
- data/lib/loco/ws_connection_identifier.rb +15 -0
- data/lib/loco/ws_connection_manager.rb +20 -74
- data/lib/loco/ws_connection_storage.rb +57 -17
- metadata +52 -42
- data/app/jobs/loco/uuid_job.rb +0 -51
- data/lib/loco/ws_connected_resources_manager.rb +0 -64
data/lib/loco/emitter.rb
CHANGED
@@ -3,23 +3,28 @@
|
|
3
3
|
module Loco
|
4
4
|
module Emitter
|
5
5
|
def emit(obj, event = nil, opts = {})
|
6
|
-
Broadcaster.
|
6
|
+
Broadcaster.(
|
7
|
+
obj,
|
8
|
+
event,
|
9
|
+
payload: opts[:payload] || opts[:data],
|
10
|
+
recipients: opts[opts[:for] ? :for : :to]
|
11
|
+
)
|
7
12
|
end
|
8
13
|
|
9
|
-
def emit_to(
|
10
|
-
Sender.
|
14
|
+
def emit_to(recipient_s, data)
|
15
|
+
Sender.(recipient_s, data)
|
11
16
|
end
|
12
17
|
|
13
18
|
def add_hub(name, members = [])
|
14
|
-
Hub.
|
19
|
+
Hub.set(name, members)
|
15
20
|
end
|
16
21
|
|
17
22
|
def get_hub(name)
|
18
|
-
Hub.get
|
23
|
+
Hub.get(name)
|
19
24
|
end
|
20
25
|
|
21
26
|
def del_hub(name)
|
22
|
-
hub = Hub.get
|
27
|
+
hub = Hub.get(name)
|
23
28
|
return false if hub.nil?
|
24
29
|
|
25
30
|
hub.destroy
|
data/lib/loco/hub.rb
CHANGED
@@ -2,71 +2,64 @@
|
|
2
2
|
|
3
3
|
module Loco
|
4
4
|
class Hub
|
5
|
-
PREFIX = '
|
6
|
-
|
7
|
-
attr_reader :raw_members
|
8
|
-
|
9
|
-
def initialize(name, members = [])
|
10
|
-
@name = "#{PREFIX}#{name}"
|
11
|
-
@raw_members = members.map { |m| serialize m }
|
12
|
-
end
|
5
|
+
PREFIX = 'hub:'
|
13
6
|
|
14
7
|
class << self
|
8
|
+
def set(name, members)
|
9
|
+
new(name, members)
|
10
|
+
end
|
11
|
+
|
15
12
|
def get(name)
|
16
|
-
|
17
|
-
return nil if hub.blank?
|
13
|
+
return nil if WsConnectionStorage.current.type("s:#{full_name(name)}") != 'set'
|
18
14
|
|
19
|
-
new
|
15
|
+
new(name)
|
20
16
|
end
|
17
|
+
|
18
|
+
def full_name(val)
|
19
|
+
"#{PREFIX}#{val}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(name, members = [])
|
24
|
+
@name = self.class.full_name(name)
|
25
|
+
members.map { |member| add_member(member) }
|
21
26
|
end
|
22
27
|
|
23
28
|
def name
|
24
|
-
|
29
|
+
full_name.split(PREFIX).last
|
25
30
|
end
|
26
31
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
32
|
+
def full_name
|
33
|
+
@name
|
34
|
+
end
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
raw_members
|
36
|
+
def add_member(member)
|
37
|
+
WsConnectionStorage.current.add(@name, WsConnectionIdentifier.(member))
|
34
38
|
end
|
35
39
|
|
36
40
|
def del_member(member)
|
37
|
-
|
38
|
-
return nil unless raw_members.include? serialized
|
39
|
-
|
40
|
-
raw_members.delete serialized
|
41
|
-
save
|
42
|
-
serialized
|
41
|
+
WsConnectionStorage.current.rem(@name, WsConnectionIdentifier.(member))
|
43
42
|
end
|
44
43
|
|
45
44
|
def destroy
|
46
|
-
WsConnectionStorage.current.
|
47
|
-
|
45
|
+
WsConnectionStorage.current.members(@name).each do |member|
|
46
|
+
WsConnectionStorage.current.rem(@name, member)
|
47
|
+
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
WsConnectionStorage.current.
|
52
|
-
self
|
50
|
+
def include?(resource)
|
51
|
+
WsConnectionStorage.current.member?(@name, WsConnectionIdentifier.(resource))
|
53
52
|
end
|
54
53
|
|
55
|
-
def
|
56
|
-
|
54
|
+
def raw_members
|
55
|
+
WsConnectionStorage.current.members(@name)
|
57
56
|
end
|
58
57
|
|
59
58
|
def members
|
60
|
-
raw_members.map do |
|
61
|
-
klass, id =
|
62
|
-
klass.classify.constantize.find_by
|
59
|
+
raw_members.map do |serialized|
|
60
|
+
klass, id = serialized.split(':')
|
61
|
+
klass.classify.constantize.find_by(id: id)
|
63
62
|
end
|
64
63
|
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def serialize(member)
|
69
|
-
WsConnectionManager.new(member).identifier
|
70
|
-
end
|
71
64
|
end
|
72
65
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Loco
|
4
|
+
module PermissionsPresenter
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def indexed(loco_permissions, opts = {})
|
8
|
+
h = signed_in(loco_permissions).index_by do |o|
|
9
|
+
o.class.name.downcase.to_sym
|
10
|
+
end
|
11
|
+
if opts[:except] == :uuid
|
12
|
+
h.reject { |k, _| k == :string }
|
13
|
+
else
|
14
|
+
h
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def signed_in(loco_permissions, opts = {})
|
19
|
+
arr = loco_permissions.compact
|
20
|
+
if opts[:except] == :uuid
|
21
|
+
arr.reject { |e| e.is_a?(String) }
|
22
|
+
else
|
23
|
+
arr
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/loco/sender.rb
CHANGED
@@ -2,43 +2,60 @@
|
|
2
2
|
|
3
3
|
module Loco
|
4
4
|
class Sender
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
11
|
-
|
12
|
-
|
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
35
|
payload[:loco][:idempotency_key]
|
15
36
|
end
|
16
37
|
|
17
38
|
private
|
18
39
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
32
|
-
|
33
|
-
|
34
|
-
end
|
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
|
-
|
39
|
-
|
40
|
-
@
|
41
|
-
|
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
@@ -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
|
-
|
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
|
20
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
30
|
+
WsConnectionStorage.current.set(uuid, 'ok', ex: EXPIRATION)
|
35
31
|
end
|
36
32
|
|
37
|
-
|
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
|
55
|
-
|
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
|
20
|
-
|
21
|
-
|
22
|
-
|
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.hget(proper_key("h:#{key}"), hkey)
|
23
30
|
else
|
24
|
-
storage.get
|
31
|
+
storage.get(proper_key("k:#{key}"))
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
28
|
-
def set(key, val)
|
29
|
-
|
30
|
-
|
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
|
39
|
+
storage.set(proper_key("k:#{key}"), val, ex: opts[:ex])
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
|
-
def del(key)
|
38
|
-
|
39
|
-
|
40
|
-
storage.delete proper_key(key)
|
43
|
+
def del(key, hkey = nil)
|
44
|
+
if !hkey.nil?
|
45
|
+
storage.hdel(proper_key("h:#{key}"), hkey)
|
41
46
|
else
|
42
|
-
storage.del
|
47
|
+
storage.del(proper_key("k:#{key}"))
|
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
|
-
|
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}"
|