hyper-operation 1.0.alpha1.2 → 1.0.alpha1.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|