pione 0.4.0 → 0.4.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.
Files changed (60) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +1 -0
  3. data/History.txt +7 -0
  4. data/example/DeferredChoice/DeferredChoice.pione +14 -7
  5. data/{misc → example/DeferredChoice/bin}/ui.xml +11 -6
  6. data/example/DeferredChoice/pione-package.json +1 -1
  7. data/example/DeferredChoiceWithPage/DeferredChoiceWithPage.pione +47 -0
  8. data/example/DeferredChoiceWithPage/etc/index.html +22 -0
  9. data/example/DeferredChoiceWithPage/pione-package.json +18 -0
  10. data/example/Interaction/Interaction.pione +27 -0
  11. data/example/Interaction/bin/show-environment.cgi +45 -0
  12. data/example/Interaction/etc/.hidden-file.txt +1 -0
  13. data/example/Interaction/etc/cgi.html +46 -0
  14. data/example/Interaction/etc/create-files.html +51 -0
  15. data/example/Interaction/etc/delete-files.html +31 -0
  16. data/example/Interaction/etc/get-files.html +21 -0
  17. data/example/Interaction/etc/index.html +18 -0
  18. data/example/Interaction/etc/list-files.html +36 -0
  19. data/example/Interaction/pione-package.json +24 -0
  20. data/lib/pione/agent/job-manager.rb +19 -3
  21. data/lib/pione/agent/logger.rb +9 -9
  22. data/lib/pione/agent/messenger.rb +3 -2
  23. data/lib/pione/agent/task-worker.rb +32 -10
  24. data/lib/pione/command/option.rb +18 -0
  25. data/lib/pione/command/pione-client.rb +51 -22
  26. data/lib/pione/command/pione-interactive.rb +128 -55
  27. data/lib/pione/command/pione-package-build.rb +3 -3
  28. data/lib/pione/command/pione-task-worker.rb +23 -10
  29. data/lib/pione/command/pione-tuple-space-provider.rb +8 -8
  30. data/lib/pione/command/spawner.rb +28 -1
  31. data/lib/pione/front/interactive-front.rb +76 -0
  32. data/lib/pione/global/interactive-variable.rb +26 -0
  33. data/lib/pione/log/message-log-receiver.rb +4 -2
  34. data/lib/pione/model/task-worker-broker-model.rb +7 -1
  35. data/lib/pione/package/package-archiver.rb +16 -9
  36. data/lib/pione/package/package-handler.rb +6 -0
  37. data/lib/pione/package/package-info.rb +4 -0
  38. data/lib/pione/package/package-reader.rb +2 -4
  39. data/lib/pione/package/package-scanner.rb +23 -3
  40. data/lib/pione/rule-engine.rb +48 -19
  41. data/lib/pione/rule-engine/action-handler.rb +29 -5
  42. data/lib/pione/rule-engine/basic-handler.rb +27 -19
  43. data/lib/pione/test-helper/command-helper.rb +1 -1
  44. data/lib/pione/tuple-space/tuple-definition.yml +2 -3
  45. data/lib/pione/tuple-space/tuple-space-server.rb +8 -0
  46. data/lib/pione/util/cgi.rb +326 -0
  47. data/lib/pione/version.rb +1 -1
  48. data/lib/rootage/normalizer.rb +4 -0
  49. data/lib/rootage/option.rb +11 -4
  50. data/test/agent/spec_logger.rb +0 -1
  51. data/test/agent/spec_messenger.rb +1 -1
  52. data/test/command/spec_pione-client.rb +4 -4
  53. data/test/log/spec_message-log.rb +1 -1
  54. data/test/rule-engine/spec_action-handler.rb +25 -5
  55. data/test/rule-engine/spec_empty-handler.rb +36 -3
  56. data/test/rule-engine/spec_flow-handler.rb +90 -7
  57. metadata +22 -72
  58. data/misc/test-drb-stop-service.rb +0 -34
  59. data/misc/test-many-waiters-client.rb +0 -56
  60. data/misc/test-many-waiters-server.rb +0 -14
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Interaction Example: List files</title>
6
+ </head>
7
+ <body>
8
+ <h1>POST Method Example</h1>
9
+
10
+ <section>
11
+ <h2>List with no options</h2>
12
+ <form action="./" method="POST">
13
+ <input type="hidden" name="pione-action" value="list" />
14
+ <button type="submit">List files</button>
15
+ </form>
16
+ </section>
17
+
18
+ <section>
19
+ <h2>List with pione-show-all=true</h2>
20
+ <form action="./" method="POST">
21
+ <input type="hidden" name="pione-action" value="list" />
22
+ <input type="hidden" name="pione-show-all" value="true" />
23
+ <button type="submit">List files</button>
24
+ </form>
25
+ </section>
26
+
27
+ <section>
28
+ <h2>List with pione-show-all=false</h2>
29
+ <form action="./" method="POST">
30
+ <input type="hidden" name="pione-action" value="list" />
31
+ <input type="hidden" name="pione-show-all" value="false" />
32
+ <button type="submit">List files</button>
33
+ </form>
34
+ </section>
35
+ </body>
36
+ </html>
@@ -0,0 +1,24 @@
1
+ {
2
+ "PackageName": "Interaction",
3
+ "Parents": [
4
+
5
+ ],
6
+ "Documents": [
7
+ "Interaction.pione"
8
+ ],
9
+ "Scenarios": [
10
+
11
+ ],
12
+ "Bins": [
13
+ "bin/show-environment.cgi"
14
+ ],
15
+ "Etcs": [
16
+ "etc/create-files.html",
17
+ "etc/list-files.html",
18
+ "etc/get-files.html",
19
+ "etc/index.html",
20
+ "etc/delete-files.html",
21
+ "etc/cgi.html",
22
+ "etc/.hidden-file.txt"
23
+ ]
24
+ }
@@ -54,6 +54,11 @@ module Pione
54
54
 
55
55
  # share my environment
56
56
  write(TupleSpace::EnvTuple.new(@env.dumpable)) # need to be dumpable
57
+
58
+ # collect tuple space attributes
59
+ @request_from = @tuple_space.attribute("request_from")
60
+ @session_id = @tuple_space.attribute("session_id")
61
+ @client_ui = @tuple_space.attribute("client_ui")
57
62
  end
58
63
 
59
64
  def transit_to_sleep
@@ -69,9 +74,20 @@ module Pione
69
74
  else
70
75
  # call root rule of the current package
71
76
  list.each do |env, inputs|
72
- package_id = @env.current_package_id
73
- handler = RuleEngine.make(@tuple_space, @env, package_id, "Root", inputs, Lang::ParameterSet.new, 'root', nil)
74
- handler.handle
77
+ engine_param = {
78
+ :tuple_space => @tuple_space,
79
+ :env => @env,
80
+ :package_id => @env.current_package_id,
81
+ :rule_name => "Root",
82
+ :inputs => inputs,
83
+ :param_set => Lang::ParameterSet.new,
84
+ :domain_id => 'root',
85
+ :caller_id => nil,
86
+ :request_from => @request_from,
87
+ :session_id => @session_id,
88
+ :client_ui => @client_ui
89
+ }
90
+ RuleEngine.make(engine_param).handle
75
91
  end
76
92
  end
77
93
 
@@ -5,15 +5,15 @@ module Pione
5
5
  class Logger < TupleSpaceClient
6
6
  set_agent_type :logger, self
7
7
 
8
- attr_reader :log_location # location of log file
9
- attr_reader :output_location # output location
8
+ attr_reader :log_location # location of log file
9
+ attr_reader :temporary_location # temporary location
10
10
 
11
11
  # Create a logger agent.
12
12
  def initialize(tuple_space, location)
13
13
  super(tuple_space)
14
14
  @log_id = Time.now.iso8601(3)
15
15
  @log_location = location.directory? ? location + "pione-process.log" : location
16
- @output_location = get_output_location
16
+ @temporary_location = get_temporary_location
17
17
  end
18
18
 
19
19
  #
@@ -40,7 +40,7 @@ module Pione
40
40
  end
41
41
  end
42
42
 
43
- # Copy from output to log when log and output are different.
43
+ # Copy from temporary location to log location.
44
44
  def transit_to_terminate
45
45
  begin
46
46
  write_records(take_all!(TupleSpace::ProcessLogTuple.any))
@@ -48,8 +48,8 @@ module Pione
48
48
  # logger is terminated at last in termination processes, so tuple space may be closed
49
49
  Log::SystemLog.warn("logger agent failed to take process logs.", self, e)
50
50
  end
51
- if @log_location != @output_location
52
- @output_location.copy(@log_location)
51
+ if @log_location != @temporary_location
52
+ @temporary_location.copy(@log_location)
53
53
  end
54
54
  super
55
55
  end
@@ -63,13 +63,13 @@ module Pione
63
63
  # Write records with sorting.
64
64
  def write_records(tuples)
65
65
  tuples.sort{|a,b| a.timestamp <=> b.timestamp}.each do |tuple|
66
- @output_location.append tuple.message.format(@log_id) + "\n"
66
+ @temporary_location.append tuple.message.format(@log_id) + "\n"
67
67
  end
68
68
  end
69
69
 
70
- # Get the output location. If the log location is not suportted append
70
+ # Get the temporary location. If the log location doesn't suport append
71
71
  # writing, output location is in local filesystem.
72
- def get_output_location
72
+ def get_temporary_location
73
73
  if @log_location.real_appendable?
74
74
  @log_location
75
75
  else
@@ -8,11 +8,12 @@ module Pione
8
8
  # tuple space
9
9
  # @param receiver [Log::MessageLogReceiver]
10
10
  # message log receiver
11
- def initialize(tuple_space, receiver)
11
+ def initialize(tuple_space, receiver, session_id)
12
12
  super(tuple_space)
13
13
 
14
14
  # message log receiver
15
15
  @receiver = receiver
16
+ @session_id = session_id
16
17
  end
17
18
 
18
19
  #
@@ -34,7 +35,7 @@ module Pione
34
35
  tuples.sort{|a,b| a.timestamp <=> b.timestamp}.each do |tuple|
35
36
  tuple.contents.tap do |contents|
36
37
  (contents.kind_of?(String) ? [contents] : contents).each do |msg|
37
- @receiver.receive(msg, tuple.level, tuple.head, tuple.color)
38
+ @receiver.receive(msg, tuple.level, tuple.head, tuple.color, @session_id)
38
39
  end
39
40
  end
40
41
  end
@@ -12,6 +12,17 @@ module Pione
12
12
  attr_reader :execution_thread
13
13
  attr_accessor :once # the agent will be killed at task completion if true
14
14
 
15
+ # @param [Pione::TupleSpace::TupleSpaceServer] tuple_space
16
+ # tuple space
17
+ # @param [String] features
18
+ # features that the task worker has
19
+ # @param [Hash] option
20
+ # @option option [] :env
21
+ # a environment object
22
+ # @option option [String] :session_id
23
+ # session ID
24
+ # @option option [URI] :request_from
25
+ # URI that a client requested from
15
26
  def initialize(tuple_space, features, env=nil)
16
27
  super(tuple_space)
17
28
  @tuple_space = tuple_space
@@ -43,6 +54,12 @@ module Pione
43
54
  # transitions
44
55
  #
45
56
 
57
+ def transit_to_init
58
+ @request_from = @tuple_space.attribute("request_from")
59
+ @session_id = @tuple_space.attribute("session_id")
60
+ @client_ui = @tuple_space.attribute("client_ui")
61
+ end
62
+
46
63
  # Take a task and turn it to foreground.
47
64
  def transit_to_take_task
48
65
  return take(TupleSpace::TaskTuple.new(features: @features))
@@ -122,16 +139,21 @@ module Pione
122
139
 
123
140
  # Make an engine from the task.
124
141
  def make_engine(task)
125
- RuleEngine.make(
126
- @tuple_space,
127
- @env,
128
- task.package_id,
129
- task.rule_name,
130
- task.inputs,
131
- task.param_set,
132
- task.domain_id,
133
- task.caller_id
134
- )
142
+ param = {
143
+ :tuple_space => @tuple_space,
144
+ :env => @env,
145
+ :package_id => task.package_id,
146
+ :rule_name => task.rule_name,
147
+ :inputs => task.inputs,
148
+ :param_set => task.param_set,
149
+ :domain_id => task.domain_id,
150
+ :caller_id => task.caller_id,
151
+ :request_from => @request_from,
152
+ :session_id => @session_id,
153
+ :client_ui => @client_ui
154
+ }
155
+
156
+ RuleEngine.make(param)
135
157
  end
136
158
 
137
159
  # Spawn child task worker. This method repeats to create a child agent
@@ -207,5 +207,23 @@ module Pione
207
207
  end
208
208
  end
209
209
  end
210
+
211
+ module SessionOption
212
+ extend Rootage::OptionCollection
213
+
214
+ define(:request_from) do |item|
215
+ item.type = :uri
216
+ item.long = "--request-from"
217
+ item.arg = "URI"
218
+ item.desc = "URI that the client requested the job from"
219
+ end
220
+
221
+ define(:session_id) do |item|
222
+ item.type = :string
223
+ item.long = "--session-id"
224
+ item.arg = "ID"
225
+ item.desc = "Session id of the job"
226
+ end
227
+ end
210
228
  end
211
229
  end
@@ -49,6 +49,9 @@ module Pione
49
49
  option(NotificationOption.notification_targets)
50
50
  option(NotificationOption.notification_receivers)
51
51
 
52
+ option(SessionOption.request_from)
53
+ option(SessionOption.session_id)
54
+
52
55
  option(:input_location) do |item|
53
56
  item.type = :location
54
57
  item.short = '-i'
@@ -57,23 +60,23 @@ module Pione
57
60
  item.desc = 'Set input directory'
58
61
  end
59
62
 
60
- option(:output_location) do |item|
63
+ option(:base_location) do |item|
61
64
  item.type = :location
62
- item.short = '-o'
63
- item.long = '--output'
65
+ item.short = '-b'
66
+ item.long = '--base'
64
67
  item.arg = 'LOCATION'
65
- item.desc = 'Set output directory'
66
- item.init = "local:./output/"
68
+ item.desc = 'Set process base location'
69
+ item.init = "local:./process/"
67
70
 
68
71
  item.process do |location|
69
- model[:output_location] = location
72
+ model[:base_location] = location
70
73
  if location.scheme == "myftp"
71
74
  model[:myftp] = URI.parse(uri).normalize
72
75
  end
73
76
  end
74
77
 
75
78
  item.exception(ArgumentError) do |e, val|
76
- raise OptionError.new(cmd, "output location '%s' is bad in %s" % [uri, cmd.name])
79
+ raise OptionError.new(cmd, "base location '%s' is bad in %s" % [uri, cmd.name])
77
80
  end
78
81
  end
79
82
 
@@ -135,7 +138,7 @@ module Pione
135
138
  item.arg = '[SCENARIO]'
136
139
  item.desc = 'rehearse the scenario'
137
140
 
138
- item.assign {|val| val.size != 0 ? val : :anything}
141
+ item.assign {|val| not(val.nil?) and val.size != 0 ? val : :anything}
139
142
  end
140
143
 
141
144
  option(:timeout) do |item|
@@ -145,6 +148,13 @@ module Pione
145
148
  item.desc = 'timeout processing after SEC'
146
149
  end
147
150
 
151
+ option(:client_ui) do |item|
152
+ item.type = :string
153
+ item.long = "--client-ui"
154
+ item.arg = "TYPE"
155
+ item.desc = "Type of the client's user interface"
156
+ end
157
+
148
158
  option_post(:validate_task_worker_size) do |item|
149
159
  item.desc = "Validate task worker size"
150
160
  item.process do
@@ -173,7 +183,7 @@ module Pione
173
183
  seq << :spawner_thread_group
174
184
  seq << :ftp_server
175
185
  seq << :tuple_space
176
- seq << :output_location
186
+ seq << :base_location
177
187
  seq << :lang_environment
178
188
  seq << :package
179
189
  seq << :scenario
@@ -217,18 +227,32 @@ module Pione
217
227
  # write tuples
218
228
  model[:tuple_space].write(TupleSpace::ProcessInfoTuple.new('standalone', 'Standalone'))
219
229
  model[:tuple_space].write(TupleSpace::DryRunTuple.new(model[:dry_run]))
230
+
231
+ if model[:request_from]
232
+ model[:tuple_space].write(TupleSpace::AttributeTuple.new("request_from", model[:request_from]))
233
+ end
234
+
235
+ if model[:session_id]
236
+ model[:tuple_space].write(TupleSpace::AttributeTuple.new("session_id", model[:session_id]))
237
+ end
238
+
239
+ if model[:client_ui]
240
+ model[:tuple_space].write(TupleSpace::AttributeTuple.new("client_ui", model[:client_ui]))
241
+ else
242
+ model[:tuple_space].write(TupleSpace::AttributeTuple.new("client_ui", "GUI"))
243
+ end
220
244
  end
221
245
  end
222
246
 
223
- setup(:output_location) do |item|
224
- item.desc = "Setup output location"
247
+ setup(:base_location) do |item|
248
+ item.desc = "Setup base location"
225
249
 
226
250
  # setup location
227
251
  item.process do
228
- case model[:output_location]
252
+ case model[:base_location]
229
253
  when Location::LocalLocation
230
- model[:output_location] = Location[model[:output_location].path.expand_path]
231
- model[:output_location].path.mkpath
254
+ model[:base_location] = Location[model[:base_location].path.expand_path]
255
+ model[:base_location].path.mkpath
232
256
  when Location::DropboxLocation
233
257
  Location::DropboxLocation.setup_for_cui_client(tuple_space_server)
234
258
  end
@@ -236,13 +260,13 @@ module Pione
236
260
 
237
261
  # mkdir
238
262
  item.process do
239
- test(not(model[:output_location].exist?))
240
- model[:output_location].mkdir
263
+ test(not(model[:base_location].exist?))
264
+ model[:base_location].mkdir
241
265
  end
242
266
 
243
267
  # set base location into tuple space
244
268
  item.process do
245
- model[:tuple_space].set_base_location(model[:output_location])
269
+ model[:tuple_space].set_base_location(model[:base_location])
246
270
  end
247
271
  end
248
272
 
@@ -270,7 +294,7 @@ module Pione
270
294
 
271
295
  # upload the package
272
296
  item.process do
273
- model[:package_handler].upload(model[:output_location] + "package")
297
+ model[:package_handler].upload(model[:base_location] + "package")
274
298
  end
275
299
 
276
300
  item.exception(Package::InvalidPackage) do |e|
@@ -349,7 +373,7 @@ module Pione
349
373
  receiver = Log::CUIMessageLogReceiver.new
350
374
  end
351
375
 
352
- Agent::Messenger.new(model[:tuple_space], receiver).start
376
+ Agent::Messenger.new(model[:tuple_space], receiver, model[:session_id]).start
353
377
  end
354
378
  end
355
379
 
@@ -358,7 +382,7 @@ module Pione
358
382
  item.desc = "Start a logger agent"
359
383
 
360
384
  item.assign(:logger) do
361
- Agent::Logger.start(model[:tuple_space], model[:output_location])
385
+ Agent::Logger.start(model[:tuple_space], model[:base_location])
362
386
  end
363
387
  end
364
388
 
@@ -412,7 +436,12 @@ module Pione
412
436
  item.desc = "Spawn a task worker"
413
437
 
414
438
  item.process do
415
- Command::PioneTaskWorker.spawn(model, Global.features, model[:tuple_space].uuid)
439
+ param = {
440
+ :features => Global.features,
441
+ :tuple_space_id => model[:tuple_space].uuid
442
+ }
443
+
444
+ Command::PioneTaskWorker.spawn(model, param)
416
445
  end
417
446
 
418
447
  item.exception(SpawnError) do |e|
@@ -506,7 +535,7 @@ module Pione
506
535
 
507
536
  pscenario = test(model[:package_handler].find_scenario(model[:rehearse]))
508
537
 
509
- errors = pscenario.validate(model[:output_location])
538
+ errors = pscenario.validate(model[:base_location])
510
539
  if errors.empty?
511
540
  Log::SystemLog.info "Rehearsal Result: Succeeded"
512
541
  else
@@ -1,3 +1,7 @@
1
+ require 'pione/global/interactive-variable'
2
+ require 'pione/front/interactive-front'
3
+ require 'pione/util/cgi'
4
+
1
5
  module Pione
2
6
  module Command
3
7
  class PioneInteractive < BasicCommand
@@ -7,11 +11,6 @@ module Pione
7
11
 
8
12
  require 'rexml/document'
9
13
 
10
- # debug mode only
11
- unless ENV["PIONE_JOB_ID"]
12
- require 'webrick'
13
- end
14
-
15
14
  #
16
15
  # informations
17
16
  #
@@ -19,40 +18,43 @@ module Pione
19
18
  define(:toplevel, true)
20
19
  define(:name, "pione-interactive")
21
20
  define(:desc, "interactive action handler")
21
+ define(:front, Front::InteractiveFront)
22
22
 
23
23
  #
24
24
  # arguments
25
25
  #
26
26
 
27
- argument(:xml) do |item|
28
- item.type = :location
29
- item.desc = "UI definition file"
30
- item.missing = "There are no definition file."
27
+ argument(:type) do |item|
28
+ item.type = :symbol_downcase
29
+ item.desc = "View type"
31
30
  end
32
31
 
33
32
  #
34
33
  # options
35
34
  #
36
35
 
37
- option(:ui) do |item|
38
- item.type = :symbol_downcase
39
- item.long = "--ui"
40
- item.arg = "NAME"
41
- item.desc = "User interface name"
36
+ option(:public) do |item|
37
+ item.desc = "public directory for interactive operation pages"
38
+ item.type = :location
39
+ item.long = "--public"
40
+ item.arg = "DIR"
41
+ item.init = "./public"
42
+ item.default = "./"
42
43
  end
43
44
 
44
- option_post(:validate_ui) do |item|
45
- item.desc = "Validate UI name"
46
-
47
- item.process do
48
- test(model[:ui].nil?)
49
- raise Rootage::OptionError.new(cmd, "No UI name")
50
- end
45
+ option(:output) do |item|
46
+ item.desc = "Output file"
47
+ item.type = :location
48
+ item.long = "--output"
49
+ item.short = "-o"
50
+ item.arg = "FILE"
51
+ end
51
52
 
52
- item.process do
53
- test(model[:ui] != :browser)
54
- raise Rootage::OptionError.new(cmd, "Unknown UI name: %s" % model[:ui])
55
- end
53
+ option(:timeout) do |item|
54
+ item.desc = "timeout after the second"
55
+ item.type = :integer
56
+ item.long = "--timeout"
57
+ item.arg = "SEC"
56
58
  end
57
59
 
58
60
  #
@@ -60,49 +62,75 @@ module Pione
60
62
  #
61
63
 
62
64
  phase(:setup) do |seq|
63
- seq << :ui_definition
65
+ seq << :session_id
66
+ seq << :interaction_id
64
67
  end
65
68
 
66
- setup(:ui_definition) do |item|
67
- item.desc = "Extract informations from UI definition"
69
+ setup(:session_id) do |item|
70
+ item.desc = "Setup session ID"
68
71
  item.process do
69
- fm = REXML::Formatters::Default.new
70
-
71
- # create a document
72
- doc = REXML::Document.new(model[:xml].read)
73
-
74
- # get the prefix of root element(e.g. "pione")
75
- prefix = doc.root.prefix
76
- prefix = prefix ? prefix + ":" : ""
77
-
78
- # get embeded contents
79
- content = REXML::XPath.first(doc, "/#{prefix}interactive/#{prefix}content")
80
- model[:content] = ""
81
- content.elements.each {|e| fm.write(e, model[:content])}
82
-
83
- # get embeded script
84
- script = REXML::XPath.first(doc, "/#{prefix}interactive/#{prefix}script")
85
- model[:script] = script.text
72
+ if ENV["PIONE_SESSION_ID"]
73
+ model[:session_id] = ENV["PIONE_SESSION_ID"]
74
+ model[:request_from] = ENV["PIONE_REQUEST_FROM"]
75
+ else
76
+ # debug mode only
77
+ require 'webrick'
78
+ end
86
79
  end
87
80
  end
88
81
 
82
+ setup(:interaction_id) do |item|
83
+ item.desc = "Setup interaction ID"
84
+ item.assign { Util::UUID.generate }
85
+ end
86
+
89
87
  #
90
88
  # command lifecycle: execution phase
91
89
  #
92
90
 
93
91
  phase(:execution) do |seq|
94
- if ENV["PIONE_JOB_ID"]
95
- seq << :connect_webclient
96
- else
97
- # debug mode
98
- seq << :debug_mode
99
- seq << :print_result
100
- end
92
+ seq << :render
93
+ seq << :print_result
101
94
  end
102
95
 
103
- execution(:debug_mode) do |item|
104
- item.desc = "Launch a debug server"
96
+ execution(:render) do |item|
97
+ item.desc = "Render a widget"
98
+
99
+ # this is called from webclient
100
+ item.process do
101
+ test(model[:session_id])
102
+ test(model[:request_from])
103
+
104
+ webclient = DRb::DRbObject.new_with_uri(model[:request_from])
105
+ case model[:type]
106
+ when :browser
107
+ result, status = webclient.request_interaction(
108
+ model[:session_id],
109
+ model[:interaction_id],
110
+ :browser,
111
+ {:front_address => model[:front].uri.to_s})
112
+ when :dialog
113
+ result, status = webclient.request_interaction(
114
+ model[:session_id],
115
+ model[:interaction_id],
116
+ :dialog,
117
+ {:content => model[:content], :script => model[:script]})
118
+ else
119
+ cmd.abort('Type "%s" is unknown.' % model[:type])
120
+ end
121
+ model[:result] = result
122
+
123
+ # command fails if the status is "failure"
124
+ if status == "failure"
125
+ self.exit_status = false
126
+ end
127
+ end
128
+
129
+ # this is called from the exception of webclient
105
130
  item.process do
131
+ test(not(model[:session_id] and model[:request_from]))
132
+ test(model[:definition])
133
+
106
134
  begin
107
135
  template = <<HTML
108
136
  <!DOCTYPE html>
@@ -174,13 +202,58 @@ HTML
174
202
  end
175
203
  end
176
204
  end
205
+
206
+ # this is called from the exception of webclient
207
+ item.process do
208
+ test(not(model[:session_id] and model[:request_from]))
209
+ test(model[:type] == :page)
210
+
211
+ begin
212
+ model[:debug_server] = WEBrick::HTTPServer.new(
213
+ :Port => 8080, :Logger => WEBrick::Log.new($stderr)
214
+ )
215
+
216
+ # page handler on '/'
217
+ model[:debug_server].mount("/", WEBrick::HTTPServlet::FileHandler, model[:public].path.to_s)
218
+
219
+ # finish
220
+ model[:debug_server].mount_proc("/finish") do |req, res|
221
+ model[:result] = req.query["result"]
222
+ model[:debug_server].shutdown
223
+ end
224
+
225
+ # shutdown handler on '/shutdown'
226
+ model[:debug_server].mount_proc("/shutdown") do |req, res|
227
+ model[:result] = req.body
228
+ model[:debug_server].shutdown
229
+ end
230
+
231
+ # `Kernel.trap` can take multiple INT handlers
232
+ trap("INT") { model[:debug_server].shutdown }
233
+
234
+ # show the location
235
+ $stderr.puts "See http://localhost:8080"
236
+
237
+ # start the debug server
238
+ model[:debug_server].start
239
+ ensure
240
+ if model[:debug_server]
241
+ model[:debug_server].shutdown
242
+ end
243
+ end
244
+
245
+ end
177
246
  end
178
247
 
179
248
  # Print a result string of interactive action to stdout.
180
249
  execution(:print_result) do |item|
181
250
  item.desc = "Print a result string."
182
251
  item.process do
183
- $stdout.print model[:result]
252
+ if model[:output]
253
+ model[:output].write model[:result]
254
+ else
255
+ $stdout.print model[:result]
256
+ end
184
257
  end
185
258
  end
186
259
  end