commit 9f407d69de35c34fa55382f4a137b1cec6e739af
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Thu Mar 10 01:17:36 2011 +0100

    [evol] Botnet/Task: added 'ask :self' support (useful for Clerk batch processing)

diff --git a/bin/test_client b/bin/test_client
index 859a5a0..be25439 100755
--- a/bin/test_client
+++ b/bin/test_client
@@ -60,7 +60,14 @@ module CyborgHood
           #know? "MapMaker", :k2, "/prout"
           set_user "guihome"
           set_preferred_locales "fr"
-          ask "Clerk", :dns_info, "/Commands/DNS/INFO"
+          #ask "Clerk", :dns_info, "/Commands/DNS/INFO"
+          ask "Clerk", :dns_info, "/Batch/taiste"
+#           ask "Clerk", :dns_info, "/Batch", {
+#             :commands => [
+#                           ["DNS", "INFO"]
+# #                          ["DNS", "INFO"]
+#                          ]
+#           }
           on_error do
             puts "PLOUF"
             pp errors
diff --git a/lib/cyborghood-clerk/interface/0_base.rb b/lib/cyborghood-clerk/interface/0_base.rb
index f49f5df..01dd3d1 100644
--- a/lib/cyborghood-clerk/interface/0_base.rb
+++ b/lib/cyborghood-clerk/interface/0_base.rb
@@ -2,4 +2,26 @@ node 'Commands', :dir => '_commands'
 
 node 'Batch' do
   # TODO
+
+  # test node
+  node 'taiste' do
+    on_request do |request|
+      task 'batch_commands' do
+        # propagate environment
+        set_user request.env.user
+        set_preferred_locales request.env.preferred_locales
+
+        ask :self, :dns_info, "/Commands/DNS/INFO"
+        on_error do
+          puts "Batch PLOUF"
+          request.reply.errors << "Internal error"
+          request.send_reply
+        end
+        on_success do
+          request.reply.results = results[:dns_info]
+          request.send_reply
+        end
+      end
+    end
+  end
 end
diff --git a/lib/cyborghood-clerk/interface/_commands/_dns/info.rb b/lib/cyborghood-clerk/interface/_commands/_dns/info.rb
index 2cb5470..3f59f70 100644
--- a/lib/cyborghood-clerk/interface/_commands/_dns/info.rb
+++ b/lib/cyborghood-clerk/interface/_commands/_dns/info.rb
@@ -5,6 +5,7 @@ node 'INFO', :case_insensitive => true do
       logger.warn "User: #{request.env.user}"
 
       # do later requests using provided token
+      # TODO: check is not empty
       set_user request.env.user
 
       # cannot search directly 'person/<user>' until LdapShadows is used,
diff --git a/lib/cyborghood/cyborg/botnet/task.rb b/lib/cyborghood/cyborg/botnet/task.rb
index 1975121..69fa164 100644
--- a/lib/cyborghood/cyborg/botnet/task.rb
+++ b/lib/cyborghood/cyborg/botnet/task.rb
@@ -23,21 +23,11 @@ module CyborgHood
       def ask(peer, key, cmd, *args)
         action_name = ['ask', cmd, *args].hash
 
-        _add_subtask_using_peer(action_name, peer) do |subtask, conv_thread, env|
-          cmd = cmd.call if cmd.is_a? Proc
-          args.collect!{|a| a.is_a?(Proc) ? a.call : a }
-
-          conv_thread.call(env, cmd, *args) do |reply|
-            case reply[:status]
-            when :ok
-              subtask.results = {key => reply[:result]}
-            when :decline
-              # TODO: remove this case ???
-            when :error
-              subtask.errors += reply[:exceptions]
-            end
-
-            subtask.finish
+        _add_subtask_using_peer(action_name, key, peer, cmd, args) do |conv_thread, env, cmd, args, reply_cb|
+          if peer == :self
+            @bot.interface._call(nil, env, cmd, args, &reply_cb)
+          else
+            conv_thread.call(env, cmd, *args, &reply_cb)
           end
         end
       end
@@ -45,29 +35,24 @@ module CyborgHood
       def know?(peer, key, cmd)
         action_name = ['know', cmd].hash
 
-        _add_subtask_using_peer(action_name, peer) do |subtask, conv_thread, env|
-          cmd = cmd.call if cmd.is_a? Proc
-
-          conv_thread.exists?(env, cmd) do |reply|
-            case reply[:status]
-            when :ok
-              subtask.results = {key => reply[:result]}
-            when :decline
-              # TODO: remove this case ???
-            when :error
-              subtask.errors += reply[:exceptions]
-            end
-
-            subtask.finish
+        _add_subtask_using_peer(action_name, key, peer, cmd, args) do |conv_thread, env, cmd, args, reply_cb|
+          if peer == :self
+            @bot.interface._is_node?(nil, env, cmd, &reply_cb)
+          else
+            conv_thread.exists?(env, cmd, &reply_cb)
           end
         end
       end
 
-      def _add_subtask_using_peer(action_name, peer)
+      def _add_subtask_using_peer(action_name, key, peer, cmd, args = nil, &cmd_cb)
         subtask_name = "botnet/peer/#{peer}/#{action_name}/out"
 
         _add_subtask(subtask_name) do |subtask|
-          logger.debug "Task '#{@name}': Trying to contact peer '#{peer}'"
+          if peer == :self
+            logger.debug "Task '#{@name}': Talking to oneself"
+          else
+            logger.debug "Task '#{@name}': Trying to contact peer '#{peer}'"
+          end
 
           # callback to end peer action and subtask
           # (used when shooting the task)
@@ -84,31 +69,77 @@ module CyborgHood
             registered_resources[subtask_name] = defuse_peer_action_cb
           end
 
+          cmd = cmd.call if cmd.is_a? Proc
+          args.collect!{|a| a.is_a?(Proc) ? a.call : a }
+
           # catch current environment to transmit it
           env = {
             :preferred_locales  => @preferred_locales,
             :user               => @user
           }
 
-          @bot.contact_peer(peer) do |conv|
-            if conv
-              logger.debug "Task '#{@name}': subtask '#{subtask.name}': peer '#{peer}' contacted, starting conversation"
+          reply_cb = Proc.new do |reply|
+            case reply[:status]
+            when :ok
+              subtask.results = {key => reply[:result]}
+            when :decline
+              # TODO: remove this case ???
+            when :error
+              subtask.errors += reply[:exceptions]
+            end
 
-              @peer_contacted << peer
+            subtask.finish
+          end
 
-              # don't use the block call to leave the conversation thread open
-              conv_thread = conv.thread(@notification_name)
+          if peer == :self
+            _run_subtask_using_peer_local(subtask, env, cmd, args, cmd_cb, reply_cb)
+          else
+            _run_subtask_using_peer_remote(subtask, env, peer, cmd, args, cmd_cb, reply_cb)
+          end
+        end
+      end
 
-              yield(subtask, conv_thread, env)
-            else
-              logger.debug "Task '#{@name}': Could not contact peer '#{peer}'"
-              subtask.errors << CyberError.new(:unrecoverable, "botnet/client/dsl", "Task '#{@name}': could not contact peer '#{peer}'")
-              subtask.finish
-            end
+      def _run_subtask_using_peer_remote(subtask, env, peer, cmd, args, cmd_cb, reply_cb)
+        @bot.contact_peer(peer) do |conv|
+          if conv
+            logger.debug "Task '#{@name}': subtask '#{subtask.name}': peer '#{peer}' contacted, starting conversation"
+
+            @peer_contacted << peer
+
+            # don't use the block call to leave the conversation thread open
+            conv_thread = conv.thread(@notification_name)
+
+            cmd_cb.call(conv_thread, env, cmd, args, reply_cb)
+          else
+            logger.debug "Task '#{@name}': Could not contact peer '#{peer}'"
+            subtask.errors << CyberError.new(:unrecoverable, "botnet/client/dsl", "Task '#{@name}': could not contact peer '#{peer}'")
+            subtask.finish
           end
         end
       end
 
+      def _run_subtask_using_peer_local(subtask, env, cmd, args, cmd_cb, reply_cb)
+        process_result_cb = Proc.new do |reply|
+          # reformat reply
+          new_reply = {
+            :status  => :ok,
+            :result  => reply[:results]
+          }
+
+          reply_cb.call new_reply
+        end
+
+        begin
+          cmd_cb.call(nil, env, cmd, args, process_result_cb)
+        rescue CyberError => e
+          subtask.errors << e
+          subtask.finish
+        rescue
+          subtask.errors << CyberError.new(:unrecoverable, 'unknown', $!.message)
+          subtask.finish
+        end
+      end
+
       def _setup
         super
 
