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.
data/lib/listener.rb DELETED
@@ -1,26 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'websocket_manager'
4
-
5
- module Factor
6
- # Class Listener for integrating with connector service
7
- class Listener
8
- def initialize(url)
9
- @url = url
10
- end
11
-
12
- def listener(listener_id)
13
- listen("#{@url}/listeners/#{listener_id}")
14
- end
15
-
16
- def action(action_id)
17
- listen("#{@url}/actions/#{action_id}")
18
- end
19
-
20
- private
21
-
22
- def listen(uri_path)
23
- WebSocketManager.new(uri_path)
24
- end
25
- end
26
- end
data/lib/runtime.rb DELETED
@@ -1,232 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'json'
4
- require 'securerandom'
5
- require 'yaml'
6
- require 'eventmachine'
7
- require 'uri'
8
- require 'faye/websocket'
9
- require 'ostruct'
10
-
11
- require 'listener'
12
- require 'commands/base'
13
-
14
- module Factor
15
- # Runtime class is the magic of the server
16
- class Runtime
17
- attr_accessor :logger, :name, :description, :id, :instance_id, :connectors, :credentials
18
-
19
- def initialize(connectors, credentials)
20
- @workflow_spec = {}
21
- @sockets = []
22
- @instance_id = SecureRandom.hex(3)
23
- @reconnect = true
24
-
25
- trap 'SIGINT' do
26
- info "Exiting '#{@instance_id}'"
27
- @reconnect = false
28
- @sockets.each { |s| s.close }
29
- exit
30
- end
31
-
32
- @connectors = {}
33
- flat_hash(connectors).each do |key, connector_url|
34
- @connectors[key] = Listener.new(connector_url)
35
- end
36
-
37
- @credentials = {}
38
- credentials.each do |connector_id, credential_settings|
39
- @credentials[connector_id] = credential_settings
40
- end
41
- end
42
-
43
- def load(workflow_definition)
44
- EM.run do
45
- instance_eval(workflow_definition)
46
- end
47
- end
48
-
49
- def listen(service_ref, params = {}, &block)
50
- service_map = service_ref.split('::')
51
- service_id = service_map.first
52
- listener_id = service_map.last
53
- service_key = service_map[0..-2].map{|k| k.to_sym}
54
-
55
- ws = @connectors[service_key].listener(listener_id)
56
-
57
- handle_on_open(service_ref, 'Listener', ws, params)
58
-
59
- ws.on :close do
60
- error 'Listener disconnected'
61
- if @reconnect
62
- warn 'Reconnecting...'
63
- sleep 3
64
- ws.open
65
- end
66
- end
67
-
68
- ws.on :message do |event|
69
- listener_response = JSON.parse(event.data)
70
- case listener_response['type']
71
- when'start_workflow'
72
- success "Workflow '#{service_id}::#{listener_id}' triggered"
73
- error_handle_call(listener_response, &block)
74
- when 'return'
75
- success "Workflow '#{service_ref}' started"
76
- when 'fail'
77
- error "Workflow '#{service_ref}' failed to start"
78
- when 'log'
79
- listener_response['message'] = " #{listener_response['message']}"
80
- log_message(listener_response)
81
- else
82
- error "Unknown listener response: #{listener_response}"
83
- end
84
- end
85
-
86
- ws.on :retry do |event|
87
- warn event[:message]
88
- end
89
-
90
- ws.on :error do |event|
91
- err = 'Error during WebSocket handshake: Unexpected response code: 401'
92
- if event.message == err
93
- error "Sorry but you don't have access to this listener,
94
- | either because your token is invalid or your plan doesn't
95
- | support this listener"
96
- else
97
- error 'Failure in WebSocket connection to connector service'
98
- end
99
- end
100
-
101
- ws.open
102
-
103
- @sockets << ws
104
- end
105
-
106
- def run(service_ref, params = {}, &block)
107
- service_map = service_ref.split('::')
108
- service_id = service_map.first
109
- action_id = service_map.last
110
- service_key = service_map[0..-2].map{|k| k.to_sym}
111
-
112
- ws = @connectors[service_key].action(action_id)
113
-
114
- handle_on_open(service_ref, 'Action', ws, params)
115
-
116
- ws.on :error do
117
- error 'Connection dropped while calling action'
118
- end
119
-
120
- ws.on :message do |event|
121
- action_response = JSON.parse(event.data)
122
- case action_response['type']
123
- when 'return'
124
- ws.close
125
- success "Action '#{service_ref}' responded"
126
- error_handle_call(action_response, &block)
127
- when 'fail'
128
- ws.close
129
- error " #{action_response['message']}"
130
- error "Action '#{service_ref}' failed"
131
- when 'log'
132
- action_response['message'] = " #{action_response['message']}"
133
- log_message(action_response)
134
- else
135
- error "Unknown action response: #{action_response}"
136
- end
137
- end
138
-
139
- ws.open
140
-
141
- @sockets << ws
142
- end
143
-
144
- private
145
-
146
- class DeepStruct < OpenStruct
147
- def initialize(hash=nil)
148
- @table = {}
149
- @hash_table = {}
150
-
151
- if hash
152
- hash.each do |k,v|
153
- @table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
154
- @hash_table[k.to_sym] = v
155
-
156
- new_ostruct_member(k)
157
- end
158
- end
159
- end
160
-
161
- def to_h
162
- @hash_table
163
- end
164
-
165
- def [](idx)
166
- hash = marshal_dump
167
- hash[idx.to_sym]
168
- end
169
- end
170
-
171
- def simple_object_convert(item)
172
- if item.is_a?(Hash)
173
- DeepStruct.new(item)
174
- elsif item.is_a?(Array)
175
- item.map do |i|
176
- simple_object_convert(i)
177
- end
178
- else
179
- item
180
- end
181
- end
182
-
183
- def flat_hash(h,f=[],g={})
184
- return g.update({ f=>h }) unless h.is_a? Hash
185
- h.each { |k,r| flat_hash(r,f+[k],g) }
186
- g
187
- end
188
-
189
- def handle_on_open(service_ref, dsl_type, ws, params)
190
- service_map = service_ref.split('::')
191
- service_id = service_map.first
192
-
193
- ws.on :open do
194
- params.merge!(@credentials[service_id.to_sym] || {})
195
- success "#{dsl_type.capitalize} '#{service_ref}' called"
196
- ws.send(params.to_json)
197
- end
198
- end
199
-
200
- def error_handle_call(listener_response, &block)
201
- content = simple_object_convert(listener_response['payload'])
202
- block.call(content) if block
203
- rescue => ex
204
- error "Error in workflow definition: #{ex.message}"
205
- ex.backtrace.each do |line|
206
- error " #{line}"
207
- end
208
- end
209
-
210
- def success(msg)
211
- log_message('type' => 'log', 'status' => 'success', 'message' => msg)
212
- end
213
-
214
- def warn(msg)
215
- log_message('type' => 'log', 'status' => 'warn', 'message' => msg)
216
- end
217
-
218
- def error(msg)
219
- log_message('type' => 'log', 'status' => 'error', 'message' => msg)
220
- end
221
-
222
- def info(msg)
223
- log_message('type' => 'log', 'status' => 'info', 'message' => msg)
224
- end
225
-
226
- def log_message(message_info)
227
- message_info['instance_id'] = @instance_id
228
- message_info['workflow_id'] = @id
229
- @logger.call(message_info) if @logger
230
- end
231
- end
232
- end
data/spec/base_spec.rb DELETED
@@ -1,102 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
- require 'tempfile'
5
- require 'yaml'
6
- require 'commander'
7
-
8
- describe Factor::Commands::Command do
9
- before :each do
10
- @command = Factor::Commands::Command.new
11
- end
12
-
13
- output_methods = %w(info warn error success)
14
-
15
- output_methods.each do |method_name|
16
- describe ".#{method_name}" do
17
- it "logs #{method_name}" do
18
-
19
- test_string = 'Hello World'
20
- output = capture_stdout do
21
- @command.method(method_name.to_sym).call message: test_string
22
- end
23
-
24
- expect(output).to include(test_string)
25
- expect(output).to include(method_name.upcase)
26
- end
27
- end
28
- end
29
-
30
- describe '.exception' do
31
- it 'logs exception' do
32
-
33
- test_string = 'Hello World'
34
- exception_string = 'Something be busted'
35
- output = capture_stdout do
36
- begin
37
- fail ArgumentError, exception_string
38
- rescue => ex
39
- @command.exception test_string, ex
40
- end
41
- end
42
-
43
- expect(output).to include(test_string)
44
- expect(output).to include(exception_string)
45
- expect(output).to include('ERROR')
46
-
47
- end
48
- end
49
-
50
- describe '.load_config' do
51
- it 'can load credentials and connectors' do
52
- credentials_file = Tempfile.new('credentials')
53
- connectors_file = Tempfile.new('connectors')
54
-
55
- credentials_content = {
56
- 'github' => {
57
- 'api_key' => 'fake_github_key'
58
- },
59
- 'heroku' => {
60
- 'api_key' => 'fake_heroku_key'
61
- }
62
- }
63
-
64
- connectors_content = {
65
- 'timer' => 'http://localhost:9294/v0.4/timer',
66
- 'web' => 'http://localhost:9294/v0.4/web',
67
- 'github' => 'http://localhost:9294/v0.4/github',
68
- 'heroku' => 'http://localhost:9294/v0.4/heroku'
69
- }
70
-
71
- credentials_file.write(YAML.dump(credentials_content))
72
- connectors_file.write(YAML.dump(connectors_content))
73
-
74
- credentials_file.rewind
75
- connectors_file.rewind
76
-
77
- options = Commander::Command::Options.new
78
- options.credentials = credentials_file.path
79
- options.connectors = connectors_file.path
80
-
81
- config_settings = {
82
- credentials: options.credentials,
83
- connectors: options.connectors
84
- }
85
-
86
- output = capture_stdout do
87
- @command.load_config config_settings
88
- end
89
-
90
- expect(configatron.credentials.github.api_key).to eq('fake_github_key')
91
- expect(configatron.credentials.heroku.api_key).to eq('fake_heroku_key')
92
- connectors_content.keys.each do |expected_connector_key|
93
- actual_connector = configatron.connectors[expected_connector_key]
94
- expected_connector = connectors_content[expected_connector_key]
95
- expect(actual_connector).to eq(expected_connector)
96
- end
97
-
98
- credentials_file.close
99
- connectors_file.close
100
- end
101
- end
102
- end
@@ -1,9 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Factor::Listener do
6
- it 'does stuff' do
7
- expect(true).to eq(true)
8
- end
9
- end
File without changes
@@ -1,11 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Factor::Commands::Workflow do
6
- describe '.server' do
7
- it 'can run a basic workflow' do
8
-
9
- end
10
- end
11
- end