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