factor 0.1.09 → 0.1.10
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 +20 -0
- data/lib/cli/workflow_task.rb +16 -1
- data/lib/runtime/engine.rb +121 -28
- data/lib/runtime/listener_message.rb +42 -0
- data/lib/runtime/message_bus.rb +5 -6
- data/lib/runtime/{message.rb → workflow_step_messsage.rb} +14 -17
- metadata +5 -3
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Factor
|
4
|
+
module Channel
|
5
|
+
class Listener
|
6
|
+
attr_accessor :workflow_id, :event
|
7
|
+
|
8
|
+
def start(params,&code)
|
9
|
+
end
|
10
|
+
|
11
|
+
def stop()
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(workflow_id,event)
|
15
|
+
@workflow_id=workflow_id
|
16
|
+
@event=event
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/cli/workflow_task.rb
CHANGED
@@ -11,11 +11,26 @@ module Factor
|
|
11
11
|
puts "starting workflow #{workflow_name} with options #{options.parameters.to_s}"
|
12
12
|
|
13
13
|
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
14
|
-
id = engine.
|
14
|
+
id = engine.send_start_workflow(workflow_name,options.parameters)
|
15
15
|
|
16
16
|
puts "workflow executed with id #{id}"
|
17
17
|
end
|
18
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)
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "stop WORKFLOW","stop listener for workflow"
|
28
|
+
def stop(workflow_name)
|
29
|
+
puts "starting listener #{workflow_name}"
|
30
|
+
|
31
|
+
engine = Factor::Runtime::Engine.new(get_config[:email],get_config[:token])
|
32
|
+
engine.send_stop_listener(workflow_name)
|
33
|
+
end
|
19
34
|
|
20
35
|
|
21
36
|
desc "list", "list all the workflows"
|
data/lib/runtime/engine.rb
CHANGED
@@ -7,16 +7,17 @@ require 'mustache'
|
|
7
7
|
module Factor
|
8
8
|
module Runtime
|
9
9
|
class Engine
|
10
|
-
attr_accessor :channel_modules, :workflows, :message_bus
|
10
|
+
attr_accessor :channel_modules, :workflows, :message_bus, :listeners
|
11
11
|
|
12
12
|
# Engine needs modules that contain the code, workflows to run, and message bus for communication
|
13
13
|
def initialize(username,token)
|
14
|
-
@channel_modules=
|
15
|
-
@channel_definitions=
|
16
|
-
@workflows =
|
14
|
+
@channel_modules={}
|
15
|
+
@channel_definitions=[]
|
16
|
+
@workflows = {}
|
17
17
|
@message_bus = MessageBus.new(username,token)
|
18
|
-
@credentials =
|
19
|
-
@tags =
|
18
|
+
@credentials = {}
|
19
|
+
@tags = {}
|
20
|
+
@listeners={}
|
20
21
|
end
|
21
22
|
|
22
23
|
def tag(key,value)
|
@@ -38,7 +39,14 @@ module Factor
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def load_credentials credentials,secret=nil
|
41
|
-
|
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
|
42
50
|
end
|
43
51
|
|
44
52
|
# adds the workflow to the workflows list
|
@@ -55,11 +63,11 @@ module Factor
|
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
58
|
-
def
|
66
|
+
def send_start_workflow workflow, params, keep_open=false
|
59
67
|
instance_id=SecureRandom.hex
|
60
68
|
|
61
69
|
@message_bus.start do
|
62
|
-
message =
|
70
|
+
message = WorkflowStepMessage.new
|
63
71
|
message.position << "start"
|
64
72
|
message.workflow=workflow
|
65
73
|
message.add_values params
|
@@ -68,51 +76,116 @@ module Factor
|
|
68
76
|
end
|
69
77
|
instance_id
|
70
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
|
71
93
|
|
72
94
|
# start your engines. vroom vrooooom!
|
73
95
|
def start
|
74
96
|
begin
|
75
97
|
@message_bus.start do
|
76
|
-
@message_bus.listen do |
|
77
|
-
|
78
|
-
|
79
|
-
|
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)
|
80
118
|
if !activity.nil?
|
81
119
|
action = activity["action"]
|
82
120
|
channel = activity["channel"]
|
83
121
|
target = activity["target"]
|
84
122
|
params_template = activity["params"]
|
85
|
-
|
86
|
-
# if match(target)
|
87
|
-
|
123
|
+
|
124
|
+
# if match(target)
|
125
|
+
values = step.body.merge(@credentials)
|
126
|
+
# puts "Values: #{values.inspect}"
|
88
127
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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)
|
93
133
|
|
94
|
-
|
134
|
+
@message_bus.send response_message
|
95
135
|
# end
|
136
|
+
else
|
137
|
+
puts "[error] no activity found for position '#{step.position}'"
|
96
138
|
end
|
97
139
|
else
|
98
140
|
# workflow doesn't exist
|
141
|
+
puts "[warning] '#{step.workflow}' workflow wasn't found"
|
99
142
|
end
|
100
143
|
end
|
101
144
|
end
|
102
145
|
rescue SystemExit, Interrupt
|
103
|
-
"done"
|
146
|
+
puts "done"
|
104
147
|
rescue Exception => ex
|
105
|
-
ex
|
148
|
+
puts ex
|
106
149
|
end
|
107
150
|
end
|
108
151
|
|
109
152
|
def call_channel_method(channel_name,action_name,params)
|
110
153
|
channel_module_name = get_channel_module(channel_name)
|
111
154
|
channel_module = @channel_modules[channel_module_name]
|
112
|
-
|
113
|
-
command = channel_module.const_get(
|
155
|
+
action_class_name = get_class_name("actions",channel_name,action_name)
|
156
|
+
command = channel_module.const_get(action_class_name)
|
114
157
|
command.new.do_work(params)
|
115
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
|
116
189
|
|
117
190
|
private
|
118
191
|
|
@@ -120,11 +193,31 @@ module Factor
|
|
120
193
|
@channel_definitions.select { |channel_definition| channel_definition['name']==channel_name }.first['module_name']
|
121
194
|
end
|
122
195
|
|
123
|
-
def get_action_class(channel_name,action_name)
|
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)
|
124
217
|
@channel_definitions.each do |channel_definition|
|
125
218
|
if channel_definition['name']==channel_name
|
126
|
-
channel_definition[
|
127
|
-
return
|
219
|
+
channel_definition[type].each do |definition|
|
220
|
+
return definition["class_name"] if definition['name']==class_name
|
128
221
|
end
|
129
222
|
end
|
130
223
|
end
|
@@ -0,0 +1,42 @@
|
|
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
CHANGED
@@ -18,7 +18,7 @@ module Factor
|
|
18
18
|
# Creates the connection and creates a topic exchange
|
19
19
|
# An exchange references a place to send messages to
|
20
20
|
# the exchange routes it to the queues based on the route_key
|
21
|
-
def start(topic="
|
21
|
+
def start(topic="factor",&code)
|
22
22
|
EventMachine.run do
|
23
23
|
#connection_settings={:host=>@host,:user=>@username,:password=>@token,:vhost=>@vhost}
|
24
24
|
connection_settings={:host=>@host}
|
@@ -36,15 +36,14 @@ module Factor
|
|
36
36
|
@queue.bind(@exchange, :routing_key=>routing_key) # bind queue to the Exchange
|
37
37
|
|
38
38
|
@queue.subscribe do |headers,payload|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
code.call(message)
|
39
|
+
# code.call(headers.routing_key,payload)
|
40
|
+
puts "[Received Message (#{headers.routing_key})] #{payload.inspect}"
|
41
|
+
code.call(payload)
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
45
|
def send(message,close=false)
|
47
|
-
puts "[Sending Message (#{message.route})] #{message.
|
46
|
+
puts "[Sending Message (#{message.route})] #{message.payload.inspect}"
|
48
47
|
@exchange.publish(message.payload,:routing_key => message.route)
|
49
48
|
EM.add_timer(1, Proc.new { close}) if close
|
50
49
|
end
|
@@ -3,20 +3,20 @@ require 'json/ext'
|
|
3
3
|
|
4
4
|
module Factor
|
5
5
|
module Runtime
|
6
|
-
class
|
7
|
-
attr_accessor :body, :workflow, :workflow_instance_id, :
|
6
|
+
class WorkflowStepMessage
|
7
|
+
attr_accessor :body, :workflow, :workflow_instance_id, :step_id, :last_step_id, :position
|
8
8
|
def initialize
|
9
|
-
@
|
10
|
-
@workflow = workflow
|
9
|
+
@step_id=SecureRandom.hex
|
10
|
+
# @workflow = workflow
|
11
11
|
@body = Hash.new
|
12
12
|
@position = Array.new
|
13
13
|
end
|
14
14
|
|
15
15
|
def respond(params, event)
|
16
|
-
m =
|
16
|
+
m = WorkflowStepMessage.new
|
17
17
|
m.body = @body
|
18
18
|
m.workflow_instance_id=@workflow_instance_id
|
19
|
-
m.
|
19
|
+
m.last_step_id = @step_id
|
20
20
|
m.workflow = @workflow
|
21
21
|
m.position = @position
|
22
22
|
m.position << "on"
|
@@ -25,11 +25,9 @@ module Factor
|
|
25
25
|
m
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
28
|
def add_values(values)
|
30
29
|
current=@body
|
31
30
|
position.each do |key|
|
32
|
-
#puts "[add value] #{key} (#{key.class.name})"
|
33
31
|
current[key]={} if !current.include?(key)
|
34
32
|
current=current[key]
|
35
33
|
end
|
@@ -40,25 +38,24 @@ module Factor
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def route
|
43
|
-
"#{workflow}.#{position.join('.')}"
|
41
|
+
# "#{workflow}.#{position.join('.')}"
|
42
|
+
"workflow"
|
44
43
|
end
|
45
44
|
|
46
45
|
def payload
|
47
46
|
JSON.generator = JSON::Ext::Generator
|
48
|
-
obj = {"body"=>@body, "workflow_instance_id"=>@workflow_instance_id, "
|
47
|
+
obj = {"body"=>@body, "workflow_instance_id"=>@workflow_instance_id, "step_id"=>@step_id, "last_step_id"=>@last_step_id, "workflow"=>@workflow,"position"=>@position}
|
49
48
|
JSON.generate(obj)
|
50
49
|
end
|
51
50
|
|
52
|
-
def from_queue
|
53
|
-
routing_array=routing_key.split('.')
|
54
|
-
@workflow=routing_array.first #first
|
55
|
-
@position=routing_array.drop(1) # everything after first
|
56
|
-
|
51
|
+
def from_queue payload
|
57
52
|
message=JSON.parse(payload)
|
53
|
+
@workflow = message["workflow"]
|
54
|
+
@position=message["position"]
|
58
55
|
@body=message["body"]
|
59
56
|
@workflow_instance_id=message["workflow_instance_id"]
|
60
|
-
@
|
61
|
-
@
|
57
|
+
@step_id=message["step_id"]
|
58
|
+
@last_step_id=message["last_step_id"]
|
62
59
|
end
|
63
60
|
|
64
61
|
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.1.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- lib/channel/activity.rb
|
134
134
|
- lib/channel/channel.rb
|
135
135
|
- lib/channel/event.rb
|
136
|
+
- lib/channel/listener.rb
|
136
137
|
- lib/channel/trigger.rb
|
137
138
|
- lib/cli/channel_task.rb
|
138
139
|
- lib/cli/command.rb
|
@@ -144,10 +145,11 @@ files:
|
|
144
145
|
- lib/factor.rb
|
145
146
|
- lib/runtime/attributes.rb
|
146
147
|
- lib/runtime/engine.rb
|
147
|
-
- lib/runtime/
|
148
|
+
- lib/runtime/listener_message.rb
|
148
149
|
- lib/runtime/message_bus.rb
|
149
150
|
- lib/runtime/workflow.rb
|
150
151
|
- lib/runtime/workflow_instance.rb
|
152
|
+
- lib/runtime/workflow_step_messsage.rb
|
151
153
|
- bin/factor
|
152
154
|
homepage: http://rubygems.org/gems/factor
|
153
155
|
licenses: []
|