hyper-operation 1.0.alpha1.2 → 1.0.alpha1.7
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/.gitignore +4 -0
- data/.travis.yml +1 -0
- data/hyper-operation.gemspec +6 -4
- data/lib/hyper-operation.rb +4 -1
- data/lib/hyper-operation/api.rb +6 -2
- data/lib/hyper-operation/async_sleep.rb +23 -0
- data/lib/hyper-operation/exception.rb +29 -3
- data/lib/hyper-operation/promise.rb +32 -2
- data/lib/hyper-operation/railway/dispatcher.rb +0 -1
- data/lib/hyper-operation/railway/run.rb +57 -48
- data/lib/hyper-operation/railway/validations.rb +9 -2
- data/lib/hyper-operation/server_op.rb +31 -9
- data/lib/hyper-operation/transport/client_drivers.rb +45 -11
- data/lib/hyper-operation/transport/connection.rb +58 -136
- data/lib/hyper-operation/transport/connection_adapter/active_record.rb +113 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/auto_create.rb +26 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/connection.rb +47 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/queued_message.rb +42 -0
- data/lib/hyper-operation/transport/connection_adapter/redis.rb +94 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/connection.rb +85 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/queued_message.rb +34 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/redis_record.rb +158 -0
- data/lib/hyper-operation/transport/hyperstack.rb +15 -2
- data/lib/hyper-operation/transport/hyperstack_controller.rb +6 -2
- data/lib/hyper-operation/transport/policy.rb +16 -26
- data/lib/hyper-operation/transport/policy_diagnostics.rb +106 -0
- data/lib/hyper-operation/version.rb +1 -1
- metadata +79 -38
- data/Gemfile.lock +0 -385
- data/lib/hyper-operation/delay_and_interval.rb +0 -9
@@ -13,14 +13,18 @@ module Hyperstack
|
|
13
13
|
hash = serialize_params(hash)
|
14
14
|
Hyperstack::HTTP.post(
|
15
15
|
"#{`window.HyperstackEnginePath`}/execute_remote",
|
16
|
-
payload: {
|
17
|
-
headers:
|
16
|
+
payload: {hyperstack_secured_json: {operation: name, params: hash}.to_json},
|
17
|
+
headers: headers.merge('X-CSRF-Token' => Hyperstack::ClientDrivers.opts[:form_authenticity_token])
|
18
18
|
)
|
19
19
|
.then do |response|
|
20
20
|
deserialize_response response.json[:response]
|
21
21
|
end
|
22
22
|
.fail do |response|
|
23
|
-
|
23
|
+
begin
|
24
|
+
const_get(response.json[:error_class]).new(response.json[:error])
|
25
|
+
rescue
|
26
|
+
Exception.new response.json[:error]
|
27
|
+
end
|
24
28
|
end
|
25
29
|
end
|
26
30
|
elsif on_opal_server?
|
@@ -74,7 +78,7 @@ module Hyperstack
|
|
74
78
|
if _Railway.params_wrapper.method_defined?(:controller)
|
75
79
|
params[:controller] = controller
|
76
80
|
elsif !_Railway.params_wrapper.method_defined?(security_param)
|
77
|
-
raise AccessViolation
|
81
|
+
raise AccessViolation.new(:remote_access_not_allowed)
|
78
82
|
end
|
79
83
|
run(deserialize_params(params))
|
80
84
|
.then { |r| return { json: { response: serialize_response(r) } } }
|
@@ -84,13 +88,27 @@ module Hyperstack
|
|
84
88
|
handle_exception(e, operation, params)
|
85
89
|
end
|
86
90
|
|
91
|
+
def status(e)
|
92
|
+
if e.is_a? AccessViolation
|
93
|
+
403
|
94
|
+
elsif e.is_a? Operation::ValidationException
|
95
|
+
400
|
96
|
+
else
|
97
|
+
500
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
87
101
|
def handle_exception(e, operation, params)
|
88
|
-
if
|
89
|
-
params.
|
90
|
-
|
91
|
-
|
102
|
+
if e.respond_to? :__hyperstack_on_error
|
103
|
+
params = params.to_h
|
104
|
+
message = []
|
105
|
+
message << Pastel.new.red("HYPERSTACK ERROR during #{operation} #{e.inspect}")
|
106
|
+
params.each { |param, value| message << " #{param} => #{value.inspect.truncate(120, separator: '...')}" }
|
107
|
+
message << "\n#{e.details}" if e.respond_to? :details
|
108
|
+
e.__hyperstack_on_error(operation, params, message.join("\n"))
|
92
109
|
end
|
93
|
-
|
110
|
+
|
111
|
+
{ json: { error_class: e.class.to_s, error: e}, status: status(e) }
|
94
112
|
end
|
95
113
|
|
96
114
|
|
@@ -111,6 +129,10 @@ module Hyperstack
|
|
111
129
|
promise.reject e
|
112
130
|
end
|
113
131
|
|
132
|
+
def headers
|
133
|
+
{}
|
134
|
+
end
|
135
|
+
|
114
136
|
def serialize_params(hash)
|
115
137
|
hash
|
116
138
|
end
|
@@ -6,6 +6,10 @@ module Hyperstack
|
|
6
6
|
# We use ERB to determine the configuration and implement the appropriate
|
7
7
|
# client interface to sync_change or sync_destroy
|
8
8
|
|
9
|
+
def self.anti_csrf_token
|
10
|
+
ClientDrivers.opts[:form_authenticity_token]
|
11
|
+
end
|
12
|
+
|
9
13
|
class Application
|
10
14
|
extend Component::IsomorphicHelpers::ClassMethods
|
11
15
|
|
@@ -31,16 +35,35 @@ module Hyperstack
|
|
31
35
|
|
32
36
|
|
33
37
|
if RUBY_ENGINE == 'opal'
|
38
|
+
# Patch in a dummy copy of Model.load in case we are not using models
|
39
|
+
# this will be defined properly by hyper-model
|
40
|
+
module Model
|
41
|
+
def self.load
|
42
|
+
Promise.new.tap { |promise| promise.resolve(yield) }
|
43
|
+
end unless respond_to?(:load)
|
44
|
+
end
|
45
|
+
|
34
46
|
def self.connect(*channels)
|
35
47
|
channels.each do |channel|
|
36
48
|
if channel.is_a? Class
|
37
49
|
IncomingBroadcast.connect_to(channel.name)
|
38
50
|
elsif channel.is_a?(String) || channel.is_a?(Array)
|
39
51
|
IncomingBroadcast.connect_to(*channel)
|
40
|
-
elsif channel.id
|
41
|
-
|
52
|
+
elsif channel.respond_to?(:id)
|
53
|
+
Hyperstack::Model.load do
|
54
|
+
channel.id
|
55
|
+
end.then do |id|
|
56
|
+
raise "Hyperstack.connect cannot connect to #{channel.inspect}. "\
|
57
|
+
"The id is nil. This can be caused by connecting to a model "\
|
58
|
+
"that is not saved, or that does not exist." unless id
|
59
|
+
IncomingBroadcast.connect_to(channel.class.name, id)
|
60
|
+
end
|
42
61
|
else
|
43
|
-
raise "cannot connect to
|
62
|
+
raise "Hyperstack.connect cannot connect to #{channel.inspect}.\n"\
|
63
|
+
"Channels must be either a class, or a class name,\n"\
|
64
|
+
"a string in the form 'ClassName-id',\n"\
|
65
|
+
"an array in the form [class, id] or [class-name, id],\n"\
|
66
|
+
"or an object that responds to the id method with a non-nil value"
|
44
67
|
end
|
45
68
|
end
|
46
69
|
end
|
@@ -61,19 +84,22 @@ module Hyperstack
|
|
61
84
|
|
62
85
|
def self.add_connection(channel_name, id = nil)
|
63
86
|
channel_string = "#{channel_name}#{'-'+id.to_s if id}"
|
87
|
+
return if open_channels.include? channel_string
|
64
88
|
open_channels << channel_string
|
65
89
|
channel_string
|
66
90
|
end
|
67
91
|
|
68
92
|
def self.connect_to(channel_name, id = nil)
|
69
93
|
channel_string = add_connection(channel_name, id)
|
94
|
+
return unless channel_string # already connected!
|
70
95
|
if ClientDrivers.opts[:transport] == :pusher
|
71
96
|
channel = "#{ClientDrivers.opts[:channel]}-#{channel_string}"
|
72
97
|
%x{
|
73
98
|
var channel = #{ClientDrivers.opts[:pusher_api]}.subscribe(#{channel.gsub('::', '==')});
|
74
99
|
channel.bind('dispatch', #{ClientDrivers.opts[:dispatch]})
|
75
|
-
channel.bind('pusher:subscription_succeeded', #{
|
100
|
+
channel.bind('pusher:subscription_succeeded', #{->(*) { ClientDrivers.get_queued_data("connect-to-transport", channel_string)}})
|
76
101
|
}
|
102
|
+
@pusher_dispatcher_registered = true
|
77
103
|
elsif ClientDrivers.opts[:transport] == :action_cable
|
78
104
|
channel = "#{ClientDrivers.opts[:channel]}-#{channel_string}"
|
79
105
|
Hyperstack::HTTP.post(ClientDrivers.polling_path('action-cable-auth', channel), headers: { 'X-CSRF-Token' => ClientDrivers.opts[:form_authenticity_token] }).then do |response|
|
@@ -143,7 +169,7 @@ module Hyperstack
|
|
143
169
|
config_hash = {
|
144
170
|
transport: Hyperstack.transport,
|
145
171
|
id: id,
|
146
|
-
acting_user_id: (controller.acting_user && controller.acting_user.id),
|
172
|
+
acting_user_id: (controller.acting_user.respond_to?(:id) && controller.acting_user.id),
|
147
173
|
env: ::Rails.env,
|
148
174
|
client_logging: Hyperstack.client_logging,
|
149
175
|
pusher_fake_js: pusher_fake_js,
|
@@ -159,12 +185,17 @@ module Hyperstack
|
|
159
185
|
# not sure why the second check is needed. It happens in the test app
|
160
186
|
route.app == Hyperstack::Engine or (route.app.respond_to?(:app) and route.app.app == Hyperstack::Engine)
|
161
187
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
188
|
+
if path
|
189
|
+
path = path.path.spec
|
190
|
+
"<script type='text/javascript'>\n"\
|
191
|
+
"window.HyperstackEnginePath = '#{path}';\n"\
|
192
|
+
"window.HyperstackOpts = #{config_hash.to_json}\n"\
|
193
|
+
"</script>\n"
|
194
|
+
else
|
195
|
+
"<script type='text/javascript'>\n"\
|
196
|
+
"window.HyperstackOpts = #{config_hash.to_json}\n"\
|
197
|
+
"</script>\n"
|
198
|
+
end
|
168
199
|
end if RUBY_ENGINE != 'opal'
|
169
200
|
|
170
201
|
class << self
|
@@ -218,6 +249,9 @@ module Hyperstack
|
|
218
249
|
|
219
250
|
@opts = Hash.new(`window.HyperstackOpts`)
|
220
251
|
|
252
|
+
if opts[:transport] != :none && `typeof(window.HyperstackEnginePath) == 'undefined'`
|
253
|
+
raise "No hyperstack mount point found!\nCheck your Rails routes.rb file";
|
254
|
+
end
|
221
255
|
|
222
256
|
if opts[:transport] == :pusher
|
223
257
|
|
@@ -1,173 +1,95 @@
|
|
1
|
-
|
2
|
-
module AutoCreate
|
3
|
-
def table_exists?
|
4
|
-
# works with both rails 4 and 5 without deprecation warnings
|
5
|
-
if connection.respond_to?(:data_sources)
|
6
|
-
connection.data_sources.include?(table_name)
|
7
|
-
else
|
8
|
-
connection.tables.include?(table_name)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def needs_init?
|
13
|
-
Hyperstack.transport != :none && Hyperstack.on_server? && !table_exists?
|
14
|
-
end
|
15
|
-
|
16
|
-
def create_table(*args, &block)
|
17
|
-
connection.create_table(table_name, *args, &block) if needs_init?
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Connection < ActiveRecord::Base
|
22
|
-
class QueuedMessage < ActiveRecord::Base
|
23
|
-
|
24
|
-
extend AutoCreate
|
25
|
-
|
26
|
-
self.table_name = 'hyperstack_queued_messages'
|
27
|
-
|
28
|
-
do_not_synchronize
|
29
|
-
|
30
|
-
serialize :data
|
1
|
+
# frozen_string_literal: true
|
31
2
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
3
|
+
module Hyperstack
|
4
|
+
class Connection
|
5
|
+
class << self
|
6
|
+
attr_accessor :transport, :connection_adapter, :show_diagnostics
|
7
|
+
|
8
|
+
def adapter
|
9
|
+
adapter_name = Hyperstack.connection[:adapter].to_s
|
10
|
+
adapter_path = "hyper-operation/transport/connection_adapter/#{adapter_name}"
|
11
|
+
|
12
|
+
begin
|
13
|
+
require adapter_path
|
14
|
+
rescue LoadError => e
|
15
|
+
if e.path == adapter_path
|
16
|
+
raise e.class, "Could not load the '#{adapter_name}' adapter. Make sure the adapter is spelled correctly in your Hyperstack config, and the necessary gems are in your Gemfile.", e.backtrace
|
17
|
+
|
18
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
19
|
+
# with some guidance about how to address it and reraise.
|
20
|
+
else
|
21
|
+
raise e.class, "Error loading the '#{adapter_name}' adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
22
|
+
end
|
23
|
+
end
|
44
24
|
|
45
|
-
|
46
|
-
|
25
|
+
adapter_name = adapter_name.camelize
|
26
|
+
"Hyperstack::ConnectionAdapter::#{adapter_name}".constantize
|
47
27
|
end
|
48
28
|
|
49
|
-
def
|
50
|
-
|
29
|
+
def build_tables
|
30
|
+
adapter.build_tables
|
51
31
|
end
|
52
|
-
end
|
53
|
-
|
54
|
-
extend AutoCreate
|
55
32
|
|
56
|
-
|
57
|
-
|
58
|
-
t.string :channel
|
59
|
-
t.string :session
|
60
|
-
t.datetime :created_at
|
61
|
-
t.datetime :expires_at
|
62
|
-
t.datetime :refresh_at
|
63
|
-
end
|
64
|
-
QueuedMessage.create_table(force: :cascade) do |t|
|
65
|
-
t.text :data
|
66
|
-
t.integer :connection_id
|
33
|
+
def build_tables?
|
34
|
+
adapter.respond_to?(:build_tables)
|
67
35
|
end
|
68
|
-
end
|
69
|
-
|
70
|
-
do_not_synchronize
|
71
|
-
|
72
|
-
self.table_name = 'hyperstack_connections'
|
73
|
-
|
74
|
-
has_many :messages,
|
75
|
-
foreign_key: 'connection_id',
|
76
|
-
class_name: 'Hyperstack::Connection::QueuedMessage',
|
77
|
-
dependent: :destroy
|
78
|
-
scope :expired,
|
79
|
-
-> { where('expires_at IS NOT NULL AND expires_at < ?', Time.zone.now) }
|
80
|
-
scope :pending_for,
|
81
|
-
->(channel) { where(channel: channel).where('session IS NOT NULL') }
|
82
|
-
scope :inactive,
|
83
|
-
-> { where('session IS NULL AND refresh_at < ?', Time.zone.now) }
|
84
|
-
|
85
|
-
def self.needs_refresh?
|
86
|
-
exists?(['refresh_at IS NOT NULL AND refresh_at < ?', Time.zone.now])
|
87
|
-
end
|
88
|
-
|
89
|
-
def transport
|
90
|
-
self.class.transport
|
91
|
-
end
|
92
|
-
|
93
|
-
before_create do
|
94
|
-
if session
|
95
|
-
self.expires_at = Time.now + transport.expire_new_connection_in
|
96
|
-
elsif transport.refresh_channels_every != :never
|
97
|
-
self.refresh_at = Time.now + transport.refresh_channels_every
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
class << self
|
102
|
-
attr_accessor :transport
|
103
36
|
|
104
37
|
def active
|
105
|
-
|
106
|
-
# a migration or from a console before the server has ever started
|
107
|
-
# in these cases there are no channels so we return nothing
|
108
|
-
return [] unless table_exists?
|
109
|
-
if Hyperstack.on_server?
|
110
|
-
expired.delete_all
|
111
|
-
refresh_connections if needs_refresh?
|
112
|
-
end
|
113
|
-
all.pluck(:channel).uniq
|
38
|
+
adapter.active
|
114
39
|
end
|
115
40
|
|
116
41
|
def open(channel, session = nil, root_path = nil)
|
117
|
-
|
118
|
-
|
42
|
+
puts "open(#{channel}, #{session}, #{root_path})" if show_diagnostics
|
43
|
+
|
44
|
+
adapter.open(channel, session, root_path).tap do |c|
|
45
|
+
puts " - open returning #{c}" if show_diagnostics
|
46
|
+
end
|
119
47
|
end
|
120
48
|
|
121
49
|
def send_to_channel(channel, data)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
transport.send_data(channel, data) if exists?(channel: channel, session: nil)
|
50
|
+
puts "send_to_channel(#{channel}, #{data})" if show_diagnostics
|
51
|
+
|
52
|
+
adapter.send_to_channel(channel, data)
|
126
53
|
end
|
127
54
|
|
128
55
|
def read(session, root_path)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
QueuedMessage.for_session(session).destroy_all.pluck(:data)
|
56
|
+
puts "read(#{session}, #{root_path})" if show_diagnostics
|
57
|
+
|
58
|
+
adapter.read(session, root_path)
|
133
59
|
end
|
134
60
|
|
135
61
|
def connect_to_transport(channel, session, root_path)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
connection.destroy
|
140
|
-
else
|
141
|
-
messages = []
|
142
|
-
end
|
143
|
-
open(channel)
|
144
|
-
messages
|
62
|
+
puts "connect_to_transport(#{channel}, #{session}, #{root_path})" if show_diagnostics
|
63
|
+
|
64
|
+
adapter.connect_to_transport(channel, session, root_path)
|
145
65
|
end
|
146
66
|
|
147
67
|
def disconnect(channel)
|
148
|
-
|
68
|
+
adapter.disconnect(channel)
|
149
69
|
end
|
150
70
|
|
151
71
|
def root_path=(path)
|
152
|
-
|
72
|
+
adapter.root_path = path
|
153
73
|
end
|
154
74
|
|
155
75
|
def root_path
|
156
|
-
|
157
|
-
# a migration or from a console before the server has ever started
|
158
|
-
# in these cases there is no root path to the server
|
159
|
-
QueuedMessage.root_path if QueuedMessage.table_exists?
|
76
|
+
adapter.root_path
|
160
77
|
end
|
161
78
|
|
162
79
|
def refresh_connections
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
80
|
+
adapter.refresh_connections
|
81
|
+
end
|
82
|
+
|
83
|
+
def method_missing(method_name, *args, &block)
|
84
|
+
if adapter::Connection.respond_to?(method_name)
|
85
|
+
adapter::Connection.send(method_name, *args, &block)
|
86
|
+
else
|
87
|
+
super
|
169
88
|
end
|
170
|
-
|
89
|
+
end
|
90
|
+
|
91
|
+
def respond_to_missing?(method_name, include_private = false)
|
92
|
+
adapter::Connection.respond_to?(method_name)
|
171
93
|
end
|
172
94
|
end
|
173
95
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'active_record/connection'
|
4
|
+
require_relative 'active_record/queued_message'
|
5
|
+
|
6
|
+
module Hyperstack
|
7
|
+
module ConnectionAdapter
|
8
|
+
module ActiveRecord
|
9
|
+
class << self
|
10
|
+
def build_tables
|
11
|
+
Connection.create_table(force: :cascade) do |t|
|
12
|
+
t.string :channel
|
13
|
+
t.string :session
|
14
|
+
t.datetime :created_at
|
15
|
+
t.datetime :expires_at
|
16
|
+
t.datetime :refresh_at
|
17
|
+
end
|
18
|
+
|
19
|
+
QueuedMessage.create_table(force: :cascade) do |t|
|
20
|
+
t.text :data
|
21
|
+
t.integer :connection_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def transport
|
26
|
+
Hyperstack::Connection.transport
|
27
|
+
end
|
28
|
+
|
29
|
+
def active
|
30
|
+
# if table doesn't exist then we are either calling from within
|
31
|
+
# a migration or from a console before the server has ever started
|
32
|
+
# in these cases there are no channels so we return nothing
|
33
|
+
return [] unless Connection.table_exists?
|
34
|
+
|
35
|
+
if Hyperstack.on_server?
|
36
|
+
Connection.expired.delete_all
|
37
|
+
refresh_connections if Connection.needs_refresh?
|
38
|
+
end
|
39
|
+
|
40
|
+
Connection.all.pluck(:channel).uniq
|
41
|
+
rescue ::ActiveRecord::StatementInvalid
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
|
45
|
+
def open(channel, session = nil, root_path = nil)
|
46
|
+
self.root_path = root_path
|
47
|
+
|
48
|
+
Connection.find_or_create_by(channel: channel, session: session)
|
49
|
+
end
|
50
|
+
|
51
|
+
def send_to_channel(channel, data)
|
52
|
+
Connection.pending_for(channel).each do |connection|
|
53
|
+
QueuedMessage.create(data: data, hyperstack_connection: connection)
|
54
|
+
end
|
55
|
+
|
56
|
+
transport.send_data(channel, data) if Connection.exists?(channel: channel, session: nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
def read(session, root_path)
|
60
|
+
self.root_path = root_path
|
61
|
+
|
62
|
+
Connection.where(session: session)
|
63
|
+
.update_all(expires_at: Time.current + transport.expire_polled_connection_in)
|
64
|
+
|
65
|
+
QueuedMessage.for_session(session).destroy_all.pluck(:data)
|
66
|
+
end
|
67
|
+
|
68
|
+
def connect_to_transport(channel, session, root_path)
|
69
|
+
self.root_path = root_path
|
70
|
+
|
71
|
+
if (connection = Connection.find_by(channel: channel, session: session))
|
72
|
+
messages = connection.messages.pluck(:data)
|
73
|
+
connection.destroy
|
74
|
+
else
|
75
|
+
messages = []
|
76
|
+
end
|
77
|
+
|
78
|
+
open(channel)
|
79
|
+
|
80
|
+
messages
|
81
|
+
end
|
82
|
+
|
83
|
+
def disconnect(channel)
|
84
|
+
Connection.find_by(channel: channel, session: nil).destroy
|
85
|
+
end
|
86
|
+
|
87
|
+
def root_path=(path)
|
88
|
+
QueuedMessage.root_path = path if path
|
89
|
+
end
|
90
|
+
|
91
|
+
def root_path
|
92
|
+
# if the QueuedMessage table doesn't exist then we are either calling from within
|
93
|
+
# a migration or from a console before the server has ever started
|
94
|
+
# in these cases there is no root path to the server
|
95
|
+
QueuedMessage.root_path if QueuedMessage.table_exists?
|
96
|
+
end
|
97
|
+
|
98
|
+
def refresh_connections
|
99
|
+
refresh_started_at = Time.current
|
100
|
+
channels = transport.refresh_channels
|
101
|
+
next_refresh = refresh_started_at + transport.refresh_channels_every
|
102
|
+
|
103
|
+
channels.each do |channel|
|
104
|
+
connection = Connection.find_by(channel: channel, session: nil)
|
105
|
+
connection.update(refresh_at: next_refresh) if connection
|
106
|
+
end
|
107
|
+
|
108
|
+
Connection.inactive.delete_all
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|