lib/safubot/bot.rb in safubot-0.0.2 vs lib/safubot/bot.rb in safubot-0.0.3

- old
+ new

@@ -1,12 +1,16 @@ #!/usr/bin/env ruby module Safubot + ## + # Pretty-printing of Exceptions and their backtraces. + # @param e An Exception to print. def error_report(e) "#{e.inspect}\n#{e.backtrace.join("\n\t")}" end + ## # Defines elements of the input queue, agnostic of the transfer medium. # May be extended by service-specific modules. class Request include MongoMapper::Document safe @@ -16,15 +20,13 @@ key :text, String # The actual content. belongs_to :source, :polymorphic => true # The concrete medium-specific source. belongs_to :user, :polymorphic => true many :responses, :class_name => "Safubot::Response" timestamps! - - attr_accessor :callback # If a callback is set, responses will be sent to it instead of Response. - end + ## # Defines elements of the output queue, agnostic of the transfer medium. # May be extended by service-specific modules. class Response include MongoMapper::Document safe @@ -33,24 +35,33 @@ key :text, String belongs_to :request, :polymorphic => true timestamps! end + ## + # The main event-processing class. You are encouraged to + # inherit from this class when building your own bot, but + # delegation is also entirely feasible. class Bot include Evented attr_reader :opts, :twitter, :xmpp + ## # Records an error and emits a corresponding :request_error event. + # @param req The Request for which the error was encountered. + # @param e The caught Exception. def request_error(req, e) Log.error "Error processing #{req.source.class} '#{req.text}': #{e}\n#{e.backtrace.join("\n\t")}" req.errors[Time.now] = e req.save emit(:request_error, req, e) end + ## # Processes an individual request (synchronously). + # @param req An unprocessed Request. def process_request(req) begin emit(:request, req) rescue Exception => e request_error(req, e) @@ -58,11 +69,13 @@ req.processed = true req.save end end + ## # Performs appropriate dispatch operation for response type. + # @param resp An undispatched Response. def dispatch(resp) begin source = resp.request.source if Safubot::mode != :production Log.info "#{source.class} Response to #{source.username}: #{resp.text}" @@ -96,10 +109,11 @@ Request.where(:processed => false).each do |req| concurrently(req) { process_request(req) } end end + ## # Adds a response to the queue. # @param req Request to respond to. # @param text Contents of the response. def respond(req, text) Log.info("#{req.user.name}: #{req.text}\nsafubot: #{text}") @@ -115,38 +129,43 @@ # Dispatches all undispatched Responses. def push Response.where(:dispatched => false).each(&method(:dispatch)) end - # Wraps EM::defer with error handling and response pushing for the given request. + ## + # Wraps Thread.new with error handling and response pushing for the given request. # @param req The Request being processed. # @param blk The operation to be performed in a separate thread. def concurrently(req, &blk) - EM::defer do + Thread.new do begin blk.call rescue Exception => e request_error(req, e) end push end end + # Runs an initial request-processing loop and then forks the streaming processes. + def run_nowait + pull; process; push + @twitter.run if @twitter + @xmpp.run if @xmpp + end + + # Calls run_nowait and then waits for all child processes. def run - #EventMachine::run do - pull; process; push - @twitter.run if @twitter - @xmpp.run if @xmpp - begin - Process.waitall - rescue Interrupt - stop - end - #end + run_nowait + begin + Process.waitall + rescue Interrupt + stop + end end - # Shuts down the event loop. + # Shuts down the streaming processes. def stop @twitter.stop if @twitter @xmpp.stop if @xmpp end