hyper-operation 1.0.alpha1.8 → 1.0.0.lap28
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 +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
|