factor 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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.3
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-10-30 00:00:00.000000000 Z
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.7.5
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.7.5
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/registry.rb
155
- - lib/commands/workflows.rb
156
- - lib/factor.rb
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/listener.rb
159
- - lib/runtime.rb
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"