factor 0.1.10 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/channel/listener.rb +1 -1
- data/lib/cli/channel_task.rb +18 -20
- data/lib/cli/command.rb +3 -3
- data/lib/cli/credential_task.rb +16 -8
- data/lib/cli/factor_task.rb +2 -4
- data/lib/cli/workflow_task.rb +22 -32
- data/lib/client/client.rb +42 -148
- metadata +2 -58
- data/lib/cli/server_task.rb +0 -82
- data/lib/runtime/attributes.rb +0 -26
- data/lib/runtime/engine.rb +0 -256
- data/lib/runtime/listener_message.rb +0 -42
- data/lib/runtime/message_bus.rb +0 -59
- data/lib/runtime/workflow.rb +0 -25
- data/lib/runtime/workflow_instance.rb +0 -28
- data/lib/runtime/workflow_step_messsage.rb +0 -63
data/lib/channel/listener.rb
CHANGED
data/lib/cli/channel_task.rb
CHANGED
@@ -1,36 +1,34 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'cli/command'
|
3
|
-
require 'zip/zip'
|
4
|
-
require 'zip/zipfilesystem'
|
5
3
|
|
6
4
|
module Factor
|
7
5
|
module CLI
|
8
6
|
class ChannelTask < Command
|
9
|
-
|
10
|
-
desc "call CHANNEL METHOD TARGET","start a workflow"
|
11
|
-
method_option :parameters, :type=>:hash, :default=>{}, :required=>false
|
12
|
-
def call(channel, method, target)
|
13
|
-
|
14
|
-
puts "not implemented"
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
7
|
desc "list", "list all the channels"
|
21
8
|
#method_option :key, :alias=>"-k", :type=>:string, :desc=>"key reference"
|
22
9
|
def list
|
23
|
-
|
10
|
+
@client.get_channels().each do |channel|
|
11
|
+
puts "#{channel['name']} (#{channel['slug']})"
|
12
|
+
puts " Listeners:" if channel['listeners'].count>0
|
13
|
+
channel['listeners'].each do |listener|
|
14
|
+
puts " #{listener['name']}: #{listener['description']}"
|
15
|
+
end
|
16
|
+
puts " Actions:" if channel['actions'].count>0
|
17
|
+
channel['actions'].each do |action|
|
18
|
+
puts " #{action['name']}: #{action['description']}"
|
19
|
+
end
|
20
|
+
end
|
24
21
|
end
|
25
22
|
|
26
|
-
desc "
|
27
|
-
|
28
|
-
|
23
|
+
desc "create DIRECTORY DEFINITION", "add a key and value for the credential"
|
24
|
+
method_option :organization, :alias=>"-o", :type=>:string, :desc=>"Organizoation to which this workflow belongs"
|
25
|
+
def create(directory,definition_file)
|
26
|
+
puts @client.create_channel(directory,definition_file,options[:organization])["notice"]
|
29
27
|
end
|
30
28
|
|
31
|
-
desc "
|
32
|
-
def
|
33
|
-
puts @client.
|
29
|
+
desc "delete NAME", "remove a workflow"
|
30
|
+
def delete(name)
|
31
|
+
puts @client.delete_channel(name)["notice"]
|
34
32
|
end
|
35
33
|
|
36
34
|
|
data/lib/cli/command.rb
CHANGED
@@ -16,7 +16,7 @@ module Factor
|
|
16
16
|
def initialize(*vals)
|
17
17
|
@config_file_dir = File.expand_path("~/.factor")
|
18
18
|
@client = Factor::Client::Client.new
|
19
|
-
@client.login_token(get_config[
|
19
|
+
@client.login_token(get_config['token'])
|
20
20
|
super(*vals)
|
21
21
|
end
|
22
22
|
|
@@ -24,7 +24,7 @@ module Factor
|
|
24
24
|
File.open(@config_file_dir,'w') do |file|
|
25
25
|
YAML::dump(config,file)
|
26
26
|
end
|
27
|
-
@client.login_token(get_config[
|
27
|
+
@client.login_token(get_config['token'])
|
28
28
|
end
|
29
29
|
|
30
30
|
def get_config
|
@@ -33,4 +33,4 @@ module Factor
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
data/lib/cli/credential_task.rb
CHANGED
@@ -6,24 +6,32 @@ module Factor
|
|
6
6
|
class CredentialTask < Command
|
7
7
|
|
8
8
|
|
9
|
-
desc "
|
9
|
+
desc "create SERVICE NAME VALUE", "add a key and value for the credential"
|
10
10
|
method_option :key, :type=>:string, :desc=>"File reference containing the symmetric key for encryption"
|
11
|
-
|
12
|
-
|
11
|
+
method_option :organization, :type=>:string, :desc=>"Organizoation to which this credential belongs"
|
12
|
+
def create(service,name,value)
|
13
|
+
secret=nil
|
13
14
|
if options[:key]
|
14
15
|
secret=File.read(options[:key])
|
15
16
|
end
|
16
|
-
puts @client.
|
17
|
+
puts @client.create_credential(service,name,value,secret,options[:organization])
|
17
18
|
end
|
18
19
|
|
19
20
|
desc "list", "get all of the credential"
|
20
21
|
def list()
|
21
|
-
|
22
|
+
@client.get_credentials["value"].each do |service,values|
|
23
|
+
# puts "#{credential['service']} : #{credential['name']} (#{credential['slug']}): #{credential['value']}"
|
24
|
+
puts "#{service}:"
|
25
|
+
values.each do |key,values|
|
26
|
+
# puts "#{key['value']} (#{value['slug']}) : #{value}"
|
27
|
+
puts " #{key} (#{values['slug']}): ***"
|
28
|
+
end
|
29
|
+
end
|
22
30
|
end
|
23
31
|
|
24
|
-
desc "
|
25
|
-
def
|
26
|
-
puts @client.
|
32
|
+
desc "delete SERVICE NAME", "remove a value from the credentials bag"
|
33
|
+
def delete(service,name)
|
34
|
+
puts @client.delete_credential(service,name)
|
27
35
|
end
|
28
36
|
|
29
37
|
end
|
data/lib/cli/factor_task.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'cli/command'
|
3
|
-
require 'cli/server_task'
|
4
3
|
require 'cli/workflow_task'
|
5
4
|
require 'cli/credential_task'
|
6
5
|
require 'cli/channel_task'
|
@@ -14,15 +13,14 @@ module Factor
|
|
14
13
|
# method_option :token, :alias=>"-t", :type=>:string, :desc=>"Token value to set", :required=>true
|
15
14
|
def login(email,token)
|
16
15
|
config = get_config
|
17
|
-
config[
|
18
|
-
config[
|
16
|
+
config['email']=email
|
17
|
+
config['token']=token
|
19
18
|
save_config(config)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
|
-
Factor::CLI::FactorTask.register(Factor::CLI::ServerTask, "server","server","start and list servers")
|
26
24
|
Factor::CLI::FactorTask.register(Factor::CLI::WorkflowTask,"workflow","workflow","start and list workflows")
|
27
25
|
Factor::CLI::FactorTask.register(Factor::CLI::ChannelTask,"channel","channel","install,uninstall, list channels")
|
28
26
|
Factor::CLI::FactorTask.register(Factor::CLI::CredentialTask,"credential","credential","manage remote credential store")
|
data/lib/cli/workflow_task.rb
CHANGED
@@ -4,53 +4,43 @@ require 'cli/command'
|
|
4
4
|
module Factor
|
5
5
|
module CLI
|
6
6
|
class WorkflowTask < Command
|
7
|
-
|
8
|
-
desc "
|
9
|
-
|
10
|
-
|
11
|
-
puts "starting workflow #{workflow_name} with options #{options.parameters.to_s}"
|
12
|
-
|
13
|
-
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
14
|
-
id = engine.send_start_workflow(workflow_name,options.parameters)
|
15
|
-
|
16
|
-
puts "workflow executed with id #{id}"
|
17
|
-
end
|
18
|
-
|
19
|
-
desc "listen WORKFLOW","start listener for workflow"
|
20
|
-
def listen(workflow_name)
|
21
|
-
puts "starting listener #{workflow_name}"
|
22
|
-
|
23
|
-
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
24
|
-
engine.send_start_listener(workflow_name)
|
7
|
+
|
8
|
+
desc "start WORKFLOW","start listener for workflow"
|
9
|
+
def start(workflow_name)
|
10
|
+
puts @client.start_workflow(workflow_name)["notice"]
|
25
11
|
end
|
26
12
|
|
27
13
|
desc "stop WORKFLOW","stop listener for workflow"
|
28
14
|
def stop(workflow_name)
|
29
|
-
puts
|
30
|
-
|
31
|
-
|
32
|
-
|
15
|
+
puts @client.stop_workflow(workflow_name)["notice"]
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "call WORKFLOW","call workflow"
|
19
|
+
method_option :parameters, :type=>:hash, :default=>{}, :required=>false
|
20
|
+
def call(workflow_name)
|
21
|
+
puts @client.call_workflow(workflow_name,options[:parameters])["notice"]
|
33
22
|
end
|
34
23
|
|
35
24
|
|
36
25
|
desc "list", "list all the workflows"
|
37
|
-
#method_option :key, :alias=>"-k", :type=>:string, :desc=>"key reference"
|
38
26
|
def list
|
39
|
-
|
27
|
+
@client.get_workflows().each do |workflow|
|
28
|
+
puts "#{workflow['name']} (#{workflow['slug']})"
|
29
|
+
end
|
40
30
|
end
|
41
31
|
|
42
|
-
desc "
|
32
|
+
desc "create NAME FILENAME", "add a key and value for the credential"
|
43
33
|
#method_option :key, :alias=>"-k", :type=>:string, :desc=>"key reference"
|
44
|
-
|
45
|
-
def
|
34
|
+
method_option :organization, :alias=>"-v", :type=>:string, :desc=>"Organizoation to which this workflow belongs"
|
35
|
+
def create(name,filename)
|
46
36
|
contents=File.open(File.expand_path(filename), "rb") {|f| f.read}
|
47
|
-
puts @client.
|
37
|
+
puts @client.create_workflow(name,contents,options[:organization])["notice"]
|
48
38
|
end
|
49
39
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
40
|
+
desc "delete NAME", "remove a workflow"
|
41
|
+
def delete(name)
|
42
|
+
puts @client.delete_workflow(name)
|
43
|
+
end
|
54
44
|
|
55
45
|
|
56
46
|
|
data/lib/client/client.rb
CHANGED
@@ -7,6 +7,7 @@ require 'open-uri'
|
|
7
7
|
require 'digest/sha2'
|
8
8
|
require 'openssl'
|
9
9
|
require 'base64'
|
10
|
+
require 'json'
|
10
11
|
|
11
12
|
|
12
13
|
module Factor
|
@@ -19,102 +20,11 @@ module Factor
|
|
19
20
|
@host=host
|
20
21
|
end
|
21
22
|
|
22
|
-
def register(email,password)
|
23
|
-
end
|
24
|
-
|
25
|
-
def login(email, password)
|
26
|
-
end
|
27
|
-
|
28
23
|
def login_token(token)
|
29
24
|
@token=token
|
30
25
|
end
|
31
26
|
|
32
|
-
def
|
33
|
-
code.call("downloading workflow list")
|
34
|
-
workflows = rest_get("workflows")
|
35
|
-
code.call("downloaded #{workflows.size} workflows")
|
36
|
-
workflows.each do |workflow_info|
|
37
|
-
code.call("parsing '#{workflow_info['name']}'")
|
38
|
-
workflow_definition = JSON.parse(workflow_info['definition'])
|
39
|
-
code.call("loading '#{workflow_info['name']}' into runtime")
|
40
|
-
workflow=Factor::Runtime::Workflow.new(workflow_definition)
|
41
|
-
engine.load_workflow(workflow)
|
42
|
-
code.call("loading complete for '#{workflow_info['name']}'")
|
43
|
-
end
|
44
|
-
engine
|
45
|
-
end
|
46
|
-
|
47
|
-
def load_credentials(engine,secret=nil,&code)
|
48
|
-
code.call("downloading credential list")
|
49
|
-
credentials = rest_get("credentials")["value"]
|
50
|
-
code.call("loading credentials")
|
51
|
-
|
52
|
-
if secret
|
53
|
-
code.call("decrypting credentials")
|
54
|
-
decrypter = OpenSSL::Cipher.new("AES-256-CFB")
|
55
|
-
sha256= Digest::SHA2.new(256)
|
56
|
-
decrypter.key=Base64.encode64(sha256.digest(secret))
|
57
|
-
decrypter.decrypt
|
58
|
-
credentials.each do |service,creds|
|
59
|
-
creds.each do |credential,value|
|
60
|
-
if value["encrypted"]
|
61
|
-
decrypted = decrypter.update(Base64.decode64(value["value"])) + decrypter.final
|
62
|
-
credentials[service][credential]["value"]=decrypted
|
63
|
-
credentials[service][credential]["encrypted"]=false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
code.call("decrypting credentials complete")
|
68
|
-
end
|
69
|
-
|
70
|
-
engine.load_credentials(credentials)
|
71
|
-
|
72
|
-
engine
|
73
|
-
end
|
74
|
-
|
75
|
-
def load_channels(engine,&code)
|
76
|
-
|
77
|
-
# get list of channels
|
78
|
-
code.call("downloading channels list")
|
79
|
-
channels = rest_get("channels")
|
80
|
-
|
81
|
-
#load each channel
|
82
|
-
channels.each do |channel|
|
83
|
-
if !channel['zip_url'].empty?
|
84
|
-
code.call("downloading '#{channel['zip_url']}'")
|
85
|
-
# URI of the zip file containing the module
|
86
|
-
uri = URI.parse(channel['zip_url'])
|
87
|
-
|
88
|
-
# temp file to store the zip for download
|
89
|
-
#temp_file = Tempfile.new([uri.path.gsub(/\W+/,'-'), '.zip'], :encoding => 'ascii-8bit')
|
90
|
-
temp_file = Tempfile.new([uri.to_s.gsub(/\W+/,'-'), '.zip'])
|
91
|
-
|
92
|
-
# temp directory where zip will be decompressed
|
93
|
-
unzip_dir=temp_file.path[0..-5]
|
94
|
-
|
95
|
-
# download
|
96
|
-
open(uri.to_s,"rb") do |bin|
|
97
|
-
temp_file.print bin.read
|
98
|
-
end
|
99
|
-
temp_file.close
|
100
|
-
|
101
|
-
code.call("unzipping '#{channel['name']}'")
|
102
|
-
# unzip download zip into unzipped directory
|
103
|
-
unzip(temp_file.path,unzip_dir)
|
104
|
-
|
105
|
-
filename = unzip_dir + "/" + channel['module_name'].split(/(?=[A-Z])/).map{ |x| x.downcase }.join('_') + ".rb"
|
106
|
-
|
107
|
-
code.call("loading '#{channel["name"]}' into engine")
|
108
|
-
engine.load_channel(filename, channel)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
engine
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
def set_credential(service,name,value,secret=nil)
|
27
|
+
def create_credential(service,name,value,secret=nil,organization=nil)
|
118
28
|
# this is a PUT not POST because it is technically editing, not creating a new one
|
119
29
|
credential = {:service=>service,:name=>name,:value=>value}
|
120
30
|
|
@@ -129,49 +39,65 @@ module Factor
|
|
129
39
|
credential[:value]=encrypted
|
130
40
|
credential[:encrypted]=true
|
131
41
|
end
|
132
|
-
|
133
|
-
rest_post(
|
42
|
+
path = !!organization ? "organizations/#{organization}/credentials" : "credentials"
|
43
|
+
rest_post(path,credential)
|
134
44
|
end
|
135
45
|
|
136
46
|
def get_credentials()
|
137
47
|
rest_get("credentials")
|
138
48
|
end
|
139
49
|
|
140
|
-
def
|
50
|
+
def delete_credential(service,name)
|
141
51
|
rest_delete("credentials",{:service=>service,:name=>name})
|
142
52
|
end
|
143
53
|
|
144
54
|
|
145
55
|
|
146
56
|
|
147
|
-
#
|
148
|
-
def
|
149
|
-
|
57
|
+
# untested
|
58
|
+
def create_workflow(key,definition,organization=nil)
|
59
|
+
path = !!organization ? "organizations/#{organization}/workflows" : "workflows"
|
60
|
+
rest_post(path,{:workflow=>{:name=>key,:definition=>definition}})
|
150
61
|
end
|
151
62
|
|
152
63
|
def get_workflows()
|
153
64
|
rest_get("workflows")
|
154
65
|
end
|
155
66
|
|
156
|
-
|
157
|
-
|
158
|
-
|
67
|
+
def delete_workflow(workflow_name)
|
68
|
+
rest_delete("workflows/#{workflow_name}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def start_workflow(workflow_name)
|
72
|
+
rest_get("workflows/#{workflow_name}/state")
|
73
|
+
end
|
74
|
+
|
75
|
+
def stop_workflow(workflow_name)
|
76
|
+
rest_delete("workflows/#{workflow_name}/state")
|
77
|
+
end
|
78
|
+
|
79
|
+
def call_workflow(workflow_name,params)
|
80
|
+
rest_get("workflows/#{workflow_name}/call",params)
|
81
|
+
end
|
82
|
+
|
159
83
|
|
160
84
|
|
161
85
|
# channels
|
162
|
-
def
|
86
|
+
def create_channel(path,definition_file,organization=nil)
|
163
87
|
file=zip(File.expand_path(path))
|
164
88
|
definition = File.read(definition_file)
|
165
|
-
|
89
|
+
|
90
|
+
path = !!organization ? "organizations/#{organization}/channels" : "channels"
|
91
|
+
rest_post(path,{:zip=>file,:channel=>{:definition=>definition}})
|
166
92
|
end
|
167
93
|
|
168
94
|
def get_channels()
|
169
95
|
rest_get("channels")
|
170
96
|
end
|
171
97
|
|
172
|
-
|
173
|
-
|
174
|
-
|
98
|
+
def delete_channel(channel_name)
|
99
|
+
rest_delete("channels/#{channel_name}")
|
100
|
+
end
|
175
101
|
|
176
102
|
|
177
103
|
|
@@ -180,37 +106,6 @@ module Factor
|
|
180
106
|
|
181
107
|
private
|
182
108
|
|
183
|
-
def fix_github_zip_archive(file)
|
184
|
-
Zip::ZipFile.open(file.path) do |zip|
|
185
|
-
basedir = zip.entries.first.name
|
186
|
-
zip.remove zip.entries.first
|
187
|
-
zip.each do |entry|
|
188
|
-
target = entry.name.sub(/^#{basedir}/,'')
|
189
|
-
if entry.directory?
|
190
|
-
zip.dir.mkdir(target)
|
191
|
-
else
|
192
|
-
zip.file.open(entry.name) do |istream|
|
193
|
-
zip.file.open(target, 'w') do |ostream|
|
194
|
-
ostream.write istream.read
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
zip.remove entry
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def unzip(zip, unzip_dir, remove_after = false)
|
204
|
-
Zip::ZipFile.open(zip) do |zip_file|
|
205
|
-
zip_file.each do |f|
|
206
|
-
f_path=File.join(unzip_dir, f.name)
|
207
|
-
FileUtils.mkdir_p(File.dirname(f_path))
|
208
|
-
zip_file.extract(f, f_path) unless File.exist?(f_path)
|
209
|
-
end
|
210
|
-
end
|
211
|
-
FileUtils.rm(zip) if remove_after
|
212
|
-
end
|
213
|
-
|
214
109
|
def zip(directory)
|
215
110
|
path=directory.dup
|
216
111
|
path.sub!(%r[/$],'')
|
@@ -223,35 +118,34 @@ module Factor
|
|
223
118
|
end
|
224
119
|
File.open(zip_path,'r')
|
225
120
|
end
|
226
|
-
|
121
|
+
|
227
122
|
def rest_get(path,params={})
|
228
123
|
params["auth_token"]=@token
|
229
124
|
|
230
125
|
param_string=params.map{|key,value| "#{key}=#{value}"}.join("&")
|
231
|
-
|
232
|
-
JSON.parse(
|
126
|
+
response=RestClient.get("http://#{@host}/#{path}.json?#{param_string}")
|
127
|
+
JSON.parse(response)
|
233
128
|
end
|
234
129
|
|
235
130
|
def rest_put(path,params={})
|
236
131
|
params["auth_token"]=@token
|
237
|
-
|
238
|
-
JSON.parse(
|
132
|
+
response=RestClient.put("http://#{@host}/#{path}.json",params)
|
133
|
+
JSON.parse(response)
|
239
134
|
end
|
240
135
|
|
241
136
|
def rest_post(path,params={})
|
242
|
-
|
243
|
-
|
244
|
-
JSON.parse(RestClient.post("http://#{@host}/#{path}.json?auth_token=#{@token}",params))
|
137
|
+
response=RestClient.post("http://#{@host}/#{path}.json?auth_token=#{@token}",params)
|
138
|
+
JSON.parse(response)
|
245
139
|
end
|
246
140
|
|
247
141
|
def rest_delete(path,params={})
|
248
142
|
params["auth_token"]=@token
|
249
143
|
|
250
144
|
param_string=params.map{|key,value| "#{key}=#{value}"}.join("&")
|
251
|
-
|
252
|
-
JSON.parse(
|
145
|
+
response=RestClient.delete("http://#{@host}/#{path}.json?#{param_string}")
|
146
|
+
JSON.parse(response)
|
253
147
|
end
|
254
148
|
|
255
149
|
end
|
256
150
|
end
|
257
|
-
end
|
151
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -59,38 +59,6 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 2.0.2
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: mustache
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ! '>='
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 0.99.4
|
70
|
-
type: :runtime
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ! '>='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 0.99.4
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: eventmachine
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ! '>='
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: 0.12.10
|
86
|
-
type: :runtime
|
87
|
-
prerelease: false
|
88
|
-
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ! '>='
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: 0.12.10
|
94
62
|
- !ruby/object:Gem::Dependency
|
95
63
|
name: json
|
96
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,22 +75,6 @@ dependencies:
|
|
107
75
|
- - ! '>='
|
108
76
|
- !ruby/object:Gem::Version
|
109
77
|
version: 1.7.6
|
110
|
-
- !ruby/object:Gem::Dependency
|
111
|
-
name: amqp
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
|
-
requirements:
|
115
|
-
- - ! '>='
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: 0.9.8
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
|
-
requirements:
|
123
|
-
- - ! '>='
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: 0.9.8
|
126
78
|
description: Friendly command-line interface and library for Factor
|
127
79
|
email: maciej@factor.io
|
128
80
|
executables:
|
@@ -139,17 +91,9 @@ files:
|
|
139
91
|
- lib/cli/command.rb
|
140
92
|
- lib/cli/credential_task.rb
|
141
93
|
- lib/cli/factor_task.rb
|
142
|
-
- lib/cli/server_task.rb
|
143
94
|
- lib/cli/workflow_task.rb
|
144
95
|
- lib/client/client.rb
|
145
96
|
- lib/factor.rb
|
146
|
-
- lib/runtime/attributes.rb
|
147
|
-
- lib/runtime/engine.rb
|
148
|
-
- lib/runtime/listener_message.rb
|
149
|
-
- lib/runtime/message_bus.rb
|
150
|
-
- lib/runtime/workflow.rb
|
151
|
-
- lib/runtime/workflow_instance.rb
|
152
|
-
- lib/runtime/workflow_step_messsage.rb
|
153
97
|
- bin/factor
|
154
98
|
homepage: http://rubygems.org/gems/factor
|
155
99
|
licenses: []
|
@@ -172,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
116
|
version: '0'
|
173
117
|
requirements: []
|
174
118
|
rubyforge_project:
|
175
|
-
rubygems_version: 1.8.
|
119
|
+
rubygems_version: 1.8.25
|
176
120
|
signing_key:
|
177
121
|
specification_version: 3
|
178
122
|
summary: Factor.io Library and CLI
|
data/lib/cli/server_task.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'cli/command'
|
3
|
-
|
4
|
-
module Factor
|
5
|
-
module CLI
|
6
|
-
class ServerTask < Command
|
7
|
-
desc "start", "start the server"
|
8
|
-
method_option :tags, :alias=>"-t", :type=>:hash, :desc=>"Optional tags to identify from workflow"
|
9
|
-
method_option :channels, :type=>:array, :desc=>"Optional channel ruby file list for development"
|
10
|
-
method_option :verbose, :type=>:boolean, :desc=>"Display everything"
|
11
|
-
method_option :key, :type=>:string, :desc=>"File reference containing the symmetric key for encryption"
|
12
|
-
def start
|
13
|
-
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
14
|
-
|
15
|
-
options.tags.each {|tag,value| engine.tag(tag,value)} if options.tags?
|
16
|
-
|
17
|
-
# load channels from server
|
18
|
-
say "loading channels from server" if options.verbose?
|
19
|
-
engine = @client.load_channels(engine) do |message|
|
20
|
-
say " #{message}" if options.verbose?
|
21
|
-
end
|
22
|
-
|
23
|
-
# load channels from files
|
24
|
-
if options.channels?
|
25
|
-
options.channels.each do |file|
|
26
|
-
full_file=File.expand_path(file)
|
27
|
-
say " loading '#{full_file}'" if options.verbose?
|
28
|
-
engine.load_channel(full_file)
|
29
|
-
say " loaded '#{full_file}'" if options.verbose?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
say "loading channels complete" if options.verbose?
|
34
|
-
|
35
|
-
|
36
|
-
# load workflows from server
|
37
|
-
say "loading workflows from server" if options.verbose?
|
38
|
-
engine = @client.load_workflows(engine) do |message|
|
39
|
-
say " #{message}" if options.verbose?
|
40
|
-
end
|
41
|
-
say "loading workflows complete" if options.verbose?
|
42
|
-
|
43
|
-
say "loading credentials from server" if options.verbose?
|
44
|
-
securet=nil
|
45
|
-
if options[:key]
|
46
|
-
secret=File.read(options[:key])
|
47
|
-
end
|
48
|
-
engine = @client.load_credentials(engine,secret) do |message|
|
49
|
-
say " #{message}" if options.verbose?
|
50
|
-
end
|
51
|
-
say "loading credentials complete" if options.verbose?
|
52
|
-
|
53
|
-
say "starting the server...", :green
|
54
|
-
message = engine.start
|
55
|
-
if message.is_a?(Exception)
|
56
|
-
say "[Unknown exception]", :red
|
57
|
-
say " message:#{message}", :red
|
58
|
-
say " backtrace:", :red
|
59
|
-
message.backtrace.each {|line| say " #{line}", :red}
|
60
|
-
else
|
61
|
-
say "disconnecting...", :green
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
desc "list", "list all the running servers"
|
67
|
-
def list
|
68
|
-
say "listing all servers"
|
69
|
-
end
|
70
|
-
|
71
|
-
desc "logs", "listen to incoming logs"
|
72
|
-
def logs
|
73
|
-
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
74
|
-
say "Listening...", :green
|
75
|
-
engine.logs do |message|
|
76
|
-
say "[#{message.route}] #{JSON.pretty_generate(message.body)}"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
data/lib/runtime/attributes.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
module Factor
|
4
|
-
module Runtime
|
5
|
-
|
6
|
-
class Attributes < Hash
|
7
|
-
|
8
|
-
private
|
9
|
-
def map_values(map,values)
|
10
|
-
params=Hash.new
|
11
|
-
map.each do |key,reference|
|
12
|
-
params[key]=values[reference]
|
13
|
-
end
|
14
|
-
params
|
15
|
-
end
|
16
|
-
|
17
|
-
def format_map(parent,map)
|
18
|
-
newmap=Hash.new
|
19
|
-
map.each do |key,value|
|
20
|
-
newmap["#{parent}::#{key}"]=value
|
21
|
-
end
|
22
|
-
newmap
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/runtime/engine.rb
DELETED
@@ -1,256 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'factor'
|
3
|
-
require 'mustache'
|
4
|
-
#require 'facter'
|
5
|
-
|
6
|
-
|
7
|
-
module Factor
|
8
|
-
module Runtime
|
9
|
-
class Engine
|
10
|
-
attr_accessor :channel_modules, :workflows, :message_bus, :listeners
|
11
|
-
|
12
|
-
# Engine needs modules that contain the code, workflows to run, and message bus for communication
|
13
|
-
def initialize(username,token)
|
14
|
-
@channel_modules={}
|
15
|
-
@channel_definitions=[]
|
16
|
-
@workflows = {}
|
17
|
-
@message_bus = MessageBus.new(username,token)
|
18
|
-
@credentials = {}
|
19
|
-
@tags = {}
|
20
|
-
@listeners={}
|
21
|
-
end
|
22
|
-
|
23
|
-
def tag(key,value)
|
24
|
-
@tags[key]=value
|
25
|
-
end
|
26
|
-
|
27
|
-
# load the channel by referencing the .rb file
|
28
|
-
# the filename is lowercase with "_" for spaces
|
29
|
-
# and the module inside must be camal cased to match
|
30
|
-
# once loaded it is in the channel_modules Hash
|
31
|
-
def load_channel filename, definition
|
32
|
-
filename = File.absolute_path(File.expand_path(filename.path)) if filename.is_a?(File) # just in case someone passes in a File not a String (i.e. me)
|
33
|
-
require filename
|
34
|
-
# channel_module_name = File.basename(filename).gsub('.rb','').split('_').map{|ea| ea.capitalize}.join('')
|
35
|
-
channel_module_name = definition['module_name']
|
36
|
-
channel_module= self.class.const_get(channel_module_name)
|
37
|
-
@channel_modules[channel_module_name]=channel_module
|
38
|
-
@channel_definitions << definition
|
39
|
-
end
|
40
|
-
|
41
|
-
def load_credentials credentials,secret=nil
|
42
|
-
credentials.each do |service_name,services|
|
43
|
-
@credentials[service_name] = {} if !@credentials.include?(service_name)
|
44
|
-
services.each do |credential_name,credential|
|
45
|
-
@credentials[service_name][credential_name] = credential["value"]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# @credentials["credentials"] = credentials
|
50
|
-
end
|
51
|
-
|
52
|
-
# adds the workflow to the workflows list
|
53
|
-
# the object must be a Workflow type
|
54
|
-
def load_workflow workflow
|
55
|
-
@workflows[workflow.name] = workflow
|
56
|
-
end
|
57
|
-
|
58
|
-
def logs routing_key="#", &code
|
59
|
-
@message_bus.start do
|
60
|
-
@message_bus.listen routing_key do |message|
|
61
|
-
code.call message
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def send_start_workflow workflow, params, keep_open=false
|
67
|
-
instance_id=SecureRandom.hex
|
68
|
-
|
69
|
-
@message_bus.start do
|
70
|
-
message = WorkflowStepMessage.new
|
71
|
-
message.position << "start"
|
72
|
-
message.workflow=workflow
|
73
|
-
message.add_values params
|
74
|
-
message.workflow_instance_id= instance_id
|
75
|
-
@message_bus.send message, !keep_open
|
76
|
-
end
|
77
|
-
instance_id
|
78
|
-
end
|
79
|
-
|
80
|
-
def send_start_listener workflow_name, keep_open=false
|
81
|
-
@message_bus.start do
|
82
|
-
message = ListenerMessage.new("start",workflow_name)
|
83
|
-
@message_bus.send message, !keep_open
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def send_stop_listener workflow_name, keep_open=false
|
88
|
-
@message_bus.start do
|
89
|
-
message = ListenerMessage.new("stop",workflow_name)
|
90
|
-
@message_bus.send message, !keep_open
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# start your engines. vroom vrooooom!
|
95
|
-
def start
|
96
|
-
begin
|
97
|
-
@message_bus.start do
|
98
|
-
@message_bus.listen("listener") do |payload|
|
99
|
-
message = ListenerMessage.new
|
100
|
-
message.from_queue(payload)
|
101
|
-
|
102
|
-
listener=@workflows[message.workflow].definition["listener"]
|
103
|
-
params = render_template(listener["params"],@credentials)
|
104
|
-
|
105
|
-
if message.command=="start"
|
106
|
-
start_listening(listener["channel"],listener["name"],listener["event"],message.workflow,params)
|
107
|
-
else
|
108
|
-
stop_listening(listener["channel"],listener["name"],listener["event"],message.workflow)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
@message_bus.listen("workflow") do |payload|
|
113
|
-
step = WorkflowStepMessage.new
|
114
|
-
step.from_queue(payload)
|
115
|
-
if @workflows.include? step.workflow
|
116
|
-
workflow = @workflows[step.workflow]
|
117
|
-
activity = workflow.get_activity(step.position)
|
118
|
-
if !activity.nil?
|
119
|
-
action = activity["action"]
|
120
|
-
channel = activity["channel"]
|
121
|
-
target = activity["target"]
|
122
|
-
params_template = activity["params"]
|
123
|
-
|
124
|
-
# if match(target)
|
125
|
-
values = step.body.merge(@credentials)
|
126
|
-
# puts "Values: #{values.inspect}"
|
127
|
-
|
128
|
-
# this maps the input values passed in with the templated defined in the workflow
|
129
|
-
params = render_template(params_template,values)
|
130
|
-
puts "content: #{params}"
|
131
|
-
event = call_channel_method(channel,action,params)
|
132
|
-
response_message = step.respond(event.params,event.class.name.split("::").last)
|
133
|
-
|
134
|
-
@message_bus.send response_message
|
135
|
-
# end
|
136
|
-
else
|
137
|
-
puts "[error] no activity found for position '#{step.position}'"
|
138
|
-
end
|
139
|
-
else
|
140
|
-
# workflow doesn't exist
|
141
|
-
puts "[warning] '#{step.workflow}' workflow wasn't found"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
rescue SystemExit, Interrupt
|
146
|
-
puts "done"
|
147
|
-
rescue Exception => ex
|
148
|
-
puts ex
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def call_channel_method(channel_name,action_name,params)
|
153
|
-
channel_module_name = get_channel_module(channel_name)
|
154
|
-
channel_module = @channel_modules[channel_module_name]
|
155
|
-
action_class_name = get_class_name("actions",channel_name,action_name)
|
156
|
-
command = channel_module.const_get(action_class_name)
|
157
|
-
command.new.do_work(params)
|
158
|
-
end
|
159
|
-
|
160
|
-
def start_listening(channel_name,listener_name,event,workflow_name,params)
|
161
|
-
channel_module_name = get_channel_module(channel_name)
|
162
|
-
channel_module = @channel_modules[channel_module_name]
|
163
|
-
listener_class_name = get_class_name("listeners",channel_name,listener_name)
|
164
|
-
command = channel_module.const_get(listener_class_name)
|
165
|
-
job_info = {:channel_name=>channel_name,:listener_name=>listener_name,:workflow_name=>workflow_name,:event=>event}.to_json
|
166
|
-
|
167
|
-
@job = Thread.new do
|
168
|
-
puts "Creating listener #{channel_name}::#{listener_name} on event '#{event}' => #{workflow_name}"
|
169
|
-
listener=command.new(workflow_name,event)
|
170
|
-
|
171
|
-
puts "Starting listener thread #{params}"
|
172
|
-
listener.start params do |event_params|
|
173
|
-
send_start_workflow workflow_name, event_params
|
174
|
-
end
|
175
|
-
end
|
176
|
-
@listeners[job_info]=@job
|
177
|
-
end
|
178
|
-
|
179
|
-
def stop_listening(channel_name,listener_name,event,workflow_name)
|
180
|
-
# channel_module_name = get_channel_module(channel_name)
|
181
|
-
# channel_module = @channel_modules[channel_module_name]
|
182
|
-
# listener_class = get_class_name("listeners",channel_name,listener_name)
|
183
|
-
# command = channel_module.const_get(listener_name)
|
184
|
-
job_info = {:channel_name=>channel_name,:listener_name=>listener_name,:workflow_name=>workflow_name,:event=>event}.to_json
|
185
|
-
|
186
|
-
@listeners[job_info].kill if @listeners.include?(job_info)
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
private
|
191
|
-
|
192
|
-
def get_channel_module(channel_name)
|
193
|
-
@channel_definitions.select { |channel_definition| channel_definition['name']==channel_name }.first['module_name']
|
194
|
-
end
|
195
|
-
|
196
|
-
# def get_action_class(channel_name,action_name)
|
197
|
-
# @channel_definitions.each do |channel_definition|
|
198
|
-
# if channel_definition['name']==channel_name
|
199
|
-
# channel_definition['actions'].each do |action|
|
200
|
-
# return action["class_name"] if action['name']==action_name
|
201
|
-
# end
|
202
|
-
# end
|
203
|
-
# end
|
204
|
-
# end
|
205
|
-
|
206
|
-
# def get_listener_class(channel_name,listener_name)
|
207
|
-
# @channel_definitions.each do |channel_definition|
|
208
|
-
# if channel_definition['name']==channel_name
|
209
|
-
# channel_definition['listeners'].each do |listener|
|
210
|
-
# return listener["class_name"] if listener['name']==listener_name
|
211
|
-
# end
|
212
|
-
# end
|
213
|
-
# end
|
214
|
-
# end
|
215
|
-
|
216
|
-
def get_class_name(type,channel_name,class_name)
|
217
|
-
@channel_definitions.each do |channel_definition|
|
218
|
-
if channel_definition['name']==channel_name
|
219
|
-
channel_definition[type].each do |definition|
|
220
|
-
return definition["class_name"] if definition['name']==class_name
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def render_template(source,values)
|
227
|
-
#params = Hash.new
|
228
|
-
|
229
|
-
if source.is_a?(Hash)
|
230
|
-
params = Hash.new
|
231
|
-
source.each do |key,template|
|
232
|
-
params[key]=render_template(template,values)
|
233
|
-
end
|
234
|
-
else
|
235
|
-
params = Mustache.render(source,values)
|
236
|
-
end
|
237
|
-
|
238
|
-
# activity_params.each do |key,template|
|
239
|
-
# params[key]=Mustache.render(template,values)
|
240
|
-
# end
|
241
|
-
params
|
242
|
-
end
|
243
|
-
|
244
|
-
# def match(target)
|
245
|
-
# return true if target==nil || target==""
|
246
|
-
# facts={}
|
247
|
-
# #Facter.each {|k,v| facts[k]=v}
|
248
|
-
# @tags.each {|k,v| facts[k]=v}
|
249
|
-
# key,value=target.split("=")
|
250
|
-
# facts[key]==value
|
251
|
-
# end
|
252
|
-
|
253
|
-
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'json/ext'
|
3
|
-
|
4
|
-
module Factor
|
5
|
-
module Runtime
|
6
|
-
class ListenerMessage
|
7
|
-
attr_accessor :command,:workflow
|
8
|
-
def initialize(command=nil,workflow=nil)
|
9
|
-
@command=command
|
10
|
-
@workflow=workflow
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def route
|
15
|
-
# "#{workflow}.#{position.join('.')}"
|
16
|
-
"listener"
|
17
|
-
end
|
18
|
-
|
19
|
-
def payload
|
20
|
-
JSON.generator = JSON::Ext::Generator
|
21
|
-
obj = {"command"=>@command, "workflow"=>@workflow}
|
22
|
-
JSON.generate(obj)
|
23
|
-
end
|
24
|
-
|
25
|
-
def from_queue payload
|
26
|
-
message=JSON.parse(payload)
|
27
|
-
@command=message["command"]
|
28
|
-
@workflow=message["workflow"]
|
29
|
-
end
|
30
|
-
# def from_queue payload
|
31
|
-
#
|
32
|
-
# @workflow = message["workflow"]
|
33
|
-
# @position=message["position"]
|
34
|
-
# @body=message["body"]
|
35
|
-
# @workflow_instance_id=message["workflow_instance_id"]
|
36
|
-
# @step_id=message["step_id"]
|
37
|
-
# @last_step_id=message["last_step_id"]
|
38
|
-
# end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/runtime/message_bus.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'amqp'
|
4
|
-
|
5
|
-
module Factor
|
6
|
-
module Runtime
|
7
|
-
class MessageBus
|
8
|
-
attr_accessor :host, :vhost, :username, :token, :connection, :channel, :exchange, :queue
|
9
|
-
|
10
|
-
def initialize(email,token)
|
11
|
-
@host = "queue.factor.io"
|
12
|
-
@vhost = email
|
13
|
-
@username=email
|
14
|
-
@token=token
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
# Creates the connection and creates a topic exchange
|
19
|
-
# An exchange references a place to send messages to
|
20
|
-
# the exchange routes it to the queues based on the route_key
|
21
|
-
def start(topic="factor",&code)
|
22
|
-
EventMachine.run do
|
23
|
-
#connection_settings={:host=>@host,:user=>@username,:password=>@token,:vhost=>@vhost}
|
24
|
-
connection_settings={:host=>@host}
|
25
|
-
@connection = AMQP.connect(connection_settings)
|
26
|
-
@channel = AMQP::Channel.new(connection)
|
27
|
-
@exchange = @channel.topic(topic,:auto_delete=>true) # new topic exchange
|
28
|
-
code.call
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# creates a new queue to listen to the topic exchange
|
33
|
-
def listen(routing_key="#",&code)
|
34
|
-
queue_name=SecureRandom.hex
|
35
|
-
@queue = @channel.queue(queue_name)
|
36
|
-
@queue.bind(@exchange, :routing_key=>routing_key) # bind queue to the Exchange
|
37
|
-
|
38
|
-
@queue.subscribe do |headers,payload|
|
39
|
-
# code.call(headers.routing_key,payload)
|
40
|
-
puts "[Received Message (#{headers.routing_key})] #{payload.inspect}"
|
41
|
-
code.call(payload)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def send(message,close=false)
|
46
|
-
puts "[Sending Message (#{message.route})] #{message.payload.inspect}"
|
47
|
-
@exchange.publish(message.payload,:routing_key => message.route)
|
48
|
-
EM.add_timer(1, Proc.new { close}) if close
|
49
|
-
end
|
50
|
-
|
51
|
-
def close
|
52
|
-
@connection.close{ EventMachine.stop }
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
data/lib/runtime/workflow.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
module Factor
|
4
|
-
module Runtime
|
5
|
-
class Workflow
|
6
|
-
attr_accessor :definition
|
7
|
-
attr_reader :name
|
8
|
-
|
9
|
-
def initialize(definition)
|
10
|
-
@definition=definition
|
11
|
-
@name = @definition["name"]
|
12
|
-
end
|
13
|
-
|
14
|
-
def get_activity(position)
|
15
|
-
last_position=@definition
|
16
|
-
position.each do |section|
|
17
|
-
return nil if last_position[section].nil?
|
18
|
-
last_position=last_position[section]
|
19
|
-
end
|
20
|
-
last_position
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
module Factor
|
4
|
-
module Runtime
|
5
|
-
class WorkflowInstance
|
6
|
-
attr_accessor :id, :attributes, :start_message, :workflow
|
7
|
-
|
8
|
-
def initialize(workflow,attributes)
|
9
|
-
@id=SecureRandom.hex
|
10
|
-
@attributes = attributes
|
11
|
-
@workflow = workflow
|
12
|
-
@start_message = Message.new(@attributes)
|
13
|
-
@start_message.workflow_instance_id=@id
|
14
|
-
@start_message.position=["start"]
|
15
|
-
end
|
16
|
-
|
17
|
-
def get_activity(position)
|
18
|
-
last_position=@workflow
|
19
|
-
position.each do |section|
|
20
|
-
return nil if last_position[section].nil?
|
21
|
-
last_position=last_position[section]
|
22
|
-
end
|
23
|
-
last_position
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'json/ext'
|
3
|
-
|
4
|
-
module Factor
|
5
|
-
module Runtime
|
6
|
-
class WorkflowStepMessage
|
7
|
-
attr_accessor :body, :workflow, :workflow_instance_id, :step_id, :last_step_id, :position
|
8
|
-
def initialize
|
9
|
-
@step_id=SecureRandom.hex
|
10
|
-
# @workflow = workflow
|
11
|
-
@body = Hash.new
|
12
|
-
@position = Array.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def respond(params, event)
|
16
|
-
m = WorkflowStepMessage.new
|
17
|
-
m.body = @body
|
18
|
-
m.workflow_instance_id=@workflow_instance_id
|
19
|
-
m.last_step_id = @step_id
|
20
|
-
m.workflow = @workflow
|
21
|
-
m.position = @position
|
22
|
-
m.position << "on"
|
23
|
-
m.position << event
|
24
|
-
m.add_values(params)
|
25
|
-
m
|
26
|
-
end
|
27
|
-
|
28
|
-
def add_values(values)
|
29
|
-
current=@body
|
30
|
-
position.each do |key|
|
31
|
-
current[key]={} if !current.include?(key)
|
32
|
-
current=current[key]
|
33
|
-
end
|
34
|
-
values.each do |key,value|
|
35
|
-
current[key]=value
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def route
|
41
|
-
# "#{workflow}.#{position.join('.')}"
|
42
|
-
"workflow"
|
43
|
-
end
|
44
|
-
|
45
|
-
def payload
|
46
|
-
JSON.generator = JSON::Ext::Generator
|
47
|
-
obj = {"body"=>@body, "workflow_instance_id"=>@workflow_instance_id, "step_id"=>@step_id, "last_step_id"=>@last_step_id, "workflow"=>@workflow,"position"=>@position}
|
48
|
-
JSON.generate(obj)
|
49
|
-
end
|
50
|
-
|
51
|
-
def from_queue payload
|
52
|
-
message=JSON.parse(payload)
|
53
|
-
@workflow = message["workflow"]
|
54
|
-
@position=message["position"]
|
55
|
-
@body=message["body"]
|
56
|
-
@workflow_instance_id=message["workflow_instance_id"]
|
57
|
-
@step_id=message["step_id"]
|
58
|
-
@last_step_id=message["last_step_id"]
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|