factor 0.1.10 → 0.3.1
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/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
|