factor 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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: []
|