Browse files

Tweak code layout of connection a bit.

There are too many concerns!
  • Loading branch information...
1 parent 8df4620 commit d547e3fcbe8d87a199b437a7a96f14f60dee4281 @ConradIrwin ConradIrwin committed Jul 2, 2011
Showing with 60 additions and 53 deletions.
  1. +60 −53 lib/em-imap/connection.rb
View
113 lib/em-imap/connection.rb
@@ -25,6 +25,38 @@ def self.connect(host, port, ssl=false)
end
end
+ def post_init
+ @listeners = []
+ super
+ listen_for_failure
+ listen_for_greeting
+ end
+
+ # This listens for the IMAP connection to have been set up. This should
+ # be shortly after the TCP connection is available, once we've received
+ # a greeting from the server.
+ def listen_for_greeting
+ add_to_listener_pool(hello_listener)
+ hello_listener.listen do |response|
+ # TODO: Is this the right condition? I think it can be one of several
+ # possible answers depending on how trusted the connection is, but probably
+ # not *anything* except BYE.
+ if response.is_a?(Net::IMAP::UntaggedResponse) && response.name != "BYE"
+ hello_listener.succeed response
+ else
+ hello_listener.fail Net::IMAP::ResponseParseError.new(response.raw_data)
+ end
+ end.errback do |e|
+ hello_listener.fail e
+ end
+ end
+
+ # Returns a Listener that is active during connection setup, and which is succeeded
+ # or failed as soon as we've received a greeting from the server.
+ def hello_listener
+ @hello_listener ||= Listener.new.errback{ |e| fail e }.bothback{ hello_listener.stop }
+ end
+
# Send the command, with the given arguments, to the IMAP server.
#
# @param cmd, the name of the command to send (a string)
@@ -69,33 +101,34 @@ def add_response_handler(&block)
end
end
- def post_init
- @listeners = []
- super
- listen_for_failure
- listen_for_greeting
+ def add_to_listener_pool(listener)
+ @listeners << listener.bothback{ @listeners.delete listener }
end
- # Listen for the first response from the server and succeed or fail
- # the connection deferrable.
- def listen_for_greeting
- add_to_listener_pool(hello_listener)
- hello_listener.listen do |response|
- # TODO: Is this the right condition? I think it can be one of several
- # possible answers depending on how trusted the connection is, but probably
- # not *anything* except BYE.
- if response.is_a?(Net::IMAP::UntaggedResponse) && response.name != "BYE"
- hello_listener.succeed response
- else
- hello_listener.fail Net::IMAP::ResponseParseError.new(response.raw_data)
- end
- end.errback do |e|
- hello_listener.fail e
- end
+ # receive_response is a higher-level receive_data provided by
+ # EM::IMAP::ResponseParser. Each response is a Net::IMAP response
+ # object. (FIXME)
+ def receive_response(response)
+ # NOTE: Take a shallow clone of the listeners so that if receiving an
+ # event causes a new listener to be added, it won't receive this response!
+ @listeners.clone.each{ |listener| listener.receive_event response }
end
- def hello_listener
- @hello_listener ||= Listener.new.errback{ |e| fail e }.bothback{ hello_listener.stop }
+ # Await the response that marks the completion of this command,
+ # and succeed or fail the command as appropriate.
+ def listen_for_tagged_response(command)
+ command.listen do |response|
+ if response.is_a?(Net::IMAP::TaggedResponse) && response.tag == command.tag
+ case response.name
+ when "NO"
+ command.fail Net::IMAP::NoResponseError.new(response.data.text)
+ when "BAD"
+ command.fail Net::IMAP::BadResponseError.new(response.data.text)
+ else
+ command.succeed response
+ end
+ end
+ end
end
# Called when the connection is closed.
@@ -105,6 +138,10 @@ def unbind
fail EOFError.new("Connection to IMAP server was unbound")
end
+ # Attach life-long listeners on various conditions that we want to treat as connection
+ # errors. When such an error occurs, we want to fail all the currently pending commands
+ # so that the user of the library doesn't have to subscribe to more than one stream
+ # of errors.
def listen_for_failure
errback do |error|
# NOTE: Take a shallow clone of the listeners here so that we get guaranteed
@@ -123,36 +160,6 @@ def listen_for_failure
end
end
- def add_to_listener_pool(listener)
- @listeners << listener.bothback{ @listeners.delete listener }
- end
-
- # receive_response is a higher-level receive_data provided by
- # EM::IMAP::ResponseParser. Each response is a Net::IMAP response
- # object. (FIXME)
- def receive_response(response)
- # NOTE: Take a shallow clone of the listeners so that if receiving an
- # event causes a new listener to be added, it won't receive this response!
- @listeners.clone.each{ |listener| listener.receive_event response }
- end
-
- # Await the response that marks the completion of this command,
- # and succeed or fail the command as appropriate.
- def listen_for_tagged_response(command)
- command.listen do |response|
- if response.is_a?(Net::IMAP::TaggedResponse) && response.tag == command.tag
- case response.name
- when "NO"
- command.fail Net::IMAP::NoResponseError.new(response.data.text)
- when "BAD"
- command.fail Net::IMAP::BadResponseError.new(response.data.text)
- else
- command.succeed response
- end
- end
- end
- end
-
# Provides a next_tag! method to generate unique tags
# for an IMAP session.
module TagSequence

0 comments on commit d547e3f

Please sign in to comment.