celluloid / celluloid-io

UNMAINTAINED: See celluloid/celluloid#779 - Evented sockets for Celluloid actors
https://celluloid.io
MIT License
879 stars 93 forks source link

server-side closing of an SSLSocket doesn't cause an event #176

Open dblock opened 8 years ago

dblock commented 8 years ago

I think this is a bug (or a non-feature). Trying to fix https://github.com/dblock/slack-ruby-client/issues/90. In the following code if the connection is forcibly closed server-side, I see the EOF, but no :close or :closed event.

require 'celluloid/current'
require 'celluloid/io'
require 'http'
require 'websocket/driver'

class Connection
  include Celluloid::IO
  extend Forwardable

  def initialize(url)
    @url = url
    uri = URI.parse(url)
    port = uri.port || (uri.scheme == "ws" ? 80 : 443)
    @socket = Celluloid::IO::TCPSocket.new(uri.host, port)
    @socket = SSLSocket.new(@socket, OpenSSL::SSL::SSLContext.new(:TLSv1_2_client))
    @socket.connect
    @client = ::WebSocket::Driver.client(self)
    async.run
  end
  attr_reader :url

  def run
    @client.on('open') do |event|
      puts "OPEN: #{event}"
    end
    @client.on('message') do |event|
      puts "MESSAGE: #{event}"
    end
    @client.on('close') do |event|
      puts "CLOSE: #{event}"
    end

    @client.start

    loop do
      begin
        @client.parse(@socket.readpartial(1024))
      rescue EOFError
        puts "EOF"
        break
      end
    end
  end

  def_delegators :@client, :text, :binary, :ping, :close, :protocol

  def write(buffer)
    @socket.write buffer
  end
end

fail 'missing token' unless ENV['SLACK_API_TOKEN']

url = JSON.parse(HTTP.get("https://slack.com/api/rtm.start?token=#{ENV['SLACK_API_TOKEN']}"))['url']
puts "connecting to #{URI.parse(url).host} ..."

conn = Connection.new(url)

loop do
  Thread.pass
end

puts "done."
connecting to mpmulti-wu48.slack-msgs.com ...
OPEN: #<struct WebSocket::Driver::OpenEvent>
MESSAGE: #<struct WebSocket::Driver::MessageEvent data="{\"type\":\"hello\"}">
MESSAGE: #<struct WebSocket::Driver::MessageEvent data="{}">
EOF
dblock commented 8 years ago

Looks like it's not implemented. For example, faye-websocket listens for the client TCP/TLS socket being closed:

https://github.com/faye/faye-websocket-ruby/blob/c6403578831822433a3cee7113d2c40677ae23fb/lib/faye/websocket/client.rb#L75

and emits its own event:

https://github.com/faye/faye-websocket-ruby/blob/c6403578831822433a3cee7113d2c40677ae23fb/lib/faye/websocket/api.rb#L129