factor 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/factor +3 -3
- data/lib/channel/activity.rb +10 -0
- data/lib/channel/channel.rb +8 -0
- data/lib/channel/event.rb +13 -0
- data/lib/channel/trigger.rb +16 -0
- data/lib/cli/channel_task.rb +25 -0
- data/lib/cli/command.rb +25 -0
- data/lib/cli/credential_task.rb +22 -0
- data/lib/cli/factor_task.rb +45 -0
- data/lib/cli/server_task.rb +47 -0
- data/lib/cli/workflow_task.rb +26 -0
- data/lib/client/client.rb +118 -0
- data/lib/factor.rb +6 -8
- data/lib/runtime/attributes.rb +26 -0
- data/lib/runtime/engine.rb +107 -0
- data/lib/runtime/message.rb +65 -0
- data/lib/runtime/message_bus.rb +57 -0
- data/lib/runtime/workflow.rb +25 -0
- data/lib/runtime/workflow_instance.rb +28 -0
- metadata +22 -4
data/bin/factor
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cli/command'
|
3
|
+
|
4
|
+
module Factor
|
5
|
+
module CLI
|
6
|
+
class ChannelTask < Command
|
7
|
+
|
8
|
+
desc "install NAME", "install a new channel"
|
9
|
+
def install(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "uninstall NAME", "uninstall the channel"
|
13
|
+
def uninstall(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "list", "list all my installed channels"
|
17
|
+
def list
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "all", "list all channels available for installation"
|
21
|
+
def all
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/cli/command.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'thor'
|
3
|
+
require 'thor/group'
|
4
|
+
require 'yaml'
|
5
|
+
require 'rest_client'
|
6
|
+
|
7
|
+
|
8
|
+
module Factor
|
9
|
+
module CLI
|
10
|
+
class Command < Thor
|
11
|
+
CONFIG_FILE_DIR = File.expand_path("~/.factor")
|
12
|
+
no_tasks do
|
13
|
+
def save_config(config)
|
14
|
+
File.open(CONFIG_FILE_DIR,'w') do |file|
|
15
|
+
YAML::dump(config,file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_config
|
20
|
+
File.exists?(CONFIG_FILE_DIR) ? YAML::load_file(CONFIG_FILE_DIR) : {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cli/command'
|
3
|
+
|
4
|
+
module Factor
|
5
|
+
module CLI
|
6
|
+
class CredentialTask < Command
|
7
|
+
|
8
|
+
desc "list", "list all the credentials"
|
9
|
+
def list
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "add KEY VALUE", "add a key and value for the credential"
|
13
|
+
def add
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "remove KEY", "remove a value from the credentials bag"
|
17
|
+
def remove
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cli/command'
|
3
|
+
require 'cli/server_task'
|
4
|
+
require 'cli/workflow_task'
|
5
|
+
require 'cli/credential_task'
|
6
|
+
|
7
|
+
module Factor
|
8
|
+
module CLI
|
9
|
+
class FactorTask < Command
|
10
|
+
|
11
|
+
desc "register","register a new account"
|
12
|
+
method_option :email, :alias=>"-e", :type=>:string, :desc=>"Email address you would like to use for new account"
|
13
|
+
method_option :password, :alias=>"-p", :type=>:string, :desc=>"Password you would like to use for new account"
|
14
|
+
def register
|
15
|
+
email = options[:email]==nil ? ask("Email address:") : options[:email]
|
16
|
+
password = options[:password]==nil ? ask("Password:") : options[:password]
|
17
|
+
|
18
|
+
# register with email/password
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "login", "login to the account"
|
23
|
+
method_option :email, :alias=>"-u", :type=>:string, :desc=>"Account email address"
|
24
|
+
method_option :password, :alias=>"-p", :type=>:string, :desc=>"Account password"
|
25
|
+
def login
|
26
|
+
email = options[:email]==nil ? ask("Email address:") : options[:email]
|
27
|
+
password = options[:password]==nil ? ask("Password:") : options[:password]
|
28
|
+
|
29
|
+
#login with email/password
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "token", "login with token"
|
33
|
+
method_option :token, :alias=>"-t", :type=>:string, :desc=>"Token value to set", :required=>true
|
34
|
+
def token
|
35
|
+
config = get_config
|
36
|
+
config[:token]=options[:token]
|
37
|
+
save_config(config)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Factor::CLI::FactorTask.register(Factor::CLI::ServerTask, "server","server","start and list servers")
|
44
|
+
Factor::CLI::FactorTask.register(Factor::CLI::WorkflowTask,"workflow","workflow","start and list workflows")
|
45
|
+
Factor::CLI::FactorTask.register(Factor::CLI::ChannelTask,"channel","channel","install,uninstall, list channels")
|
@@ -0,0 +1,47 @@
|
|
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
|
+
def start
|
9
|
+
engine = Factor::Engine.new
|
10
|
+
|
11
|
+
client = Factor::Client.new
|
12
|
+
client.login_token(get_config[:token])
|
13
|
+
|
14
|
+
puts "loading channels"
|
15
|
+
engine = client.load_channels(engine)
|
16
|
+
puts "loading channels complete"
|
17
|
+
|
18
|
+
puts "loading workflows"
|
19
|
+
engine = client.load_workflows(engine)
|
20
|
+
puts "loading workflows complete"
|
21
|
+
|
22
|
+
puts "loading credentials"
|
23
|
+
engine = client.load_credentials(engine)
|
24
|
+
puts "loading credentials complete"
|
25
|
+
|
26
|
+
puts "starting the server..."
|
27
|
+
engine.start
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "list", "list all the running servers"
|
32
|
+
def list
|
33
|
+
puts "listing all servers"
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "logs", "listen to incoming logs"
|
37
|
+
def logs
|
38
|
+
engine = Factor::Engine.new
|
39
|
+
puts "Listening..."
|
40
|
+
engine.logs do |message|
|
41
|
+
puts "[#{message.route}] #{message.body}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cli/command'
|
3
|
+
|
4
|
+
module Factor
|
5
|
+
module CLI
|
6
|
+
class WorkflowTask < Command
|
7
|
+
|
8
|
+
desc "call WORKFLOW","start a workflow"
|
9
|
+
method_option :parameters, :type=>:hash, :default=>{}, :required=>false
|
10
|
+
def call(workflow_name)
|
11
|
+
puts "starting workflow #{workflow_name} with options #{options.parameters.to_s}"
|
12
|
+
|
13
|
+
engine = Factor::Engine.new
|
14
|
+
id = engine.launch(workflow_name,options.parameters)
|
15
|
+
|
16
|
+
puts "workflow executed with id #{id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "list", "list all available workflows"
|
20
|
+
def list
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'zip'
|
4
|
+
require 'zip/zipfilesystem'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
module Factor
|
8
|
+
module Client
|
9
|
+
class Client
|
10
|
+
HOST = "http://localhost:3000"
|
11
|
+
|
12
|
+
def register(email,password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def login(email, password)
|
16
|
+
end
|
17
|
+
|
18
|
+
def login_token(token)
|
19
|
+
@token=token
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_workflows(engine)
|
23
|
+
workflows = rest_get("workflows")
|
24
|
+
workflows.each do |workflow|
|
25
|
+
workflow_definition = JSON.parse(workflow['definition'])
|
26
|
+
workflow=Factor::Workflow.new(workflow_definition)
|
27
|
+
engine.load_workflow(workflow)
|
28
|
+
end
|
29
|
+
engine
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_credentials(engine)
|
33
|
+
|
34
|
+
credentials_definition = rest_get("credentials")
|
35
|
+
credentials = JSON.parse(credentials_definition["bag"])
|
36
|
+
engine.load_credentials(credentials)
|
37
|
+
|
38
|
+
engine
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def load_channels(engine)
|
43
|
+
|
44
|
+
# get list of channels
|
45
|
+
channels = rest_get("channels")
|
46
|
+
|
47
|
+
#load each channel
|
48
|
+
channels.each do |channel|
|
49
|
+
|
50
|
+
# URI of the zip file containing the module
|
51
|
+
uri = URI.parse(channel['zip_url'])
|
52
|
+
|
53
|
+
# temp file to store the zip for download
|
54
|
+
temp_file = Tempfile.new([uri.to_s.gsub(/\W+/,'-'), '.zip'], :encoding => 'ascii-8bit')
|
55
|
+
|
56
|
+
# temp directory where zip will be decompressed
|
57
|
+
unzip_dir=temp_file.path[0..-5]
|
58
|
+
|
59
|
+
# download
|
60
|
+
open(uri.to_s,"rb") do |bin|
|
61
|
+
temp_file.print bin.read
|
62
|
+
end
|
63
|
+
temp_file.close
|
64
|
+
|
65
|
+
# unzip download zip into unzipped directory
|
66
|
+
unzip(temp_file.path,unzip_dir)
|
67
|
+
|
68
|
+
Dir.glob("#{unzip_dir}/#{channel['name'].downcase}/*.rb").each do |file|
|
69
|
+
engine.load_channel(file)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
engine
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def fix_github_zip_archive(file)
|
82
|
+
Zip::ZipFile.open(file.path) do |zip|
|
83
|
+
basedir = zip.entries.first.name
|
84
|
+
zip.remove zip.entries.first
|
85
|
+
zip.each do |entry|
|
86
|
+
target = entry.name.sub(/^#{basedir}/,'')
|
87
|
+
if entry.directory?
|
88
|
+
zip.dir.mkdir(target)
|
89
|
+
else
|
90
|
+
zip.file.open(entry.name) do |istream|
|
91
|
+
zip.file.open(target, 'w') do |ostream|
|
92
|
+
ostream.write istream.read
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
zip.remove entry
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def unzip(zip, unzip_dir, remove_after = false)
|
102
|
+
Zip::ZipFile.open(zip) do |zip_file|
|
103
|
+
zip_file.each do |f|
|
104
|
+
f_path=File.join(unzip_dir, f.name)
|
105
|
+
FileUtils.mkdir_p(File.dirname(f_path))
|
106
|
+
zip_file.extract(f, f_path) unless File.exist?(f_path)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
FileUtils.rm(zip) if remove_after
|
110
|
+
end
|
111
|
+
|
112
|
+
def rest_get(path)
|
113
|
+
JSON.parse(RestClient.get "#{HOST}/#{path}.json?auth_token=#{@token}")
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/factor.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
1
|
require 'rubygems'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require
|
8
|
-
|
9
|
-
require 'message.rb'
|
2
|
+
|
3
|
+
# load all the libraries
|
4
|
+
lib_files = "../**/*.rb"
|
5
|
+
Dir[File.expand_path(lib_files,__FILE__)].each do |file|
|
6
|
+
require file
|
7
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'factor'
|
3
|
+
require 'mustache'
|
4
|
+
|
5
|
+
|
6
|
+
module Factor
|
7
|
+
module Runtime
|
8
|
+
class Engine
|
9
|
+
attr_accessor :channel_modules, :workflows, :message_bus
|
10
|
+
|
11
|
+
# Engine needs modules that contain the code, workflows to run, and message bus for communication
|
12
|
+
def initialize
|
13
|
+
@channel_modules=Hash.new
|
14
|
+
@workflows = Hash.new
|
15
|
+
@message_bus ||= MessageBus.new
|
16
|
+
@credentials = Hash.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# load the channel by referencing the .rb file
|
20
|
+
# the filename is lowercase with "_" for spaces
|
21
|
+
# and the module inside must be camal cased to match
|
22
|
+
# once loaded it is in the channel_modules Hash
|
23
|
+
def load_channel filename
|
24
|
+
file=File.new filename
|
25
|
+
require file
|
26
|
+
channel_module_name = File.basename(file).gsub('.rb','').split('_').map{|ea| ea.capitalize}.join('')
|
27
|
+
channel_module= self.class.const_get(channel_module_name)
|
28
|
+
|
29
|
+
@channel_modules[channel_module.definition["module"]]=channel_module
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_credentials credentials
|
33
|
+
@credentials["credentials"] = credentials
|
34
|
+
end
|
35
|
+
|
36
|
+
# adds the workflow to the workflows list
|
37
|
+
# the object must be a Workflow type
|
38
|
+
def load_workflow workflow
|
39
|
+
@workflows[workflow.name] = workflow
|
40
|
+
end
|
41
|
+
|
42
|
+
def logs routing_key="#", &code
|
43
|
+
@message_bus.start do
|
44
|
+
@message_bus.listen routing_key do |message|
|
45
|
+
code.call message
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def launch workflow, params
|
51
|
+
instance_id=SecureRandom.hex
|
52
|
+
@message_bus.start do
|
53
|
+
message = Message.new
|
54
|
+
message.position << "start"
|
55
|
+
message.workflow=workflow
|
56
|
+
message.add_values params
|
57
|
+
message.workflow_instance_id= instance_id
|
58
|
+
@message_bus.send_and_close message
|
59
|
+
end
|
60
|
+
instance_id
|
61
|
+
end
|
62
|
+
|
63
|
+
# start your engines. vroom vrooooom!
|
64
|
+
def start
|
65
|
+
@message_bus.start do
|
66
|
+
@message_bus.listen do |message|
|
67
|
+
if @workflows.include? message.workflow
|
68
|
+
workflow = @workflows[message.workflow]
|
69
|
+
activity = workflow.get_activity(message.position)
|
70
|
+
if !activity.nil?
|
71
|
+
# puts "[activity] #{activity.to_s}"
|
72
|
+
action = activity["action"]
|
73
|
+
channel = activity["channel"]
|
74
|
+
method = activity["method"]
|
75
|
+
|
76
|
+
values = message.body.merge(@credentials)
|
77
|
+
puts "[values] #{values}"
|
78
|
+
# this maps the input values passed in with the templated defined in the workflow
|
79
|
+
params = Hash.new
|
80
|
+
activity["params"].each do |key,template|
|
81
|
+
params[key]=Mustache.render(template,values)
|
82
|
+
end
|
83
|
+
puts "[calling] #{channel}::#{method} (#{params.to_s})"
|
84
|
+
event = call_channel_method(channel,method,params)
|
85
|
+
|
86
|
+
response_message = message.respond(event.params,event.class.name.split("::").last)
|
87
|
+
|
88
|
+
|
89
|
+
@message_bus.send response_message
|
90
|
+
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# workflow doesn't exist
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def call_channel_method(channel_name,class_name,params)
|
101
|
+
channel_module = @channel_modules[channel_name]
|
102
|
+
command = channel_module.const_get(class_name)
|
103
|
+
command.new.do_work(params)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'SecureRandom'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Factor
|
6
|
+
module Runtime
|
7
|
+
class Message
|
8
|
+
attr_accessor :body, :workflow, :workflow_instance_id, :activity_instance_id, :last_activity_instance_id, :position
|
9
|
+
def initialize
|
10
|
+
@activity_instance_id=SecureRandom.hex
|
11
|
+
@workflow = workflow
|
12
|
+
@body = Hash.new
|
13
|
+
@position = Array.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond(params, event)
|
17
|
+
m = Message.new
|
18
|
+
m.body = @body
|
19
|
+
m.workflow_instance_id=@workflow_instance_id
|
20
|
+
m.last_activity_instance_id = @activity_instance_id
|
21
|
+
m.workflow = @workflow
|
22
|
+
m.position = @position
|
23
|
+
m.position << "on"
|
24
|
+
m.position << event
|
25
|
+
m.add_values(params)
|
26
|
+
m
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def add_values(values)
|
31
|
+
current=@body
|
32
|
+
position.each do |key|
|
33
|
+
#puts "[add value] #{key} (#{key.class.name})"
|
34
|
+
current[key]={} if !current.include?(key)
|
35
|
+
current=current[key]
|
36
|
+
end
|
37
|
+
values.each do |key,value|
|
38
|
+
current[key]=value
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def route
|
44
|
+
"#{workflow}.#{position.join('.')}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def payload
|
48
|
+
{"body"=>@body, "workflow_instance_id"=>@workflow_instance_id, "activity_instance_id"=>@activity_instance_id, "last_activity_instance_id"=>@last_activity_instance_id}.to_json
|
49
|
+
end
|
50
|
+
|
51
|
+
def from_queue routing_key, payload
|
52
|
+
routing_array=routing_key.split('.')
|
53
|
+
@workflow=routing_array.first #first
|
54
|
+
@position=routing_array.drop(1) # everything after first
|
55
|
+
|
56
|
+
message=JSON.parse(payload)
|
57
|
+
@body=message["body"]
|
58
|
+
@workflow_instance_id=message["workflow_instance_id"]
|
59
|
+
@activity_instance_id=message["activity_instance_id"]
|
60
|
+
@last_activity_instance_id=message["last_activity_instance_id"]
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'SecureRandom'
|
3
|
+
|
4
|
+
module Factor
|
5
|
+
module Runtime
|
6
|
+
class MessageBus
|
7
|
+
attr_accessor :host, :connection, :channel, :exchange, :queue
|
8
|
+
|
9
|
+
def initialize(host="queue.factor.io")
|
10
|
+
@host = host
|
11
|
+
end
|
12
|
+
|
13
|
+
# Creates the connection and creates a topic exchange
|
14
|
+
# An exchange references a place to send messages to
|
15
|
+
# the exchange routes it to the queues based on the route_key
|
16
|
+
def start(topic="workflow",&code)
|
17
|
+
EventMachine.run do
|
18
|
+
@connection = AMQP.connect(:host=>@host)
|
19
|
+
@channel = AMQP::Channel.new(connection)
|
20
|
+
@exchange = @channel.topic(topic,:auto_delete=>true) # new topic exchange
|
21
|
+
code.call
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# creates a new queue to listen to the topic exchange
|
26
|
+
def listen(routing_key="#",&code)
|
27
|
+
queue_name=SecureRandom.hex
|
28
|
+
@queue = @channel.queue(queue_name)
|
29
|
+
@queue.bind(@exchange, :routing_key=>routing_key) # bind queue to the Exchange
|
30
|
+
|
31
|
+
@queue.subscribe do |headers,payload|
|
32
|
+
message = Message.new
|
33
|
+
message.from_queue headers.routing_key, payload
|
34
|
+
code.call(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def send(message)
|
39
|
+
@exchange.publish(message.payload,:routing_key => message.route)
|
40
|
+
end
|
41
|
+
|
42
|
+
def send_and_close(message)
|
43
|
+
send(message)
|
44
|
+
|
45
|
+
EM.add_timer(1, Proc.new { close})
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def close
|
50
|
+
@connection.close{ EventMachine.stop }
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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
|
@@ -0,0 +1,28 @@
|
|
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
|
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.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,16 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-09 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
14
|
+
description: Friendly command-line interface and library for Factor
|
15
15
|
email: maciej@skierkowski.com
|
16
16
|
executables:
|
17
17
|
- factor
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- lib/channel/activity.rb
|
22
|
+
- lib/channel/channel.rb
|
23
|
+
- lib/channel/event.rb
|
24
|
+
- lib/channel/trigger.rb
|
25
|
+
- lib/cli/channel_task.rb
|
26
|
+
- lib/cli/command.rb
|
27
|
+
- lib/cli/credential_task.rb
|
28
|
+
- lib/cli/factor_task.rb
|
29
|
+
- lib/cli/server_task.rb
|
30
|
+
- lib/cli/workflow_task.rb
|
31
|
+
- lib/client/client.rb
|
21
32
|
- lib/factor.rb
|
33
|
+
- lib/runtime/attributes.rb
|
34
|
+
- lib/runtime/engine.rb
|
35
|
+
- lib/runtime/message.rb
|
36
|
+
- lib/runtime/message_bus.rb
|
37
|
+
- lib/runtime/workflow.rb
|
38
|
+
- lib/runtime/workflow_instance.rb
|
22
39
|
- bin/factor
|
23
40
|
homepage: http://rubygems.org/gems/factor
|
24
41
|
licenses: []
|
@@ -26,6 +43,7 @@ post_install_message:
|
|
26
43
|
rdoc_options: []
|
27
44
|
require_paths:
|
28
45
|
- lib
|
46
|
+
- lib
|
29
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
30
48
|
none: false
|
31
49
|
requirements:
|
@@ -43,5 +61,5 @@ rubyforge_project:
|
|
43
61
|
rubygems_version: 1.8.24
|
44
62
|
signing_key:
|
45
63
|
specification_version: 3
|
46
|
-
summary: Factor.io Library
|
64
|
+
summary: Factor.io Library and CLI
|
47
65
|
test_files: []
|