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.
@@ -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"