hyper-operation 1.0.alpha1.8 → 1.0.0.lap28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -7
- data/.travis.yml +9 -21
- data/CODE_OF_CONDUCT.md +49 -0
- data/DOCS-POLICIES.md +582 -0
- data/DOCS.md +869 -0
- data/Gemfile +1 -5
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +2 -1
- data/dciy.toml +3 -0
- data/hyper-operation.gemspec +15 -19
- data/lib/hyper-operation.rb +6 -10
- data/lib/hyper-operation/api.rb +4 -8
- data/lib/hyper-operation/boot.rb +2 -3
- data/lib/hyper-operation/delay_and_interval.rb +9 -0
- data/lib/hyper-operation/engine.rb +2 -2
- data/lib/hyper-operation/exception.rb +4 -30
- data/lib/hyper-operation/filters/acting_user.rb +1 -1
- data/lib/hyper-operation/http.rb +2 -2
- data/lib/hyper-operation/promise.rb +2 -32
- data/lib/hyper-operation/railway.rb +1 -1
- data/lib/hyper-operation/railway/dispatcher.rb +5 -8
- data/lib/hyper-operation/railway/params_wrapper.rb +2 -2
- data/lib/hyper-operation/railway/run.rb +49 -58
- data/lib/hyper-operation/railway/validations.rb +3 -10
- data/lib/hyper-operation/server_op.rb +20 -46
- data/lib/hyper-operation/transport/action_cable.rb +8 -8
- data/lib/hyper-operation/transport/client_drivers.rb +55 -96
- data/lib/hyper-operation/transport/connection.rb +136 -58
- data/lib/hyper-operation/transport/{hyperstack.rb → hyperloop.rb} +15 -28
- data/lib/hyper-operation/transport/{hyperstack_controller.rb → hyperloop_controller.rb} +53 -59
- data/lib/hyper-operation/transport/policy.rb +49 -50
- data/lib/hyper-operation/version.rb +2 -2
- data/lib/sources/{hyperstack → hyperloop}/pusher.js +0 -0
- metadata +73 -94
- data/lib/hyper-operation/async_sleep.rb +0 -23
- data/lib/hyper-operation/transport/connection_adapter/active_record.rb +0 -113
- data/lib/hyper-operation/transport/connection_adapter/active_record/auto_create.rb +0 -26
- data/lib/hyper-operation/transport/connection_adapter/active_record/connection.rb +0 -47
- data/lib/hyper-operation/transport/connection_adapter/active_record/queued_message.rb +0 -42
- data/lib/hyper-operation/transport/connection_adapter/redis.rb +0 -94
- data/lib/hyper-operation/transport/connection_adapter/redis/connection.rb +0 -85
- data/lib/hyper-operation/transport/connection_adapter/redis/queued_message.rb +0 -34
- data/lib/hyper-operation/transport/connection_adapter/redis/redis_record.rb +0 -158
- data/lib/hyper-operation/transport/policy_diagnostics.rb +0 -106
@@ -1,23 +0,0 @@
|
|
1
|
-
module Hyperstack
|
2
|
-
module AsyncSleep
|
3
|
-
if RUBY_ENGINE == 'opal'
|
4
|
-
def self.every(*args, &block)
|
5
|
-
every(*args, &block)
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.after(*args, &block)
|
9
|
-
after(*args, &block)
|
10
|
-
end
|
11
|
-
else
|
12
|
-
extend self
|
13
|
-
|
14
|
-
def every(time, &block)
|
15
|
-
Thread.new { loop { sleep time; block.call } }
|
16
|
-
end
|
17
|
-
|
18
|
-
def after(time, &block)
|
19
|
-
Thread.new { sleep time; block.call }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,113 +0,0 @@
|
|
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
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hyperstack
|
4
|
-
module ConnectionAdapter
|
5
|
-
module ActiveRecord
|
6
|
-
module AutoCreate
|
7
|
-
def table_exists?
|
8
|
-
# works with both rails 4 and 5 without deprecation warnings
|
9
|
-
if connection.respond_to?(:data_sources)
|
10
|
-
connection.data_sources.include?(table_name)
|
11
|
-
else
|
12
|
-
connection.tables.include?(table_name)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def needs_init?
|
17
|
-
Hyperstack.transport != :none && Hyperstack.on_server? && !table_exists?
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_table(*args, &block)
|
21
|
-
connection.create_table(table_name, *args, &block) if needs_init?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'auto_create'
|
4
|
-
|
5
|
-
module Hyperstack
|
6
|
-
module ConnectionAdapter
|
7
|
-
module ActiveRecord
|
8
|
-
class Connection < ::ActiveRecord::Base
|
9
|
-
extend AutoCreate
|
10
|
-
|
11
|
-
self.table_name = 'hyperstack_connections'
|
12
|
-
|
13
|
-
do_not_synchronize
|
14
|
-
|
15
|
-
has_many :messages,
|
16
|
-
foreign_key: 'connection_id',
|
17
|
-
class_name: 'Hyperstack::ConnectionAdapter::ActiveRecord::QueuedMessage',
|
18
|
-
dependent: :destroy
|
19
|
-
|
20
|
-
scope :expired,
|
21
|
-
-> { where('expires_at IS NOT NULL AND expires_at < ?', Time.current) }
|
22
|
-
scope :pending_for,
|
23
|
-
->(channel) { where(channel: channel).where('session IS NOT NULL') }
|
24
|
-
scope :inactive,
|
25
|
-
-> { where('session IS NULL AND refresh_at < ?', Time.current) }
|
26
|
-
|
27
|
-
before_create do
|
28
|
-
if session
|
29
|
-
self.expires_at = Time.current + transport.expire_new_connection_in
|
30
|
-
elsif transport.refresh_channels_every != :never
|
31
|
-
self.refresh_at = Time.current + transport.refresh_channels_every
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class << self
|
36
|
-
def needs_refresh?
|
37
|
-
exists?(['refresh_at IS NOT NULL AND refresh_at < ?', Time.current])
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def transport
|
42
|
-
Hyperstack::Connection.transport
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'auto_create'
|
4
|
-
|
5
|
-
module Hyperstack
|
6
|
-
module ConnectionAdapter
|
7
|
-
module ActiveRecord
|
8
|
-
class QueuedMessage < ::ActiveRecord::Base
|
9
|
-
extend AutoCreate
|
10
|
-
|
11
|
-
self.table_name = 'hyperstack_queued_messages'
|
12
|
-
|
13
|
-
do_not_synchronize
|
14
|
-
|
15
|
-
serialize :data
|
16
|
-
|
17
|
-
belongs_to :hyperstack_connection,
|
18
|
-
class_name: 'Hyperstack::ConnectionAdapter::ActiveRecord::Connection',
|
19
|
-
foreign_key: 'connection_id',
|
20
|
-
optional: true
|
21
|
-
|
22
|
-
scope :for_session,
|
23
|
-
->(session) { joins(:hyperstack_connection).where('session = ?', session) }
|
24
|
-
|
25
|
-
# For simplicity we use QueuedMessage with connection_id 0
|
26
|
-
# to store the current path which is used by consoles to
|
27
|
-
# communicate back to the server. The belongs_to connection
|
28
|
-
# therefore must be optional.
|
29
|
-
|
30
|
-
default_scope { where('connection_id IS NULL OR connection_id != 0') }
|
31
|
-
|
32
|
-
def self.root_path=(path)
|
33
|
-
unscoped.find_or_create_by(connection_id: 0).update(data: path)
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.root_path
|
37
|
-
unscoped.find_or_create_by(connection_id: 0).data
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'redis/connection'
|
4
|
-
require_relative 'redis/queued_message'
|
5
|
-
|
6
|
-
module Hyperstack
|
7
|
-
module ConnectionAdapter
|
8
|
-
module Redis
|
9
|
-
class << self
|
10
|
-
def transport
|
11
|
-
Hyperstack::Connection.transport
|
12
|
-
end
|
13
|
-
|
14
|
-
def active
|
15
|
-
if Hyperstack.on_server?
|
16
|
-
Connection.expired.each(&:destroy)
|
17
|
-
refresh_connections if Connection.needs_refresh?
|
18
|
-
end
|
19
|
-
|
20
|
-
Connection.all.map(&:channel).uniq
|
21
|
-
end
|
22
|
-
|
23
|
-
def open(channel, session = nil, root_path = nil)
|
24
|
-
self.root_path = root_path
|
25
|
-
|
26
|
-
Connection.find_or_create_by(channel: channel, session: session)
|
27
|
-
end
|
28
|
-
|
29
|
-
def send_to_channel(channel, data)
|
30
|
-
Connection.pending_for(channel).each do |connection|
|
31
|
-
QueuedMessage.create(connection_id: connection.id, data: data)
|
32
|
-
end
|
33
|
-
|
34
|
-
transport.send_data(channel, data) if Connection.exists?(channel: channel, session: nil)
|
35
|
-
end
|
36
|
-
|
37
|
-
def read(session, root_path)
|
38
|
-
self.root_path = root_path
|
39
|
-
|
40
|
-
Connection.where(session: session).each do |connection|
|
41
|
-
connection.update(expires_at: Time.current + transport.expire_polled_connection_in)
|
42
|
-
end
|
43
|
-
|
44
|
-
messages = QueuedMessage.for_session(session)
|
45
|
-
data = messages.map(&:data)
|
46
|
-
messages.each(&:destroy)
|
47
|
-
data
|
48
|
-
end
|
49
|
-
|
50
|
-
def connect_to_transport(channel, session, root_path)
|
51
|
-
self.root_path = root_path
|
52
|
-
|
53
|
-
if (connection = Connection.find_by(channel: channel, session: session))
|
54
|
-
messages = connection.messages.map(&:data)
|
55
|
-
connection.destroy
|
56
|
-
else
|
57
|
-
messages = []
|
58
|
-
end
|
59
|
-
|
60
|
-
open(channel)
|
61
|
-
|
62
|
-
messages
|
63
|
-
end
|
64
|
-
|
65
|
-
def disconnect(channel)
|
66
|
-
Connection.find_by(channel: channel, session: nil).destroy
|
67
|
-
end
|
68
|
-
|
69
|
-
def root_path=(path)
|
70
|
-
QueuedMessage.root_path = path if path
|
71
|
-
end
|
72
|
-
|
73
|
-
def root_path
|
74
|
-
QueuedMessage.root_path
|
75
|
-
rescue
|
76
|
-
nil
|
77
|
-
end
|
78
|
-
|
79
|
-
def refresh_connections
|
80
|
-
refresh_started_at = Time.current
|
81
|
-
channels = transport.refresh_channels
|
82
|
-
next_refresh = refresh_started_at + transport.refresh_channels_every
|
83
|
-
|
84
|
-
channels.each do |channel|
|
85
|
-
connection = Connection.find_by(channel: channel, session: nil)
|
86
|
-
connection.update(refresh_at: next_refresh) if connection
|
87
|
-
end
|
88
|
-
|
89
|
-
Connection.inactive.each(&:destroy)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'redis_record'
|
4
|
-
|
5
|
-
module Hyperstack
|
6
|
-
module ConnectionAdapter
|
7
|
-
module Redis
|
8
|
-
class Connection < RedisRecord::Base
|
9
|
-
self.table_name = 'hyperstack:connections'
|
10
|
-
self.column_names = %w[id channel session created_at expires_at refresh_at].freeze
|
11
|
-
|
12
|
-
attr_accessor(*column_names.map(&:to_sym))
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def transport
|
16
|
-
Hyperstack::Connection.transport
|
17
|
-
end
|
18
|
-
|
19
|
-
def create(opts = {})
|
20
|
-
opts.tap do |hash|
|
21
|
-
if opts[:session]
|
22
|
-
hash[:expires_at] = (Time.current + transport.expire_new_connection_in)
|
23
|
-
elsif transport.refresh_channels_every != :never
|
24
|
-
hash[:refresh_at] = (Time.current + transport.refresh_channels_every)
|
25
|
-
end
|
26
|
-
|
27
|
-
hash[:created_at] = Time.current
|
28
|
-
end.to_a.flatten
|
29
|
-
|
30
|
-
super(opts)
|
31
|
-
end
|
32
|
-
|
33
|
-
def inactive
|
34
|
-
scope { |id| id if inactive?(id) }
|
35
|
-
end
|
36
|
-
|
37
|
-
def inactive?(id)
|
38
|
-
get_dejsonized_attribute(id, :session).blank? &&
|
39
|
-
get_dejsonized_attribute(id, :refresh_at).present? &&
|
40
|
-
Time.zone.parse(get_dejsonized_attribute(id, :refresh_at)) < Time.current
|
41
|
-
end
|
42
|
-
|
43
|
-
def expired
|
44
|
-
scope { |id| id if expired?(id) }
|
45
|
-
end
|
46
|
-
|
47
|
-
def expired?(id)
|
48
|
-
get_dejsonized_attribute(id, :expires_at).present? &&
|
49
|
-
Time.zone.parse(get_dejsonized_attribute(id, :expires_at)) < Time.current
|
50
|
-
end
|
51
|
-
|
52
|
-
def pending_for(channel)
|
53
|
-
scope { |id| id if pending_for?(id, channel) }
|
54
|
-
end
|
55
|
-
|
56
|
-
def pending_for?(id, channel)
|
57
|
-
get_dejsonized_attribute(id, :session).present? &&
|
58
|
-
get_dejsonized_attribute(id, :channel) == channel
|
59
|
-
end
|
60
|
-
|
61
|
-
def needs_refresh?
|
62
|
-
scope { |id| id if needs_refresh(id) }.any?
|
63
|
-
end
|
64
|
-
|
65
|
-
def needs_refresh(id)
|
66
|
-
get_dejsonized_attribute(id, :refresh_at).present? &&
|
67
|
-
Time.zone.parse(get_dejsonized_attribute(id, :refresh_at)) < Time.current
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def messages
|
72
|
-
QueuedMessage.where(connection_id: id)
|
73
|
-
end
|
74
|
-
|
75
|
-
%i[created_at expires_at refresh_at].each do |attr|
|
76
|
-
define_method(attr) do
|
77
|
-
value = instance_variable_get(:"@#{attr}")
|
78
|
-
|
79
|
-
value.is_a?(Time) ? value : Time.zone.parse(value)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'redis_record'
|
4
|
-
|
5
|
-
module Hyperstack
|
6
|
-
module ConnectionAdapter
|
7
|
-
module Redis
|
8
|
-
class QueuedMessage < RedisRecord::Base
|
9
|
-
self.table_name = 'hyperstack:queued_messages'
|
10
|
-
self.column_names = %w[id data connection_id].freeze
|
11
|
-
|
12
|
-
attr_accessor(*column_names.map(&:to_sym))
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def for_session(session)
|
16
|
-
Connection.where(session: session).map(&:messages).flatten
|
17
|
-
end
|
18
|
-
|
19
|
-
def root_path=(path)
|
20
|
-
find_or_create_by(connection_id: 0).update(data: path)
|
21
|
-
end
|
22
|
-
|
23
|
-
def root_path
|
24
|
-
find_or_create_by(connection_id: 0).data
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def connection
|
29
|
-
Connection.find(connection_id)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|