+ def writer_loop
+ loop do
+ # we could wait for the message, then calculate the delay and sleep
+ # if necessary. however, if high-priority message is enqueued while
+ # we sleep, it won't be the first to go out when the sleep is over.
+ # thus, we have to call Time.now() twice, once to calculate the delay
+ # and once to adjust @burst / @flood_send.
+ begin
+ now = Time.now
+ if @sendq_delay > 0
+ burst_delay = 0
+ if @burst > @sendq_burst
+ burst_delay = @last_send + @sendq_delay - now
+ end
+
+ flood_delay = @flood_send - MAX_IRC_SEND_PENALTY - now
+ delay = [burst_delay, flood_delay, 0].max
+ if delay > 0
+ debug "sleep(#{delay}) # (f: #{flood_delay}, b: #{burst_delay})"
+ sleep(delay)
+ end
+ end
+ msg = @sendq.shift
+ now = Time.now
+ @flood_send = now if @flood_send < now
+ @burst = 0 if @last_send + @sendq_delay < now
+ debug "got #{msg.inspect} from queue, sending"
+ emergency_puts(msg, true)
+ rescue Exception => e
+ error "Spooling failed: #{e.pretty_inspect}"
+ debug e.backtrace.join("\n")
+ raise e
+ end
+ end
+ end
+
+ # same as puts, but expects to be called with a lock held on @sock