Revision 69a12fdb
Added by Marc Dequènes about 14 years ago
- ID 69a12fdbdbd27a5673fa8b848b4a03c2aa671004
lib/cyborghood/cyborg/conversation.rb | ||
---|---|---|
|
||
module BotProtocol
|
||
VERSION = "0.1"
|
||
CAPABILITIES = []
|
||
|
||
@@request_callback = proc{|result| process_request_result(result) }
|
||
|
||
# TODO:
|
||
# - check for request/reply couples (reply to wrong of non-existent request)
|
||
... | ... | |
end
|
||
end
|
||
|
||
def process_request_result(result)
|
||
if result[:error]
|
||
send_error_action(result[:reply_message], result[:error])
|
||
else
|
||
send_reply_result(result[:reply_message], result[:action_result])
|
||
end
|
||
end
|
||
|
||
def receive_announce_helo(message)
|
||
unless message.conv_thread.id == 0
|
||
return send_quit_decline "bad negociation"
|
||
... | ... | |
@negociation_ok = true
|
||
end
|
||
|
||
def receive_request_capabilities(message)
|
||
send_reply_result(message, @conversation.capabilities + CAPABILITIES)
|
||
end
|
||
|
||
def receive_request_call(message)
|
||
unless @conversation.bot.interface.is_node? message.parameters[:node]
|
||
return send_error_action(message, "bad node")
|
||
end
|
||
send_reply_ack(message)
|
||
@conversation.bot.schedule_task(@@request_callback) do
|
||
result = {
|
||
:reply_message => message
|
||
}
|
||
begin
|
||
result[:action_result] = @conversation.bot.interface.call(message.conv_thread.session,
|
||
message.parameters[:node],
|
||
message.parameters[:data])
|
||
rescue
|
||
result[:error] = $!
|
||
end
|
||
end
|
||
end
|
||
|
||
def receive_request_exists(message)
|
||
unless @conversation.bot.interface.is_node? message.parameters[:node]
|
||
return send_error_action(message, "bad node")
|
||
end
|
||
send_reply_ack(message)
|
||
@conversation.bot.schedule_task(@@request_callback) do
|
||
{
|
||
:reply_message => message,
|
||
:action_result => @conversation.bot.interface.has_node? message.parameters[:node]
|
||
}
|
||
end
|
||
end
|
||
|
||
def receive_request_describe(message)
|
||
# TODO: implement when ready in the interface
|
||
send_quit_decline(message, "not implemented")
|
||
end
|
||
|
||
def send_announce_helo(recv_message = nil)
|
||
action_code = "ANNOUNCE HELO"
|
||
message = (recv_message.nil? ? @conversation.thread('system').new_message(action_code) :
|
||
... | ... | |
recv_message.create_reply("ANNOUNCE OK").send
|
||
end
|
||
|
||
def send_request_capabilities
|
||
@conversation.thread('system').new_message("REQUEST EXISTS", { :node => node }).send
|
||
end
|
||
|
||
def send_request_call(conv_thread, node)
|
||
conv_thread.new_message("REQUEST CALL", { :node => node }).send
|
||
end
|
||
|
||
def send_request_exists(conv_thread, node)
|
||
conv_thread.new_message("REQUEST EXISTS", { :node => node }).send
|
||
end
|
||
|
||
def send_request_describe(conv_thread, node)
|
||
conv_thread.new_message("REQUEST DESCRIBE", { :node => node }).send
|
||
end
|
||
|
||
def send_error_protocol(error, fatal = false)
|
||
@conversation.thread('system').new_message("ERROR PROTOCOL", { :error => error }).send
|
||
@conversation.set_error_status(fatal)
|
||
end
|
||
|
||
def send_error_action(recv_message, message)
|
||
recv_message.create_reply("ERROR ACTION", { :error => message }).send
|
||
def send_error_action(recv_message, error)
|
||
recv_message.create_reply("ERROR ACTION", { :error => error }).send
|
||
end
|
||
|
||
def send_reply_ack(recv_message)
|
||
... | ... | |
@protocol = BotProtocol.new(self)
|
||
end
|
||
|
||
def clear_receive_info
|
||
@receive_error = false
|
||
@receive_fatal_error = false
|
||
end
|
||
|
||
def send_line(msg)
|
||
send_data "#{msg}\n"
|
||
logger.debug "Sent data [#{identifier}]: #{msg}"
|
||
def capabilities
|
||
[]
|
||
end
|
||
|
||
def post_init
|
||
... | ... | |
check_errors
|
||
end
|
||
|
||
def check_errors
|
||
@error_count += 1 if @receive_error
|
||
|
||
msg_quit = nil
|
||
if @error_count >= MAXIMUM_ERROR_COUNT
|
||
msg_quit = "too much errors, terminating"
|
||
elsif @fatal_error
|
||
msg_quit = "previous fatal error"
|
||
end
|
||
|
||
unless msg_quit.nil?
|
||
send_quit_decline msg_quit
|
||
close_connection_after_writing
|
||
end
|
||
end
|
||
|
||
def receive_message(message)
|
||
logger.debug "Received message '#{action}' [#{identifier}]"
|
||
|
||
... | ... | |
|
||
protected
|
||
|
||
def clear_receive_info
|
||
@receive_error = false
|
||
@receive_fatal_error = false
|
||
end
|
||
|
||
def send_line(msg)
|
||
logger.debug "Sending data [#{identifier}]: #{msg}"
|
||
send_data "#{msg}\n"
|
||
end
|
||
|
||
def check_errors
|
||
@error_count += 1 if @receive_error
|
||
|
||
msg_quit = nil
|
||
if @error_count >= MAXIMUM_ERROR_COUNT
|
||
msg_quit = "too much errors, terminating"
|
||
elsif @fatal_error
|
||
msg_quit = "previous fatal error"
|
||
end
|
||
|
||
unless msg_quit.nil?
|
||
send_quit_decline msg_quit
|
||
close_connection_after_writing
|
||
end
|
||
end
|
||
|
||
def new_thread(name, id = nil)
|
||
id ||= @next_thread_id
|
||
th = ConversationThread.new(self, id, name)
|
||
... | ... | |
def identifier
|
||
"unix_socket/#{@signature}"
|
||
end
|
||
|
||
def capabilities
|
||
super + []
|
||
end
|
||
end
|
||
end
|
lib/cyborghood/cyborg/interface.rb | ||
---|---|---|
def export_parent_methods
|
||
self.export_method *self.superclass.public_instance_methods(false)
|
||
end
|
||
|
||
def is_node?(node)
|
||
(node =~ NODE_PATTERN) ? true : false
|
||
end
|
||
end
|
||
|
||
def initialize(*args)
|
||
... | ... | |
self.class.auto_export_public_instance_methods = true
|
||
end
|
||
|
||
# convenience method
|
||
def is_node?(node)
|
||
self.class.is_node?(node)
|
||
end
|
||
|
||
def api_klasses
|
||
list = self.class.constants.collect do |c|
|
||
cc = self.class.const_get(c)
|
||
... | ... | |
# preliminary incoming message handling
|
||
def call(session, cmd, data)
|
||
action = find_node_action(session, cmd)
|
||
return "551 unknown node" if action.nil?
|
||
raise "unknown node" if action.nil?
|
||
|
||
if data.nil?
|
||
formated_data = []
|
||
else
|
||
begin
|
||
formated_data = YAML.load(data) unless data.nil?
|
||
rescue
|
||
return "552 unreadable YAML data for arguments"
|
||
end
|
||
|
||
return "552 wrong format for arguments" unless formated_data.is_a? Array
|
||
end
|
||
raise "wrong format for arguments" unless data.is_a? Array
|
||
|
||
begin
|
||
# preliminary outgoing message handling
|
||
action.call(*formated_data).to_yaml
|
||
action.call(*data)
|
||
rescue
|
||
logger.debug "node action error message: " + $!
|
||
logger.debug "node action error backtrace: " + $!.backtrace.join("\n")
|
||
return "550 method call failed: " + $!
|
||
raise "method call failed: " + $!
|
||
end
|
||
end
|
||
end
|
lib/cyborghood/cyborg/server.rb | ||
---|---|---|
def unregister_communication(peer)
|
||
@comm_list.delete(peer)
|
||
end
|
||
|
||
def schedule_task(callback, &task)
|
||
EventMachine.defer(task, callback)
|
||
end
|
||
end
|
||
|
||
class BotServerUNIXSocket < BotServer
|
Also available in: Unified diff
[evol] conversation/bot protocol rework §6 (refs #30)