factor 0.6.3 → 0.6.4
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/bin/factor +1 -1
- data/lib/{factor.rb → commands.rb} +8 -8
- data/lib/commands/base.rb +6 -64
- data/lib/commands/{registry.rb → registry_command.rb} +1 -1
- data/lib/commands/{workflows.rb → workflow_command.rb} +25 -34
- data/lib/common/deep_struct.rb +48 -0
- data/lib/factor/version.rb +1 -1
- data/lib/logger/basic.rb +68 -0
- data/lib/logger/logger.rb +28 -0
- data/lib/runtime/exec_handler.rb +16 -0
- data/lib/runtime/service_address.rb +46 -0
- data/lib/runtime/service_caller.rb +105 -0
- data/lib/runtime/workflow.rb +170 -0
- data/lib/websocket_manager.rb +2 -1
- data/spec/spec_helper.rb +0 -7
- metadata +14 -17
- data/lib/listener.rb +0 -26
- data/lib/runtime.rb +0 -232
- data/spec/base_spec.rb +0 -102
- data/spec/listener_spec.rb +0 -9
- data/spec/registry_spec.rb +0 -0
- data/spec/workflow_spec.rb +0 -11
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
module Factor
|
3
|
+
module Log
|
4
|
+
|
5
|
+
class Logger
|
6
|
+
|
7
|
+
def log
|
8
|
+
raise NotImplemented
|
9
|
+
end
|
10
|
+
|
11
|
+
def info
|
12
|
+
raise NotImplemented
|
13
|
+
end
|
14
|
+
|
15
|
+
def warn
|
16
|
+
raise NotImplemented
|
17
|
+
end
|
18
|
+
|
19
|
+
def error
|
20
|
+
raise NotImplemented
|
21
|
+
end
|
22
|
+
|
23
|
+
def time
|
24
|
+
Time.now.localtime.strftime('%m/%d/%y %T.%L')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Factor
|
2
|
+
module Runtime
|
3
|
+
class ExecHandler
|
4
|
+
attr_accessor :params, :service, :fail_block
|
5
|
+
|
6
|
+
def initialize(service = nil, params = {})
|
7
|
+
@service = service
|
8
|
+
@params = params
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_fail(&block)
|
12
|
+
@fail_block = block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Factor
|
2
|
+
module Runtime
|
3
|
+
class ServiceAddress < Array
|
4
|
+
def initialize(service_ref)
|
5
|
+
if service_ref.is_a?(String)
|
6
|
+
service_map = service_ref.split('::')
|
7
|
+
raise ArgumentError, 'Address must not be empty' if service_ref.empty?
|
8
|
+
raise ArgumentError, 'Address must contain at least one value' unless service_map.count > 0
|
9
|
+
raise ArgumentError, 'Address must contain at least one value' unless service_map.all?{|i| !i.empty?}
|
10
|
+
super service_map
|
11
|
+
elsif service_ref.is_a?(ServiceAddress) || service_ref.is_a?(Array)
|
12
|
+
raise ArgumentError, 'All elements in array must be a string' unless service_ref.all?{|i| i.is_a?(String)}
|
13
|
+
super service_ref
|
14
|
+
else
|
15
|
+
raise ArgumentError, 'Address must be a String, Array, or ServiceAddress'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def workflow?
|
20
|
+
self.service == 'workflow'
|
21
|
+
end
|
22
|
+
|
23
|
+
def service
|
24
|
+
self.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def namespace
|
28
|
+
raise ArgumentError, 'Address must contain at least two parts' unless self.count >= 2
|
29
|
+
self[0..-2].map{|k| k.to_sym}
|
30
|
+
end
|
31
|
+
|
32
|
+
def id
|
33
|
+
self.last
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
self.join('::')
|
38
|
+
end
|
39
|
+
|
40
|
+
def workflow_address
|
41
|
+
workflow_service_map = self[1..-1]
|
42
|
+
ServiceAddress.new workflow_service_map
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'websocket_manager'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module Factor
|
5
|
+
module Runtime
|
6
|
+
class ServiceCaller
|
7
|
+
attr_accessor :reconnect, :retry_period
|
8
|
+
|
9
|
+
def initialize(connector_url, options = {})
|
10
|
+
@url = connector_url
|
11
|
+
@subscribers = {}
|
12
|
+
@reconnect = options[:reconnect] || true
|
13
|
+
@retry_period = options[:retry_period] || 5
|
14
|
+
@retry_count = 0
|
15
|
+
@offline_duration = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def listen(listener_id, params={})
|
19
|
+
@reconnect = true
|
20
|
+
call("#{@url}/listeners/#{listener_id}", params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def action(action_id, params={})
|
24
|
+
@reconnect = false
|
25
|
+
call("#{@url}/actions/#{action_id}", params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
@ws.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def on(event, &block)
|
33
|
+
@subscribers ||= {}
|
34
|
+
@subscribers[event.to_sym] ||= []
|
35
|
+
@subscribers[event.to_sym] << block
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def start(params)
|
41
|
+
@ws.open
|
42
|
+
@ws.send(params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def retry_connection(params)
|
46
|
+
@retry_count += 1
|
47
|
+
notify :retry, count: @retry_count, offline_duration: @offline_duration
|
48
|
+
@offline_duration += @retry_period
|
49
|
+
|
50
|
+
EM.next_tick{
|
51
|
+
sleep @retry_period
|
52
|
+
start(params)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(url, params={})
|
57
|
+
@ws = Factor::WebSocketManager.new(url)
|
58
|
+
|
59
|
+
@ws.on :open do
|
60
|
+
@retry_count = 0
|
61
|
+
@offline_duration = 0
|
62
|
+
notify :open
|
63
|
+
end
|
64
|
+
|
65
|
+
@ws.on :close do
|
66
|
+
notify :close if @retry_count == 0
|
67
|
+
retry_connection(params) if @reconnect
|
68
|
+
end
|
69
|
+
|
70
|
+
@ws.on :error do
|
71
|
+
notify :fail, message: 'Connection dropped while calling action'
|
72
|
+
end
|
73
|
+
|
74
|
+
@ws.on :message do |event|
|
75
|
+
action_response = JSON.parse(event.data)
|
76
|
+
case action_response['type']
|
77
|
+
when 'return'
|
78
|
+
notify :return, action_response['payload']
|
79
|
+
when 'fail'
|
80
|
+
@ws.close
|
81
|
+
notify :log, status:'error', message: " #{action_response['message']}"
|
82
|
+
notify :fail
|
83
|
+
when 'log'
|
84
|
+
message = " #{action_response['message']}"
|
85
|
+
notify :log, status: action_response['status'], message: message
|
86
|
+
when 'start_workflow'
|
87
|
+
notify :start_workflow, action_response
|
88
|
+
else
|
89
|
+
notify :log, status:'error', message: "Unknown action response: #{action_response}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
start(params)
|
94
|
+
end
|
95
|
+
|
96
|
+
def notify(event, params={})
|
97
|
+
if @subscribers[event]
|
98
|
+
@subscribers[event].each do |block|
|
99
|
+
EM.next_tick { block.call(params) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'eventmachine'
|
5
|
+
|
6
|
+
require 'commands/base'
|
7
|
+
require 'common/deep_struct'
|
8
|
+
require 'runtime/service_caller'
|
9
|
+
require 'runtime/service_address'
|
10
|
+
require 'runtime/exec_handler'
|
11
|
+
|
12
|
+
module Factor
|
13
|
+
module Runtime
|
14
|
+
class Workflow
|
15
|
+
attr_accessor :name, :description, :id, :instance_id, :connectors, :credentials
|
16
|
+
|
17
|
+
def initialize(connectors, credentials, options={})
|
18
|
+
@workflow_spec = {}
|
19
|
+
@workflows = {}
|
20
|
+
@instance_id = SecureRandom.hex(3)
|
21
|
+
@reconnect = true
|
22
|
+
@logger = options[:logger] if options[:logger]
|
23
|
+
|
24
|
+
@connectors = Factor::Common.flat_hash(connectors)
|
25
|
+
@credentials = credentials
|
26
|
+
end
|
27
|
+
|
28
|
+
def load(workflow_definition)
|
29
|
+
begin
|
30
|
+
EM.run do
|
31
|
+
instance_eval(workflow_definition)
|
32
|
+
end
|
33
|
+
rescue Interrupt
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def listen(service_ref, params = {}, &block)
|
38
|
+
address = ServiceAddress.new(service_ref)
|
39
|
+
e = ExecHandler.new(service_ref, params)
|
40
|
+
connector_url = @connectors[address.namespace]
|
41
|
+
|
42
|
+
if !connector_url
|
43
|
+
error "Listener '#{address}' not found"
|
44
|
+
e.fail_block.call({}) if e.fail_block
|
45
|
+
else
|
46
|
+
caller = ServiceCaller.new(connector_url)
|
47
|
+
|
48
|
+
caller.on :close do
|
49
|
+
error "Listener '#{address}' disconnected"
|
50
|
+
end
|
51
|
+
|
52
|
+
caller.on :open do
|
53
|
+
info "Listener '#{address}' starting"
|
54
|
+
end
|
55
|
+
|
56
|
+
caller.on :retry do |retry_info|
|
57
|
+
if retry_info
|
58
|
+
details = " ("
|
59
|
+
details << "retry #{retry_info[:count]}"
|
60
|
+
details << ", offline for #{retry_info[:offline_duration]} seconds" if retry_info[:offline_duration] > 0
|
61
|
+
details << ")"
|
62
|
+
end
|
63
|
+
warn "Listener '#{address}' reconnecting#{details || ''}"
|
64
|
+
end
|
65
|
+
|
66
|
+
caller.on :error do
|
67
|
+
error "Listener '#{address}' dropped the connection"
|
68
|
+
end
|
69
|
+
|
70
|
+
caller.on :return do |data|
|
71
|
+
success "Listener '#{address}' started"
|
72
|
+
end
|
73
|
+
|
74
|
+
caller.on :start_workflow do |data|
|
75
|
+
success "Listener '#{address}' triggered"
|
76
|
+
block.call(Factor::Common.simple_object_convert(data))
|
77
|
+
end
|
78
|
+
|
79
|
+
caller.on :fail do |info|
|
80
|
+
error "Listener '#{address}' failed"
|
81
|
+
e.fail_block.call(action_response) if e.fail_block
|
82
|
+
end
|
83
|
+
|
84
|
+
caller.on :log do |log_info|
|
85
|
+
@logger.log log_info[:status], log_info
|
86
|
+
end
|
87
|
+
|
88
|
+
caller.listen(address.id,params)
|
89
|
+
end
|
90
|
+
e
|
91
|
+
end
|
92
|
+
|
93
|
+
def workflow(service_ref, &block)
|
94
|
+
address = ServiceAddress.new(service_ref)
|
95
|
+
@workflows ||= {}
|
96
|
+
@workflows[address] = block
|
97
|
+
end
|
98
|
+
|
99
|
+
def run(service_ref, params = {}, &block)
|
100
|
+
address = ServiceAddress.new(service_ref)
|
101
|
+
e = ExecHandler.new(service_ref, params)
|
102
|
+
|
103
|
+
if address.workflow?
|
104
|
+
workflow_address = address.workflow_address
|
105
|
+
workflow = @workflows[workflow_address]
|
106
|
+
|
107
|
+
if workflow
|
108
|
+
success "Workflow '#{workflow_address}' starting"
|
109
|
+
content = Factor::Common.simple_object_convert(params)
|
110
|
+
workflow.call(content)
|
111
|
+
success "Workflow '#{workflow_address}' started"
|
112
|
+
else
|
113
|
+
error "Workflow '#{workflow_address}' not found"
|
114
|
+
e.fail_block.call({}) if e.fail_block
|
115
|
+
end
|
116
|
+
else
|
117
|
+
connector_url = @connectors[address.namespace]
|
118
|
+
caller = ServiceCaller.new(connector_url)
|
119
|
+
|
120
|
+
caller.on :open do
|
121
|
+
info "Action '#{address}' starting"
|
122
|
+
end
|
123
|
+
|
124
|
+
caller.on :error do
|
125
|
+
error "Action '#{address}' dropped the connection"
|
126
|
+
end
|
127
|
+
|
128
|
+
caller.on :return do |data|
|
129
|
+
success "Action '#{address}' responded"
|
130
|
+
caller.close
|
131
|
+
block.call(Factor::Common.simple_object_convert(data))
|
132
|
+
end
|
133
|
+
|
134
|
+
caller.on :close do
|
135
|
+
error "Action '#{address}' disconnected"
|
136
|
+
e.fail_block.call(action_response) if e.fail_block
|
137
|
+
end
|
138
|
+
|
139
|
+
caller.on :fail do |info|
|
140
|
+
error "Action '#{address}' failed"
|
141
|
+
e.fail_block.call(action_response) if e.fail_block
|
142
|
+
end
|
143
|
+
|
144
|
+
caller.on :log do |log_info|
|
145
|
+
@logger.log log_info[:status], log_info
|
146
|
+
end
|
147
|
+
|
148
|
+
caller.action(address.id,params)
|
149
|
+
end
|
150
|
+
e
|
151
|
+
end
|
152
|
+
|
153
|
+
def success(message)
|
154
|
+
@logger.success message
|
155
|
+
end
|
156
|
+
|
157
|
+
def info(message)
|
158
|
+
@logger.info message
|
159
|
+
end
|
160
|
+
|
161
|
+
def warn(message)
|
162
|
+
@logger.warn message
|
163
|
+
end
|
164
|
+
|
165
|
+
def error(message)
|
166
|
+
@logger.error message
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/lib/websocket_manager.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'faye/websocket'
|
4
4
|
require 'uri'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
module Factor
|
7
8
|
# class for managing the web socket connections
|
@@ -54,7 +55,7 @@ module Factor
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def send(msg)
|
57
|
-
@ws.send(msg)
|
58
|
+
@ws.send(msg.to_json)
|
58
59
|
end
|
59
60
|
|
60
61
|
private
|
data/spec/spec_helper.rb
CHANGED
@@ -7,13 +7,6 @@ CodeClimate::TestReporter.start do
|
|
7
7
|
add_filter '/spec/'
|
8
8
|
end
|
9
9
|
|
10
|
-
# include anything that could be tested
|
11
|
-
require 'commands/base'
|
12
|
-
require 'commands/workflows'
|
13
|
-
require 'listener'
|
14
|
-
require 'runtime'
|
15
|
-
require 'websocket_manager'
|
16
|
-
|
17
10
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
18
11
|
|
19
12
|
def capture_stdout(&_block)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maciej Skierkowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.8.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.8.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: colored
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,19 +144,20 @@ executables:
|
|
144
144
|
extensions: []
|
145
145
|
extra_rdoc_files: []
|
146
146
|
files:
|
147
|
-
- "./spec/base_spec.rb"
|
148
|
-
- "./spec/listener_spec.rb"
|
149
|
-
- "./spec/registry_spec.rb"
|
150
147
|
- "./spec/spec_helper.rb"
|
151
|
-
- "./spec/workflow_spec.rb"
|
152
148
|
- bin/factor
|
149
|
+
- lib/commands.rb
|
153
150
|
- lib/commands/base.rb
|
154
|
-
- lib/commands/
|
155
|
-
- lib/commands/
|
156
|
-
- lib/
|
151
|
+
- lib/commands/registry_command.rb
|
152
|
+
- lib/commands/workflow_command.rb
|
153
|
+
- lib/common/deep_struct.rb
|
157
154
|
- lib/factor/version.rb
|
158
|
-
- lib/
|
159
|
-
- lib/
|
155
|
+
- lib/logger/basic.rb
|
156
|
+
- lib/logger/logger.rb
|
157
|
+
- lib/runtime/exec_handler.rb
|
158
|
+
- lib/runtime/service_address.rb
|
159
|
+
- lib/runtime/service_caller.rb
|
160
|
+
- lib/runtime/workflow.rb
|
160
161
|
- lib/websocket_manager.rb
|
161
162
|
homepage: https://factor.io
|
162
163
|
licenses: []
|
@@ -182,8 +183,4 @@ signing_key:
|
|
182
183
|
specification_version: 4
|
183
184
|
summary: CLI to manager workflows on Factor.io
|
184
185
|
test_files:
|
185
|
-
- "./spec/base_spec.rb"
|
186
|
-
- "./spec/listener_spec.rb"
|
187
|
-
- "./spec/registry_spec.rb"
|
188
186
|
- "./spec/spec_helper.rb"
|
189
|
-
- "./spec/workflow_spec.rb"
|