Project

General

Profile

« Previous | Next » 

Revision a089227c

Added by Marc Dequènes about 13 years ago

  • ID a089227ca94121115f46e5998b497fa102787398

[fix/evol] work on better Interface/Task/Conversation/… sync and bot stop action in order to avoid races and locks

View differences:

lib/cyborghood/cyborg/botnet/conversation.rb
@sent
end
def send
def send(go_quiet = false)
raise CyberError.new(:unrecoverable, "bot/conversation", "Not sending twice the same message") if self.sent?
@action_id = @conv_thread.next_action_id if @action_id.nil?
@conv_thread.conversation.send_message(self)
@conv_thread.conversation.send_message(self, go_quiet)
@sent = true
# return message (convenience)
......
@split_data_message = nil
@split_data = []
@comm_stop = false
@comm_dead = false
# associated conversation threads
@auto_close_threads = 60 # max idle time before closing (nil => never close threads)
......
@next_thread_id = 0
@system_thread = self.thread('system')
@stop_when_finished = false
# post-negociation peer info
@peer_name = nil
@peer_capabilities = []
......
def unbind
logger.info "Conversation finished with #{identifier} (#{@peer_name})"
# ensure we go quiet
@message_send.synchronize do
@comm_stop = true
end
@comm_dead = true
@bot.unregister_communication @peer_name unless @peer_name.nil?
@bot.drop_channel(@system_notification_name)
@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
def usuable?
not (@comm_dead or @comm_stop)
end
def bye
@protocol.send_quit_leaving
stop :quickly
end
def stop(condition)
case condition
when :when_finished
@stop_when_finished = true
when :quickly
@protocol.send_quit_leaving
end
end
def set_peer_info(name, capabilities)
......
end
def set_comm_stop(peer_left = false)
@comm_stop = true
return if @comm_stop
logger.debug "Conversation with '#{@peer_name}' on #{identifier} is closing"
@system_notification.unsubscribe(@system_notification_processing)
# the block may use a <message>.send(true) to go quiet (set @comm_stop)
yield if block_given?
# ensure we go quiet
@message_send.synchronize do
@comm_stop = true
end
peer_left ? close_connection : close_connection_after_writing
end
......
@conv_threads_closing.delete(th.name)
end
def send_message(message)
def send_message(message, quiet_after = false)
raise CyberError.new(:unrecoverable, "bot/conversation", "Cannot send message without action id") if message.action_id.nil?
reset_idle_thread_check(message.conv_thread)
......
flags += "+" unless message.action_parameters.nil?
@message_send.synchronize do
send_line sprintf("%s-%04d-%04d%s %s", @bot.name, message.conv_thread.id, message.action_id, flags, message.action_code)
unless message.action_parameters.nil?
message.action_parameters.to_yaml.each_line {|l| send_line l }
send_line EOD
unless @comm_stop
send_line sprintf("%s-%04d-%04d%s %s", @bot.name, message.conv_thread.id, message.action_id, flags, message.action_code)
unless message.action_parameters.nil?
message.action_parameters.to_yaml.each_line {|l| send_line l }
send_line EOD
end
@comm_stop = true if quiet_after
end
end
......
def send_line(msg)
return if error?
return if @comm_stop
logger.debug "Sending data [#{identifier}]: #{msg}"
send_data "#{msg}\n"
......
@conv_threads_timers_manage.synchronize do
# if a timer is running, do nothing
return unless @conv_threads_timers[conv_thread.id].nil?
end
# test for idleness
if conv_thread.idle?
logger.debug "Thread '#{conv_thread.name}@#{@peer_name}' is currently idle, doing another check in #{@auto_close_threads}s"
# test for idleness
if conv_thread.idle?
if @stop_when_finished
logger.debug "Thread '#{conv_thread.name}@#{@peer_name}' is currently idle, considered finished, closing"
close_thread(conv_thread.name)
return
end
logger.debug "Thread '#{conv_thread.name}@#{@peer_name}' is currently idle, doing another check in #{@auto_close_threads}s"
# send notification
@bot.get_channel(@system_notification_name) << {
:topic => 'THREAD IDLE',
:thread => conv_thread.name
}
# send notification
@bot.get_channel(@system_notification_name) << {
:topic => 'THREAD IDLE',
:thread => conv_thread.name
}
@conv_threads_timers_manage.synchronize do
# set timer for closing
@conv_threads_timers[conv_thread.id] = EventMachine.add_timer(@auto_close_threads) do
@conv_threads_timers[conv_thread.id] = nil

Also available in: Unified diff