This class manages the connection to the IRC server. That includes processing incoming and outgoing messages, creating Ruby objects and invoking plugins.
@api private @return [Boolean] True if the connection could be established
# File lib/cinch/irc.rb, line 45 def connect tcp_socket = nil begin Timeout::timeout(@bot.config.timeouts.connect) do tcp_socket = TCPSocket.new(@bot.config.server, @bot.config.port, @bot.config.local_host) end rescue Timeout::Error @bot.loggers.warn("Timed out while connecting") return false rescue SocketError => e @bot.loggers.warn("Could not connect to the IRC server. Please check your network: #{e.message}") return false rescue => e @bot.loggers.exception(e) return false end if @bot.config.ssl.use setup_ssl(tcp_socket) else @socket = tcp_socket end @socket = Net::BufferedIO.new(@socket) @socket.read_timeout = @bot.config.timeouts.read @queue = MessageQueue.new(@socket, @bot) return true end
@api private @return [void]
# File lib/cinch/irc.rb, line 221 def parse(input) return if input.chomp.empty? @bot.loggers.incoming(input) msg = Message.new(input, @bot) events = [[:catchall]] if ("001".."004").include? msg.command @registration << msg.command if registered? events << [:connect] @bot.last_connection_was_successful = true on_connect(msg, events) end end if ["PRIVMSG", "NOTICE"].include?(msg.command) events << [:ctcp] if msg.ctcp? if msg.channel? events << [:channel] else events << [:private] end if msg.command == "PRIVMSG" events << [:message] end if msg.action? events << [:action] end end meth = "on_#{msg.command.downcase}" __send__(meth, msg, events) if respond_to?(meth, true) if msg.error? events << [:error] end events << [msg.command.downcase.to_sym] msg.events = events.map(&:first) events.each do |event, *args| @bot.handlers.dispatch(event, msg, *args) end end
@return [Boolean] true if we successfully registered yet
# File lib/cinch/irc.rb, line 270 def registered? (("001".."004").to_a - @registration).empty? end
Send a message to the server. @param [String] msg @return [void]
# File lib/cinch/irc.rb, line 277 def send(msg) @queue.queue(msg) end
@since 2.0.0 @api private @return [void]
# File lib/cinch/irc.rb, line 121 def send_cap_end send "CAP END" end
@api private @return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 107 def send_cap_ls send "CAP LS" end
@api private @return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 114 def send_cap_req send "CAP REQ :" + ([:"away-notify", :"multi-prefix", :sasl] & @network.capabilities).join(" ") end
@api private @return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 128 def send_login send "PASS #{@bot.config.password}" if @bot.config.password send "NICK #{@bot.generate_next_nick!}" send "USER #{@bot.config.user} 0 * :#{@bot.config.realname}" end
@since 2.0.0
# File lib/cinch/irc.rb, line 189 def send_sasl if @bot.config.sasl.username && @sasl_current_method = @sasl_remaining_methods.pop @bot.loggers.info "[SASL] Trying to authenticate with #{@sasl_current_method.mechanism_name}" send "AUTHENTICATE #{@sasl_current_method.mechanism_name}" else send_cap_end end end
@api private @return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 36 def setup @registration = [] @network = Network.new(:unknown, :unknown) @whois_updates = Hash.new {|h, k| h[k] = {}} @in_lists = Set.new end
@api private @return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 79 def setup_ssl(socket) # require openssl in this method so the bot doesn't break for # people who don't have SSL but don't want to use SSL anyway. require 'openssl' ssl_context = OpenSSL::SSL::SSLContext.new if @bot.config.ssl.is_a?(Configuration::SSL) if @bot.config.ssl.client_cert ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(@bot.config.ssl.client_cert)) ssl_context.key = OpenSSL::PKey::RSA.new(File.read(@bot.config.ssl.client_cert)) end ssl_context.ca_path = @bot.config.ssl.ca_path ssl_context.verify_mode = @bot.config.ssl.verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE else ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE end @bot.loggers.info "Using SSL with #{@bot.config.server}:#{@bot.config.port}" @socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context) @socket.sync = true @socket.connect end
@return [TCPSocket] @api private @since 2.0.0
# File lib/cinch/irc.rb, line 29 def socket @socket.io end
Establish a connection.
@return [void] @since 2.0.0
# File lib/cinch/irc.rb, line 202 def start setup if connect @sasl_remaining_methods = [SASL::Plain, SASL::DH_Blowfish] send_cap_ls send_login reading_thread = start_reading_thread sending_thread = start_sending_thread ping_thread = start_ping_thread reading_thread.join sending_thread.kill ping_thread.kill end end
@api private @return [Thread] The ping thread. @since 2.0.0
# File lib/cinch/irc.rb, line 177 def start_ping_thread Thread.new do while true sleep @bot.config.ping_interval # PING requires a single argument. In our case the value # doesn't matter though. send("PING 0") end end end
@api private @return [Thread] the reading thread @since 2.0.0
# File lib/cinch/irc.rb, line 137 def start_reading_thread Thread.new do begin while line = @socket.readline rescue_exception do line = Cinch::Utilities::Encoding.encode_incoming(line, @bot.config.encoding) parse line end end rescue Timeout::Error @bot.loggers.warn "Connection timed out." rescue EOFError @bot.loggers.warn "Lost connection." rescue => e @bot.loggers.exception(e) end @socket.close @bot.handlers.dispatch(:disconnect) # FIXME won't we kill all :disconnect handlers here? prolly # not, as they have 10 seconds to finish. that should be # plenty of time @bot.handlers.stop_all end end
Generated with the Darkfish Rdoc Generator 2.