Project

General

Profile

« Previous | Next » 

Revision 69a12fdb

Added by Marc Dequènes almost 11 years ago

  • ID 69a12fdbdbd27a5673fa8b848b4a03c2aa671004

[evol] conversation/bot protocol rework §6 (refs #30)

View differences:

lib/cyborghood/cyborg/conversation.rb
26 26

  
27 27
  module BotProtocol
28 28
    VERSION = "0.1"
29
    CAPABILITIES = []
30

  
31
    @@request_callback = proc{|result| process_request_result(result) }
29 32

  
30 33
    # TODO:
31 34
    #   - check for request/reply couples (reply to wrong of non-existent request)
......
52 55
      end
53 56
    end
54 57

  
58
    def process_request_result(result)
59
      if result[:error]
60
        send_error_action(result[:reply_message], result[:error])
61
      else
62
        send_reply_result(result[:reply_message], result[:action_result])
63
      end
64
    end
65

  
55 66
    def receive_announce_helo(message)
56 67
      unless message.conv_thread.id == 0
57 68
        return send_quit_decline "bad negociation"
......
81 92
      @negociation_ok = true
82 93
    end
83 94

  
95
    def receive_request_capabilities(message)
96
      send_reply_result(message, @conversation.capabilities + CAPABILITIES)
97
    end
98

  
99
    def receive_request_call(message)
100
      unless @conversation.bot.interface.is_node? message.parameters[:node]
101
        return send_error_action(message, "bad node")
102
      end
103
      send_reply_ack(message)
104
      @conversation.bot.schedule_task(@@request_callback) do
105
        result = {
106
          :reply_message => message
107
        }
108
        begin
109
          result[:action_result] = @conversation.bot.interface.call(message.conv_thread.session,
110
                                                                    message.parameters[:node],
111
                                                                    message.parameters[:data])
112
        rescue
113
          result[:error] = $!
114
        end
115
      end
116
    end
117

  
118
    def receive_request_exists(message)
119
      unless @conversation.bot.interface.is_node? message.parameters[:node]
120
        return send_error_action(message, "bad node")
121
      end
122
      send_reply_ack(message)
123
      @conversation.bot.schedule_task(@@request_callback) do
124
        {
125
          :reply_message => message,
126
          :action_result => @conversation.bot.interface.has_node? message.parameters[:node]
127
        }
128
      end
129
    end
130

  
131
    def receive_request_describe(message)
132
      # TODO: implement when ready in the interface
133
      send_quit_decline(message, "not implemented")
134
    end
135

  
84 136
    def send_announce_helo(recv_message = nil)
85 137
      action_code = "ANNOUNCE HELO"
86 138
      message = (recv_message.nil? ? @conversation.thread('system').new_message(action_code) :
......
92 144
      recv_message.create_reply("ANNOUNCE OK").send
93 145
    end
94 146

  
147
    def send_request_capabilities
148
      @conversation.thread('system').new_message("REQUEST EXISTS", { :node => node }).send
149
    end
150

  
151
    def send_request_call(conv_thread, node)
152
      conv_thread.new_message("REQUEST CALL", { :node => node }).send
153
    end
154

  
155
    def send_request_exists(conv_thread, node)
156
      conv_thread.new_message("REQUEST EXISTS", { :node => node }).send
157
    end
158

  
159
    def send_request_describe(conv_thread, node)
160
      conv_thread.new_message("REQUEST DESCRIBE", { :node => node }).send
161
    end
162

  
95 163
    def send_error_protocol(error, fatal = false)
96 164
      @conversation.thread('system').new_message("ERROR PROTOCOL", { :error => error }).send
97 165
      @conversation.set_error_status(fatal)
98 166
    end
99 167

  
100
    def send_error_action(recv_message, message)
101
      recv_message.create_reply("ERROR ACTION", { :error => message }).send
168
    def send_error_action(recv_message, error)
169
      recv_message.create_reply("ERROR ACTION", { :error => error }).send
102 170
    end
103 171

  
104 172
    def send_reply_ack(recv_message)
......
218 286
      @protocol = BotProtocol.new(self)
219 287
    end
220 288

  
221
    def clear_receive_info
222
      @receive_error = false
223
      @receive_fatal_error = false
224
    end
225

  
226
    def send_line(msg)
227
      send_data "#{msg}\n"
228
      logger.debug "Sent data [#{identifier}]: #{msg}"
289
    def capabilities
290
      []
229 291
    end
230 292

  
231 293
    def post_init
......
277 339
      check_errors
278 340
    end
279 341

  
280
    def check_errors
281
      @error_count += 1 if @receive_error
282

  
283
      msg_quit = nil
284
      if @error_count >= MAXIMUM_ERROR_COUNT
285
        msg_quit = "too much errors, terminating"
286
      elsif @fatal_error
287
        msg_quit = "previous fatal error"
288
      end
289

  
290
      unless msg_quit.nil?
291
        send_quit_decline msg_quit
292
        close_connection_after_writing
293
      end
294
    end
295

  
296 342
    def receive_message(message)
297 343
      logger.debug "Received message '#{action}' [#{identifier}]"
298 344

  
......
349 395

  
350 396
    protected
351 397

  
398
    def clear_receive_info
399
      @receive_error = false
400
      @receive_fatal_error = false
401
    end
402

  
403
    def send_line(msg)
404
      logger.debug "Sending data [#{identifier}]: #{msg}"
405
      send_data "#{msg}\n"
406
    end
407

  
408
    def check_errors
409
      @error_count += 1 if @receive_error
410

  
411
      msg_quit = nil
412
      if @error_count >= MAXIMUM_ERROR_COUNT
413
        msg_quit = "too much errors, terminating"
414
      elsif @fatal_error
415
        msg_quit = "previous fatal error"
416
      end
417

  
418
      unless msg_quit.nil?
419
        send_quit_decline msg_quit
420
        close_connection_after_writing
421
      end
422
    end
423

  
352 424
    def new_thread(name, id = nil)
353 425
      id ||= @next_thread_id
354 426
      th = ConversationThread.new(self, id, name)
......
411 483
    def identifier
412 484
      "unix_socket/#{@signature}"
413 485
    end
486

  
487
    def capabilities
488
      super + []
489
    end
414 490
  end
415 491
end
lib/cyborghood/cyborg/interface.rb
47 47
      def export_parent_methods
48 48
        self.export_method *self.superclass.public_instance_methods(false)
49 49
      end
50

  
51
      def is_node?(node)
52
        (node =~ NODE_PATTERN) ? true : false
53
      end
50 54
    end
51 55

  
52 56
    def initialize(*args)
......
58 62
      self.class.auto_export_public_instance_methods = true
59 63
    end
60 64

  
65
    # convenience method
66
    def is_node?(node)
67
      self.class.is_node?(node)
68
    end
69

  
61 70
    def api_klasses
62 71
      list = self.class.constants.collect do |c|
63 72
        cc = self.class.const_get(c)
......
146 155
    # preliminary incoming message handling
147 156
    def call(session, cmd, data)
148 157
      action = find_node_action(session, cmd)
149
      return "551 unknown node" if action.nil?
158
      raise "unknown node" if action.nil?
150 159

  
151
      if data.nil?
152
        formated_data = []
153
      else
154
        begin
155
          formated_data = YAML.load(data) unless data.nil?
156
        rescue
157
          return "552 unreadable YAML data for arguments"
158
        end
159

  
160
        return "552 wrong format for arguments" unless formated_data.is_a? Array
161
      end
160
      raise "wrong format for arguments" unless data.is_a? Array
162 161

  
163 162
      begin
164
        # preliminary outgoing message handling
165
        action.call(*formated_data).to_yaml
163
        action.call(*data)
166 164
      rescue
167 165
        logger.debug "node action error message: " + $!
168 166
        logger.debug "node action error backtrace: " + $!.backtrace.join("\n")
169
        return "550 method call failed: " + $!
167
        raise "method call failed: " + $!
170 168
      end
171 169
    end
172 170
  end
lib/cyborghood/cyborg/server.rb
63 63
    def unregister_communication(peer)
64 64
      @comm_list.delete(peer)
65 65
    end
66

  
67
    def schedule_task(callback, &task)
68
      EventMachine.defer(task, callback)
69
    end
66 70
  end
67 71

  
68 72
  class BotServerUNIXSocket < BotServer

Also available in: Unified diff