loco-rails 3.0.6 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79191fae751caacf8c4dc17551a62cb5fae5de5d69307afde0014c9c276a2d32
4
- data.tar.gz: 6bcf8149cf78be74b639a054bf1b59cac8d0c098abca76e4a4738b66cda70fe1
3
+ metadata.gz: 14ddadb549243851cfae8f6260dbe08b6813392116f03b83d4618615598ec2d3
4
+ data.tar.gz: c5cdfc9d981ce63a5e8237cb794d7eb2a9d8435941070bba84f65f188e08e215
5
5
  SHA512:
6
- metadata.gz: 5094696a9904e3e8a3a4ee41236aed45f818aeb87f7caf951bac577cd3c21b3f7e6c67377a32e7c31d926a6bc61d9ff0965ec4c93f8baef90f2ec67c22c5dc55
7
- data.tar.gz: 5df1a26fb32cb187eb2136e4e2a2b5b554bdd2d1d9ff158d5d0f52a0e24cfbe780f6d87099320a1ea023972d8661c760e87fb101006f6749c73f64370946ae9d
6
+ metadata.gz: '0921bb8ffff692bede6999ae0dc2de20d1822c0ca3b5a8bac0aabcd50909a12369a6987da6b309356e4306dfd3891aea85adff8c418cce1eacabc4bd73348509'
7
+ data.tar.gz: f8d9d259ae99c421bcbdbf03df5fa1878ae6dd590eb835d6c432a6c6e91b103df5d5efbcdfe9daff6ae1d4fbb2bab1c193d3416b1e6213b7e134842d7f2dea48
@@ -4,58 +4,62 @@ module Loco
4
4
  class NotificationCenterChannel < ApplicationCable::Channel
5
5
  def subscribed
6
6
  return unless loco_permissions.is_a?(Array)
7
+
7
8
  stream_for_resources
8
9
  return if loco_permissions.compact.size > 1
10
+
9
11
  SenderJob.perform_later @uuid, loco: { start_ajax_polling: true }
10
12
  end
11
13
 
12
14
  def unsubscribed
13
15
  loco_permissions.each do |resource|
14
16
  next if resource.nil? || resource.is_a?(String)
17
+
15
18
  UuidJob.perform_later serialize_resource(resource), @uuid, 'del'
16
19
  end
17
20
  end
18
21
 
19
- def receive data
22
+ def receive(data)
20
23
  update_connections if data['loco'] && data['loco']['connection_check']
21
- NotificationCenter.new.received_signal permissions, data
24
+ NotificationCenter.new.received_message permissions, data
22
25
  end
23
26
 
24
27
  protected
25
28
 
26
- def stream_for_resources
27
- loco_permissions.compact.each do |resource|
28
- if resource.is_a? String
29
- @uuid = resource
30
- stream_for_resource resource
31
- SenderJob.perform_later @uuid, loco: { uuid: @uuid }
32
- else
33
- UuidJob.perform_later serialize_resource(resource), @uuid, 'add'
34
- stream_for_resource resource
35
- end
29
+ def stream_for_resources
30
+ loco_permissions.compact.each do |resource|
31
+ if resource.is_a? String
32
+ @uuid = resource
33
+ stream_for_resource resource
34
+ SenderJob.perform_later @uuid, loco: { uuid: @uuid }
35
+ else
36
+ UuidJob.perform_later serialize_resource(resource), @uuid, 'add'
37
+ stream_for_resource resource
36
38
  end
37
39
  end
40
+ end
38
41
 
39
- def stream_for_resource resource
40
- identifier = WsConnectionManager.new(resource).identifier
41
- stream_from "loco:notification_center:#{identifier}"
42
- end
42
+ def stream_for_resource(resource)
43
+ identifier = WsConnectionManager.new(resource).identifier
44
+ stream_from "loco:notification_center:#{identifier}"
45
+ end
43
46
 
44
- def permissions
45
- loco_permissions.compact.map do |o|
46
- [o.class.name.downcase.to_sym, o]
47
- end.to_h
47
+ def permissions
48
+ loco_permissions.compact.index_by do |o|
49
+ o.class.name.downcase.to_sym
48
50
  end
51
+ end
49
52
 
50
- def update_connections
51
- permissions.each do |key, val|
52
- next if key == :string
53
- UuidJob.perform_later serialize_resource(val), @uuid, 'update'
54
- end
55
- end
53
+ def update_connections
54
+ permissions.each do |key, val|
55
+ next if key == :string
56
56
 
57
- def serialize_resource resource
58
- { 'class' => resource.class.name, 'id' => resource.id }
57
+ UuidJob.perform_later serialize_resource(val), @uuid, 'update'
59
58
  end
59
+ end
60
+
61
+ def serialize_resource(resource)
62
+ { 'class' => resource.class.name, 'id' => resource.id }
63
+ end
60
64
  end
61
65
  end
@@ -16,43 +16,46 @@ module Loco
16
16
 
17
17
  private
18
18
 
19
- def fetch_notifications
20
- if params[:synced_at].blank?
21
- render json: [[], Time.current.iso8601(6)]
22
- return
23
- end
24
- fetcher = Notification::Fetcher.new notif_fetcher_args
25
- render json: [
26
- fetcher.formatted_notifications,
27
- fetcher.next_sync_time.iso8601(6)
28
- ]
19
+ def fetch_notifications
20
+ if params[:synced_at].blank?
21
+ render json: [[], Time.current.iso8601(6)]
22
+ return
29
23
  end
24
+ fetcher = Notification::Fetcher.new notif_fetcher_args
25
+ render json: [
26
+ fetcher.formatted_notifications,
27
+ fetcher.next_sync_time.iso8601(6)
28
+ ]
29
+ end
30
30
 
31
- def notif_fetcher_args
32
- {
33
- synced_at: params[:synced_at],
34
- permissions: permissions,
35
- recipient_token: params[:token]
36
- }
37
- end
31
+ def notif_fetcher_args
32
+ {
33
+ synced_at: params[:synced_at],
34
+ permissions: permissions,
35
+ recipient_token: params[:token]
36
+ }
37
+ end
38
38
 
39
- def permissions
40
- return [] unless defined? loco_permissions
41
- return loco_permissions if params[:uuid].blank?
42
- process_loco_permissions
43
- end
39
+ def permissions
40
+ return [] unless defined? loco_permissions
41
+ return loco_permissions if params[:uuid].blank?
44
42
 
45
- def process_loco_permissions
46
- resources_to_del = []
47
- resources_to_add = []
48
- loco_permissions.each do |resource|
49
- next if resource.nil?
50
- ws_conn_manager = WsConnectionManager.new resource
51
- next unless ws_conn_manager.connected?(params[:uuid])
52
- resources_to_del << resource
53
- resources_to_add << resource.class
54
- end
55
- loco_permissions - resources_to_del + resources_to_add.uniq
43
+ process_loco_permissions
44
+ end
45
+
46
+ def process_loco_permissions
47
+ resources_to_del = []
48
+ resources_to_add = []
49
+ loco_permissions.each do |resource|
50
+ next if resource.nil?
51
+
52
+ ws_conn_manager = WsConnectionManager.new resource
53
+ next unless ws_conn_manager.connected?(params[:uuid])
54
+
55
+ resources_to_del << resource
56
+ resources_to_add << resource.class
56
57
  end
58
+ loco_permissions - resources_to_del + resources_to_add.uniq
59
+ end
57
60
  end
58
61
  end
@@ -4,7 +4,7 @@ module Loco
4
4
  class SenderJob < ActiveJob::Base
5
5
  queue_as :loco
6
6
 
7
- def perform recipient, data
7
+ def perform(recipient, data)
8
8
  Sender.new(recipient, data).emit
9
9
  end
10
10
  end
@@ -4,9 +4,10 @@ module Loco
4
4
  class UuidJob < ActiveJob::Base
5
5
  queue_as :loco
6
6
 
7
- def perform serialized_resource, uuid, action
7
+ def perform(serialized_resource, uuid, action)
8
8
  ws_conn_manager = init_ws_conn_manager serialized_resource
9
9
  return unless ws_conn_manager
10
+
10
11
  case action
11
12
  when 'add'
12
13
  add ws_conn_manager, uuid
@@ -19,30 +20,32 @@ module Loco
19
20
 
20
21
  protected
21
22
 
22
- def add ws_conn_manager, uuid
23
- ws_conn_manager.add uuid
24
- WsConnectedResourcesManager.add ws_conn_manager.identifier
25
- end
23
+ def add(ws_conn_manager, uuid)
24
+ ws_conn_manager.add uuid
25
+ WsConnectedResourcesManager.add ws_conn_manager.identifier
26
+ end
26
27
 
27
- def del ws_conn_manager, uuid
28
- ws_conn_manager.del uuid
29
- return if ws_conn_manager.connected_uuids.any?
30
- WsConnectedResourcesManager.del ws_conn_manager.identifier
31
- end
28
+ def del(ws_conn_manager, uuid)
29
+ ws_conn_manager.del uuid
30
+ return if ws_conn_manager.connected_uuids.any?
32
31
 
33
- def update ws_conn_manager, uuid
34
- ws_conn_manager.update uuid
35
- WsConnectedResourcesManager.add ws_conn_manager.identifier
36
- end
32
+ WsConnectedResourcesManager.del ws_conn_manager.identifier
33
+ end
37
34
 
38
- def deserialize_resource hash
39
- hash['class'].constantize.find_by id: hash['id']
40
- end
35
+ def update(ws_conn_manager, uuid)
36
+ ws_conn_manager.update uuid
37
+ WsConnectedResourcesManager.add ws_conn_manager.identifier
38
+ end
41
39
 
42
- def init_ws_conn_manager serialized_resource
43
- resource = deserialize_resource serialized_resource
44
- return unless resource
45
- WsConnectionManager.new resource
46
- end
40
+ def deserialize_resource(hash)
41
+ hash['class'].constantize.find_by id: hash['id']
42
+ end
43
+
44
+ def init_ws_conn_manager(serialized_resource)
45
+ resource = deserialize_resource serialized_resource
46
+ return unless resource
47
+
48
+ WsConnectionManager.new resource
49
+ end
47
50
  end
48
51
  end
@@ -17,7 +17,7 @@ module Loco
17
17
  end
18
18
  end
19
19
 
20
- def obj= val
20
+ def obj=(val)
21
21
  if val.instance_of? Class
22
22
  self.obj_class = val.to_s
23
23
  else
@@ -27,9 +27,10 @@ module Loco
27
27
  end
28
28
  end
29
29
 
30
- def recipient= val
30
+ def recipient=(val)
31
31
  return if val.nil?
32
32
  return if val == :all
33
+
33
34
  if val.is_a? String
34
35
  self.recipient_token = val
35
36
  elsif val.instance_of? Class
@@ -40,10 +41,11 @@ module Loco
40
41
  end
41
42
  end
42
43
 
43
- def recipient opts = {}
44
+ def recipient(opts = {})
44
45
  return recipient_token if recipient_token
45
46
  return unless regular_recipient?
46
47
  return class_recipient unless recipient_id
48
+
47
49
  obj_recipient opts[:shallow]
48
50
  end
49
51
 
@@ -58,40 +60,42 @@ module Loco
58
60
 
59
61
  private
60
62
 
61
- def regular_recipient?
62
- recipient_class && recipient_id
63
- end
63
+ def regular_recipient?
64
+ recipient_class && recipient_id
65
+ end
64
66
 
65
- def class_recipient
66
- recipient_class.constantize
67
- end
67
+ def class_recipient
68
+ recipient_class.constantize
69
+ end
68
70
 
69
- def obj_recipient shallow = false
70
- if shallow
71
- recipient_class.constantize.new id: recipient_id
72
- else
73
- recipient_class.constantize.find recipient_id
74
- end
71
+ def obj_recipient(shallow = false)
72
+ if shallow
73
+ recipient_class.constantize.new id: recipient_id
74
+ else
75
+ recipient_class.constantize.find recipient_id
75
76
  end
77
+ end
76
78
 
77
- def set_event
78
- return if event.present?
79
- return if obj.instance_of? Class
80
- if obj.new_record?
81
- self.event = 'creating'
82
- else
83
- set_event_for_persisted_obj
84
- end
85
- end
79
+ def set_event
80
+ return if event.present?
81
+ return if obj.instance_of? Class
86
82
 
87
- def set_event_for_persisted_obj
88
- self.event = obj.created_at == obj.updated_at ? 'created' : 'updated'
83
+ if obj.new_record?
84
+ self.event = 'creating'
85
+ else
86
+ set_event_for_persisted_obj
89
87
  end
88
+ end
90
89
 
91
- def set_data
92
- self.data ||= {}
93
- return if obj.nil?
94
- self.data.merge!(id: obj.id)
95
- end
90
+ def set_event_for_persisted_obj
91
+ self.event = obj.created_at == obj.updated_at ? 'created' : 'updated'
92
+ end
93
+
94
+ def set_data
95
+ self.data ||= {}
96
+ return if obj.nil?
97
+
98
+ self.data.merge!(id: obj.id)
99
+ end
96
100
  end
97
101
  end
@@ -32,56 +32,58 @@ module Loco
32
32
 
33
33
  private
34
34
 
35
- def sync_time
36
- Time.zone.parse @synced_at
37
- end
35
+ def sync_time
36
+ Time.zone.parse @synced_at
37
+ end
38
38
 
39
- def default_scope
40
- Notification.order('created_at ASC')
41
- .where('created_at > ?', sync_time)
42
- end
39
+ def default_scope
40
+ Notification.order('created_at ASC')
41
+ .where('created_at > ?', sync_time)
42
+ end
43
43
 
44
- # OPTIMIZE: one query
45
- def notifications
46
- return @notifications if @notifications
47
- notifications = notifications_for_all
48
- notifications += notifications_behind_permissions
49
- notifications += notifications_behind_token if @recipient_token
50
- @notifications = notifications.sort_by(&:created_at)[0, max_size]
51
- end
44
+ # OPTIMIZE: one query
45
+ def notifications
46
+ return @notifications if @notifications
52
47
 
53
- def notifications_for_all
54
- default_scope.where(
55
- recipient_class: nil,
56
- recipient_id: nil,
57
- recipient_token: nil
58
- ).first max_size
59
- end
48
+ notifications = notifications_for_all
49
+ notifications += notifications_behind_permissions
50
+ notifications += notifications_behind_token if @recipient_token
51
+ @notifications = notifications.sort_by(&:created_at)[0, max_size]
52
+ end
60
53
 
61
- def notifications_behind_permissions
62
- notifications = []
63
- @permissions.each do |resource|
64
- next unless resource
65
- notifications += notification_for_resource resource
66
- end
67
- notifications
68
- end
54
+ def notifications_for_all
55
+ default_scope.where(
56
+ recipient_class: nil,
57
+ recipient_id: nil,
58
+ recipient_token: nil
59
+ ).first max_size
60
+ end
69
61
 
70
- def notifications_behind_token
71
- default_scope.where(recipient_token: @recipient_token).first max_size
62
+ def notifications_behind_permissions
63
+ notifications = []
64
+ @permissions.each do |resource|
65
+ next unless resource
66
+
67
+ notifications += notification_for_resource resource
72
68
  end
69
+ notifications
70
+ end
73
71
 
74
- def notification_for_resource resource
75
- if resource.instance_of? Class
76
- sql = 'recipient_class = ? AND recipient_id IS NULL'
77
- return default_scope.where(sql, resource.to_s).first max_size
78
- end
79
- klass = resource.class.name
80
- cond1 = '(recipient_class = ? AND recipient_id = ?)'
81
- cond2 = '(recipient_class = ? AND recipient_id IS NULL)'
82
- sql = "#{cond1} OR #{cond2}"
83
- default_scope.where(sql, klass, resource.id, klass).first max_size
72
+ def notifications_behind_token
73
+ default_scope.where(recipient_token: @recipient_token).first max_size
74
+ end
75
+
76
+ def notification_for_resource(resource)
77
+ if resource.instance_of? Class
78
+ sql = 'recipient_class = ? AND recipient_id IS NULL'
79
+ return default_scope.where(sql, resource.to_s).first max_size
84
80
  end
81
+ klass = resource.class.name
82
+ cond1 = '(recipient_class = ? AND recipient_id = ?)'
83
+ cond2 = '(recipient_class = ? AND recipient_id IS NULL)'
84
+ sql = "#{cond1} OR #{cond2}"
85
+ default_scope.where(sql, klass, resource.id, klass).first max_size
86
+ end
85
87
  end
86
88
  end
87
89
  end
@@ -5,30 +5,21 @@ module Loco
5
5
  source_root File.expand_path('templates', __dir__)
6
6
 
7
7
  def routes
8
- file_path = Rails.root.join 'config', 'routes.rb'
8
+ file_path = Rails.root.join 'config/routes.rb'
9
9
  line = %( mount Loco::Engine => '/notification-center'\n\n)
10
10
  str = "Rails.application.routes.draw do\n"
11
11
  inject_into_file file_path, line, after: str
12
12
  end
13
13
 
14
14
  def application_controller
15
- file_path = Rails.root.join(
16
- 'app',
17
- 'controllers',
18
- 'application_controller.rb'
19
- )
15
+ file_path = Rails.root.join 'app/controllers/application_controller.rb'
20
16
  data = File.read find_in_source_paths('application_controller.rb')
21
17
  after_line = "class ApplicationController < ActionController::Base\n"
22
18
  inject_into_file file_path, data, after: after_line
23
19
  end
24
20
 
25
21
  def connection
26
- file_path = Rails.root.join(
27
- 'app',
28
- 'channels',
29
- 'application_cable',
30
- 'connection.rb'
31
- )
22
+ file_path = Rails.root.join 'app/channels/application_cable/connection.rb'
32
23
  data = File.read find_in_source_paths('connection.rb')
33
24
  inject_into_class file_path, 'Connection', data
34
25
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Loco::Config.configure(
4
- silence_logger: false, # false by default
5
- notifications_size: 100, # 100 by default
6
- app_name: "loco_#{Rails.env}" # your app's name (required for namespacing)
7
- )
3
+ Loco.configure do |c|
4
+ c.silence_logger = false # false by default
5
+ c.notifications_size = 100 # 100 by default
6
+ c.app_name = "loco_#{Rails.env}" # your app's name (required for namespacing)
7
+ end
@@ -1,5 +1,5 @@
1
1
  Description:
2
- Creates a notification center where you can receive signals sent by JS clients through WebSockets.
2
+ Creates a notification center where you can receive messages sent by JS clients through WebSockets.
3
3
 
4
4
  Example:
5
5
  rails generate loco:notification_center
@@ -4,8 +4,8 @@ module Loco
4
4
  class NotificationCenter
5
5
  include Emitter
6
6
 
7
- def received_signal permissions, data
8
- # handle signals here
7
+ def received_message(permissions, data)
8
+ # handle messages here
9
9
  end
10
10
  end
11
11
  end
@@ -14,4 +14,12 @@ require 'loco/ws_connected_resources_manager'
14
14
  require 'loco/ws_connection_storage'
15
15
 
16
16
  module Loco
17
+ module_function
18
+
19
+ def configure
20
+ Config::CONFIGURATION.new.tap do |config|
21
+ yield config
22
+ Config.configure config
23
+ end
24
+ end
17
25
  end
@@ -4,7 +4,7 @@ module Loco
4
4
  class Broadcaster
5
5
  attr_reader :obj, :event, :recipients, :data, :notifications
6
6
 
7
- def initialize obj, event = nil, opts = {}
7
+ def initialize(obj, event = nil, opts = {})
8
8
  recipient_key = opts[:for] ? :for : :to
9
9
  @obj = obj
10
10
  @event = event
@@ -15,15 +15,6 @@ module Loco
15
15
  @conn_res_manager = WsConnectedResourcesManager.new @recipients.compact
16
16
  end
17
17
 
18
- def signals
19
- notifications
20
- end
21
-
22
- def prepare
23
- init_notifications if notifications.empty?
24
- prepare_notifications
25
- end
26
-
27
18
  def emit
28
19
  init_notifications if notifications.empty?
29
20
  send_notifications
@@ -36,77 +27,76 @@ module Loco
36
27
 
37
28
  private
38
29
 
39
- def init_notifications
40
- recipients.each do |recipient|
41
- @notifications << Notification.new(
42
- obj: obj,
43
- event: event,
44
- recipient: recipient,
45
- data: data
46
- )
47
- end
30
+ def init_notifications
31
+ recipients.each do |recipient|
32
+ @notifications << Notification.new(
33
+ obj: obj,
34
+ event: event,
35
+ recipient: recipient,
36
+ data: data
37
+ )
48
38
  end
39
+ end
49
40
 
50
- def prepare_notifications
51
- notifications.each(&:prepare)
52
- end
41
+ def send_notifications
42
+ notifications.each do |notification|
43
+ notification.save!
44
+ next if notification.recipient_id.nil?
53
45
 
54
- def send_notifications
55
- notifications.each do |notification|
56
- notification.save!
57
- next if notification.recipient_id.nil?
58
- shallow_recipient = notification.recipient shallow: true
59
- next unless @conn_res_manager.connected? shallow_recipient
60
- send_via_ws notification
61
- end
62
- end
46
+ shallow_recipient = notification.recipient shallow: true
47
+ next unless @conn_res_manager.connected? shallow_recipient
63
48
 
64
- def send_via_ws notification
65
- recipient = notification.recipient shallow: true
66
- data = { loco: { notification: notification.compact } }
67
- SenderJob.perform_later recipient, data
68
- @sent_via_ws += 1
49
+ send_via_ws notification
69
50
  end
51
+ end
70
52
 
71
- def notify_about_xhr_notifications?
72
- @sent_via_ws < notifications.size
73
- end
53
+ def send_via_ws(notification)
54
+ recipient = notification.recipient shallow: true
55
+ data = { loco: { notification: notification.compact } }
56
+ SenderJob.perform_later recipient, data
57
+ @sent_via_ws += 1
58
+ end
59
+
60
+ def notify_about_xhr_notifications?
61
+ @sent_via_ws < notifications.size
62
+ end
63
+
64
+ def notify_about_xhr_notifications
65
+ uuids = []
66
+ fetch_identifiers.each do |ident|
67
+ Loco::WsConnectionManager.new(ident).connected_uuids.each do |uuid|
68
+ next if uuids.include? uuid
74
69
 
75
- def notify_about_xhr_notifications
76
- uuids = []
77
- fetch_identifiers.each do |ident|
78
- Loco::WsConnectionManager.new(ident).connected_uuids.each do |uuid|
79
- next if uuids.include? uuid
80
- uuids << uuid
81
- SenderJob.perform_later uuid, loco: { xhr_notifications: true }
82
- end
70
+ uuids << uuid
71
+ SenderJob.perform_later uuid, loco: { xhr_notifications: true }
83
72
  end
84
73
  end
74
+ end
85
75
 
86
- def set_sync_time_via_ws
87
- sync_time = notifications.last.created_at.iso8601(6)
88
- notifications.each do |notification|
89
- recipient = notification.recipient shallow: true
90
- SenderJob.perform_later recipient, loco: { sync_time: sync_time }
91
- end
76
+ def set_sync_time_via_ws
77
+ sync_time = notifications.last.created_at.iso8601(6)
78
+ notifications.each do |notification|
79
+ recipient = notification.recipient shallow: true
80
+ SenderJob.perform_later recipient, loco: { sync_time: sync_time }
92
81
  end
82
+ end
93
83
 
94
- def notifications_recipients
95
- notifications.map { |n| n.recipient shallow: true }.map do |o|
96
- o.instance_of?(Class) ? o.to_s.downcase : nil
97
- end
84
+ def notifications_recipients
85
+ notifications.map { |n| n.recipient shallow: true }.map do |o|
86
+ o.instance_of?(Class) ? o.to_s.downcase : nil
98
87
  end
88
+ end
99
89
 
100
- def fetch_identifiers
101
- recipients = notifications_recipients
102
- uniq_recipients = recipients.compact.uniq
103
- Loco::WsConnectedResourcesManager.identifiers.find_all do |str|
104
- if recipients.include? nil
105
- true
106
- else
107
- uniq_recipients.include? str.split(':').first
108
- end
90
+ def fetch_identifiers
91
+ recipients = notifications_recipients
92
+ uniq_recipients = recipients.compact.uniq
93
+ Loco::WsConnectedResourcesManager.identifiers.find_all do |str|
94
+ if recipients.include? nil
95
+ true
96
+ else
97
+ uniq_recipients.include? str.split(':').first
109
98
  end
110
99
  end
100
+ end
111
101
  end
112
102
  end
@@ -2,28 +2,29 @@
2
2
 
3
3
  module Loco
4
4
  class Config
5
+ CONFIGURATION = Struct.new :silence_logger, :notifications_size, :app_name, :redis_instance
6
+
5
7
  cattr_accessor(:silence_logger) { false }
6
8
  cattr_accessor(:notifications_size) { 100 }
7
9
  cattr_accessor(:app_name) { 'loco' }
8
10
  cattr_accessor(:redis_instance) { nil }
9
11
 
10
- def self.configure opts = {}
11
- self.silence_logger = opts[:silence_logger] if opts[:silence_logger]
12
- if opts[:notifications_size]
13
- self.notifications_size = opts[:notifications_size]
14
- end
15
- self.app_name = opts[:app_name] if opts[:app_name]
16
- configure_redis opts[:redis_instance]
12
+ def self.configure(config)
13
+ self.silence_logger = config.silence_logger if config.silence_logger
14
+ self.notifications_size = config.notifications_size if config.notifications_size
15
+ self.app_name = config.app_name if config.app_name
16
+ configure_redis config.redis_instance
17
17
  ensure
18
18
  true
19
19
  end
20
20
 
21
- def self.configure_redis redis_instance
21
+ def self.configure_redis(redis_instance)
22
22
  if redis_instance
23
23
  self.redis_instance = redis_instance
24
24
  return
25
25
  end
26
26
  return unless defined? Redis
27
+
27
28
  Redis.current.get 'random_redis_key'
28
29
  self.redis_instance = Redis.current
29
30
  rescue Redis::CannotConnectError
@@ -2,25 +2,26 @@
2
2
 
3
3
  module Loco
4
4
  module Emitter
5
- def emit obj, event = nil, opts = {}
5
+ def emit(obj, event = nil, opts = {})
6
6
  Broadcaster.new(obj, event, opts).emit
7
7
  end
8
8
 
9
- def emit_to recipient, data
9
+ def emit_to(recipient, data)
10
10
  Sender.new(recipient, data).emit
11
11
  end
12
12
 
13
- def add_hub name, members = []
13
+ def add_hub(name, members = [])
14
14
  Hub.new(name, members).save
15
15
  end
16
16
 
17
- def get_hub name
17
+ def get_hub(name)
18
18
  Hub.get name
19
19
  end
20
20
 
21
- def del_hub name
21
+ def del_hub(name)
22
22
  hub = Hub.get name
23
23
  return false if hub.nil?
24
+
24
25
  hub.destroy
25
26
  end
26
27
  end
@@ -6,15 +6,16 @@ module Loco
6
6
 
7
7
  attr_reader :raw_members
8
8
 
9
- def initialize name, members = []
9
+ def initialize(name, members = [])
10
10
  @name = "#{PREFIX}#{name}"
11
11
  @raw_members = members.map { |m| serialize m }
12
12
  end
13
13
 
14
14
  class << self
15
- def get name
15
+ def get(name)
16
16
  hub = WsConnectionStorage.current.get "#{PREFIX}#{name}"
17
17
  return nil if hub.blank?
18
+
18
19
  new name, JSON.parse(hub)
19
20
  end
20
21
  end
@@ -23,17 +24,19 @@ module Loco
23
24
  @name.split(PREFIX).last
24
25
  end
25
26
 
26
- def add_member member
27
+ def add_member(member)
27
28
  serialized = serialize member
28
29
  return raw_members if raw_members.include? serialized
30
+
29
31
  raw_members << serialized
30
32
  save
31
33
  raw_members
32
34
  end
33
35
 
34
- def del_member member
36
+ def del_member(member)
35
37
  serialized = serialize member
36
38
  return nil unless raw_members.include? serialized
39
+
37
40
  raw_members.delete serialized
38
41
  save
39
42
  serialized
@@ -49,7 +52,7 @@ module Loco
49
52
  self
50
53
  end
51
54
 
52
- def include? resource
55
+ def include?(resource)
53
56
  raw_members.include? serialize(resource)
54
57
  end
55
58
 
@@ -62,8 +65,8 @@ module Loco
62
65
 
63
66
  private
64
67
 
65
- def serialize member
66
- WsConnectionManager.new(member).identifier
67
- end
68
+ def serialize(member)
69
+ WsConnectionManager.new(member).identifier
70
+ end
68
71
  end
69
72
  end
@@ -2,35 +2,43 @@
2
2
 
3
3
  module Loco
4
4
  class Sender
5
- def initialize recipient, data = {}
5
+ def initialize(recipient, data = {})
6
6
  @recipients = [*recipient]
7
7
  @data = data
8
8
  end
9
9
 
10
10
  def emit
11
11
  uuids.each do |uuid|
12
- NotificationCenterChannel.broadcast_to uuid, @data
12
+ NotificationCenterChannel.broadcast_to(uuid, payload)
13
13
  end
14
+ @data[:loco][:idempotency_key]
14
15
  end
15
16
 
16
17
  private
17
18
 
18
- def uuids
19
- @recipients.map do |r|
20
- if r.is_a? String
21
- r
22
- elsif r.is_a? Hub
23
- recipients_from_hub r
24
- else
25
- WsConnectionManager.new(r).connected_uuids
26
- end
27
- end.flatten.uniq
28
- end
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
29
+ end
29
30
 
30
- def recipients_from_hub hub
31
- hub.raw_members.map do |m|
32
- WsConnectionManager.new(m).connected_uuids
33
- end.flatten.uniq
34
- end
31
+ def recipients_from_hub(hub)
32
+ hub.raw_members.map do |m|
33
+ WsConnectionManager.new(m).connected_uuids
34
+ end.flatten.uniq
35
+ end
36
+
37
+ def payload
38
+ @data[:loco] ||= {}
39
+ @data[:loco][:idempotency_key] ||= @data[:idempotency_key] || SecureRandom.hex
40
+ @data.delete(:idempotency_key)
41
+ @data
42
+ end
35
43
  end
36
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loco
4
- VERSION = '3.0.6'
4
+ VERSION = '4.0.0'
5
5
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Loco
4
4
  class WsConnectedResourcesManager
5
- def initialize resources
5
+ def initialize(resources)
6
6
  @resources = resources
7
7
  @connected_resources = nil
8
8
  end
@@ -11,19 +11,22 @@ module Loco
11
11
  def identifiers
12
12
  val = WsConnectionStorage.current.get key
13
13
  return [] if val.blank?
14
+
14
15
  JSON.parse val
15
16
  end
16
17
 
17
- def add identifier
18
+ def add(identifier)
18
19
  ids = identifiers
19
20
  return if ids.include? identifier
21
+
20
22
  ids << identifier
21
23
  WsConnectionStorage.current.set key, ids.to_json
22
24
  end
23
25
 
24
- def del identifier
26
+ def del(identifier)
25
27
  ids = identifiers
26
28
  return unless ids.include? identifier
29
+
27
30
  ids.delete identifier
28
31
  WsConnectionStorage.current.set key, ids.to_json
29
32
  end
@@ -35,14 +38,16 @@ module Loco
35
38
 
36
39
  def connected_resources
37
40
  return @connected_resources if @connected_resources
41
+
38
42
  @resources.each do |resource|
39
43
  next if WsConnectionManager.new(resource).connected_uuids.empty?
44
+
40
45
  add resource
41
46
  end
42
47
  @connected_resources || []
43
48
  end
44
49
 
45
- def connected? resource
50
+ def connected?(resource)
46
51
  connected_resources.map do |res|
47
52
  WsConnectionManager.new(res).identifier
48
53
  end.include? WsConnectionManager.new(resource).identifier
@@ -50,10 +55,10 @@ module Loco
50
55
 
51
56
  private
52
57
 
53
- def add resource
54
- @connected_resources ||= []
55
- @connected_resources << resource
56
- @connected_resources.uniq!
57
- end
58
+ def add(resource)
59
+ @connected_resources ||= []
60
+ @connected_resources << resource
61
+ @connected_resources.uniq!
62
+ end
58
63
  end
59
64
  end
@@ -2,16 +2,17 @@
2
2
 
3
3
  module Loco
4
4
  class WsConnectionManager
5
- def initialize resource
5
+ def initialize(resource)
6
6
  @resource = resource
7
7
  end
8
8
 
9
9
  def identifier
10
10
  return @resource if @resource.is_a?(String)
11
+
11
12
  "#{@resource.class.name.downcase}:#{@resource.id}"
12
13
  end
13
14
 
14
- def connected? uuid
15
+ def connected?(uuid)
15
16
  connected_uuids.include? uuid
16
17
  end
17
18
 
@@ -19,17 +20,17 @@ module Loco
19
20
  data.find_all { |_, v| v.is_a? String }.to_h.keys
20
21
  end
21
22
 
22
- def add uuid
23
+ def add(uuid)
23
24
  update uuid
24
25
  check_connections
25
26
  end
26
27
 
27
- def del uuid
28
+ def del(uuid)
28
29
  save(data.tap { |h| h.delete uuid })
29
30
  check_connections
30
31
  end
31
32
 
32
- def update uuid
33
+ def update(uuid)
33
34
  save(data.tap { |h| h[uuid] = current_time })
34
35
  end
35
36
 
@@ -39,51 +40,54 @@ module Loco
39
40
 
40
41
  protected
41
42
 
42
- def data
43
- serialized_uuids = WsConnectionStorage.current.get identifier
44
- return {} if serialized_uuids.blank?
45
- JSON.parse serialized_uuids
46
- end
43
+ def data
44
+ serialized_uuids = WsConnectionStorage.current.get identifier
45
+ return {} if serialized_uuids.blank?
47
46
 
48
- def uuids
49
- data.keys
50
- end
47
+ JSON.parse serialized_uuids
48
+ end
51
49
 
52
- def save hash
53
- WsConnectionStorage.current.set identifier, hash.to_json
54
- end
50
+ def uuids
51
+ data.keys
52
+ end
55
53
 
56
- def check_connections
57
- hash = data.to_a.map do |arr|
58
- uuid, val = check_connection arr.first, arr.last
59
- [uuid, val]
60
- end.to_h.compact
61
- save hash
62
- end
54
+ def save(hash)
55
+ WsConnectionStorage.current.set identifier, hash.to_json
56
+ end
63
57
 
64
- def check_connection uuid, val
65
- case val
66
- when String
67
- val = check_connection_str uuid, val
68
- when Hash
69
- uuid, val = check_connection_hash uuid, val
70
- end
58
+ def check_connections
59
+ hash = data.to_a.map do |arr|
60
+ uuid, val = check_connection arr.first, arr.last
71
61
  [uuid, val]
72
- end
62
+ end.to_h.compact
63
+ save hash
64
+ end
73
65
 
74
- def check_connection_str uuid, val
75
- return val if Time.zone.parse(val) >= 3.minutes.ago
76
- SenderJob.perform_later uuid, loco: { connection_check: true }
77
- { 'check' => current_time }
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
78
72
  end
73
+ [uuid, val]
74
+ end
79
75
 
80
- def check_connection_hash uuid, val
81
- return [uuid, val] if Time.zone.parse(val['check']) >= 5.seconds.ago
82
- [nil, nil]
83
- end
76
+ def check_connection_str(uuid, val)
77
+ return val if Time.zone.parse(val) >= 3.minutes.ago
84
78
 
85
- def current_time
86
- Time.current.iso8601(6)
87
- end
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)
91
+ end
88
92
  end
89
93
  end
@@ -16,7 +16,7 @@ module Loco
16
16
  @storage = Config.redis_instance || {}
17
17
  end
18
18
 
19
- def get key
19
+ def get(key)
20
20
  case @storage
21
21
  when Hash
22
22
  storage[proper_key(key)]
@@ -25,7 +25,7 @@ module Loco
25
25
  end
26
26
  end
27
27
 
28
- def set key, val
28
+ def set(key, val)
29
29
  case @storage
30
30
  when Hash
31
31
  storage[proper_key(key)] = val
@@ -34,7 +34,7 @@ module Loco
34
34
  end
35
35
  end
36
36
 
37
- def del key
37
+ def del(key)
38
38
  case @storage
39
39
  when Hash
40
40
  storage.delete proper_key(key)
@@ -45,8 +45,8 @@ module Loco
45
45
 
46
46
  protected
47
47
 
48
- def proper_key key
49
- "#{Config.app_name}:#{key}"
50
- end
48
+ def proper_key(key)
49
+ "#{Config.app_name}:#{key}"
50
+ end
51
51
  end
52
52
  end
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: 3.0.6
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zbigniew Humeniuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-15 00:00:00.000000000 Z
11
+ date: 2020-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: loco-rails-core
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.7.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: jbuilder
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.10.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.10.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: listen
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +120,14 @@ dependencies:
106
120
  requirements:
107
121
  - - "~>"
108
122
  - !ruby/object:Gem::Version
109
- version: 0.5.2
123
+ version: 0.5.3
110
124
  type: :development
111
125
  prerelease: false
112
126
  version_requirements: !ruby/object:Gem::Requirement
113
127
  requirements:
114
128
  - - "~>"
115
129
  - !ruby/object:Gem::Version
116
- version: 0.5.2
130
+ version: 0.5.3
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: puma
119
133
  requirement: !ruby/object:Gem::Requirement
@@ -184,6 +198,34 @@ dependencies:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
200
  version: '3.142'
201
+ - !ruby/object:Gem::Dependency
202
+ name: source_maps_fixer
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ - !ruby/object:Gem::Dependency
216
+ name: will_paginate
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: 3.1.8
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: 3.1.8
187
229
  description: Rails is awesome, but modern web needs Loco-motive.
188
230
  email:
189
231
  - hello@artofcode.co
@@ -245,7 +287,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
287
  - !ruby/object:Gem::Version
246
288
  version: '0'
247
289
  requirements: []
248
- rubygems_version: 3.0.3
290
+ rubygems_version: 3.1.2
249
291
  signing_key:
250
292
  specification_version: 4
251
293
  summary: Framework on top of Rails.