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.
@@ -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
@@ -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.launch(workflow_name,options.parameters)
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"
@@ -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=Hash.new
15
- @channel_definitions=Array.new
16
- @workflows = Hash.new
14
+ @channel_modules={}
15
+ @channel_definitions=[]
16
+ @workflows = {}
17
17
  @message_bus = MessageBus.new(username,token)
18
- @credentials = Hash.new
19
- @tags = Hash.new
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
- @credentials["credentials"] = credentials
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 launch workflow, params, keep_open=false
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 = Message.new
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 |message|
77
- if @workflows.include? message.workflow
78
- workflow = @workflows[message.workflow]
79
- activity = workflow.get_activity(message.position)
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
- values = message.body.merge(@credentials)
123
+
124
+ # if match(target)
125
+ values = step.body.merge(@credentials)
126
+ # puts "Values: #{values.inspect}"
88
127
 
89
- # this maps the input values passed in with the templated defined in the workflow
90
- params = render_template(params_template,values)
91
- event = call_channel_method(channel,action,params)
92
- response_message = message.respond(event.params,event.class.name.split("::").last)
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
- @message_bus.send response_message
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
- action_class = get_action_class(channel_name,action_name)
113
- command = channel_module.const_get(action_class)
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['actions'].each do |action|
127
- return action["class_name"] if action['name']==action_name
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
@@ -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="workflow",&code)
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
- message = Message.new
40
- message.from_queue headers.routing_key, payload
41
- puts "[Received Message (#{message.route})] #{message.body.inspect}"
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.body.inspect}"
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 Message
7
- attr_accessor :body, :workflow, :workflow_instance_id, :activity_instance_id, :last_activity_instance_id, :position
6
+ class WorkflowStepMessage
7
+ attr_accessor :body, :workflow, :workflow_instance_id, :step_id, :last_step_id, :position
8
8
  def initialize
9
- @activity_instance_id=SecureRandom.hex
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 = Message.new
16
+ m = WorkflowStepMessage.new
17
17
  m.body = @body
18
18
  m.workflow_instance_id=@workflow_instance_id
19
- m.last_activity_instance_id = @activity_instance_id
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, "activity_instance_id"=>@activity_instance_id, "last_activity_instance_id"=>@last_activity_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 routing_key, payload
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
- @activity_instance_id=message["activity_instance_id"]
61
- @last_activity_instance_id=message["last_activity_instance_id"]
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.09
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-21 00:00:00.000000000 Z
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/message.rb
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: []