commit 4afb2001a4b374e656585a1bccdc629d94d74ad9
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Fri Nov 12 18:33:40 2010 +0100

    [evol] preliminary work for NOTIFY: closed thread are handled but close too early in most situations yet (need request/reply tracking)

diff --git a/bin/mapmaker_client b/bin/mapmaker_client
index aac5dfa..459a68a 100755
--- a/bin/mapmaker_client
+++ b/bin/mapmaker_client
@@ -39,9 +39,10 @@ module CyborgHood
         contact_peer("MapMaker") do |conv|
           if conv
             logger.info "Yo ! Conversation ready with MapMaker (#{conv.peer_name}) !"
-            conv_thread = conv.thread("plop")
-            conv.protocol.send_request_call(conv_thread, "/") do |reply|
-              pp reply
+            conv.thread("plop") do |conv_thread|
+              conv.protocol.send_request_call(conv_thread, "/coucou") do |reply|
+                pp reply
+              end
             end
           else
             logger.error "Could not connect to MapMaker"
diff --git a/lib/cyborghood/cyborg/conversation.rb b/lib/cyborghood/cyborg/conversation.rb
index ef248d9..9b74fc4 100644
--- a/lib/cyborghood/cyborg/conversation.rb
+++ b/lib/cyborghood/cyborg/conversation.rb
@@ -30,7 +30,8 @@ module CyborgHood
       @name = name
       @id = id
 
-      @session = Session.new
+      # no need for session for system thread
+      @session = Session.new unless name == 'system'
       @next_action_id = 0
     end
 
@@ -44,7 +45,11 @@ module CyborgHood
       id
     end
 
-    def close
+    def close(notify = true)
+      # the system thread cannot be closed
+      return if name == 'system'
+      @conversation.protocol.send_notify_thread_closed(self) if notify
+      @conversation.delete_thread(self)
       @session.clear
     end
   end
@@ -197,7 +202,9 @@ module CyborgHood
     def unbind
       logger.info "Conversation finished with #{identifier} (#{@peer_name})"
       @bot.unregister_communication @peer_name unless @peer_name.nil?
-      @conv_threads.each_value {|s| s.close }
+      @conv_threads.each_value {|s| s.close(false) }
+      @conv_threads = {}
+      @conv_threads_index = {}
       @comm_logic_block.call false unless @comm_logic_block.nil? or @protocol.negociation_ok?
     end
 
@@ -231,7 +238,14 @@ module CyborgHood
     end
 
     def thread(name = 'default')
-      @conv_threads[name] || new_thread(name)
+      th = @conv_threads[name] || new_thread(name)
+      if block_given?
+        yield th
+        # TODO: wait for end of chat
+        close_thread(name)
+      else
+        th
+      end
     end
 
     def thread_by_id(id)
@@ -239,6 +253,19 @@ module CyborgHood
       name.nil? ? new_thread("noname/#{id}", id) : @conv_threads[name]
     end
 
+    def close_thread(name)
+      return if name == 'system'
+      # ignore mistakes
+      return unless @conv_threads.has_key? name
+
+      @conv_threads[name].close
+    end
+
+    def delete_thread(th)
+      @conv_threads_index.delete(th.id)
+      @conv_threads.delete(th.name)
+    end
+
     def send_message(message)
       raise CyberError.new(:unrecoverable, "bot/conversation", "Cannot send message without action id") if message.action_id.nil?
 
diff --git a/lib/cyborghood/cyborg/protocol.rb b/lib/cyborghood/cyborg/protocol.rb
index b5e142e..534b02c 100644
--- a/lib/cyborghood/cyborg/protocol.rb
+++ b/lib/cyborghood/cyborg/protocol.rb
@@ -157,6 +157,16 @@ module CyborgHood
       end
     end
 
+    # TODO: what is the peer close a thread i have opened ?
+    #       send error to all actions ?
+    def receive_notify_thread_closed(message)
+      message.conv_thread.close(false)
+    end
+
+    def receive_notify_event(message)
+      # TODO
+    end
+
     def receive_reply_ack(message)
       # TODO
     end
@@ -236,6 +246,14 @@ module CyborgHood
       recv_message.create_reply("ERROR ACTION", { :error => error }).send
     end
 
+    def send_notify_thread_closed(conv_thread)
+      conv_thread.new_message("NOTIFY THREAD CLOSED").send
+    end
+
+    def send_notify_event(conv_thread, event_name, event_info)
+      conv_thread.new_message.create_reply("NOTIFY EVENT", { :name => event_name, :info => event_info }).send
+    end
+
     def send_reply_ack(recv_message)
       recv_message.create_reply("REPLY ACK").send
     end
