opal/browser/socket.rb
# backtick_javascript: true
module Browser
# A {Socket} allows the browser and a server to have a bidirectional data
# connection.
#
# @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
class Socket < IO
def self.supported?
Browser.supports? :WebSocket
end
include Native::Wrapper
include IO::Writable if defined? IO::Writable
include Event::Target
target {|value|
Socket.new(value) if Native.is_a?(value, `window.WebSocket`)
}
# Create a connection to the given URL, optionally using the given protocol.
#
# @param url [String] the URL to connect to
# @param protocol [String] the protocol to use
#
# @yield if the block has no parameters it's `instance_exec`d, otherwise it's
# called with `self`
def initialize(url, protocol = nil, &block)
if native?(url)
super(url)
elsif protocol
super(`new window.WebSocket(#{url.to_s}, #{protocol.to_n})`)
else
super(`new window.WebSocket(#{url.to_s})`)
end
if block.arity == 0
instance_exec(&block)
else
block.call(self)
end if block
end
# @!attribute [r] protocol
# @return [String] the protocol of the socket
alias_native :protocol
# @!attribute [r] url
# @return [String] the URL the socket is connected to
alias_native :url
# @!attribute [r] buffered
# @return [Integer] the amount of buffered data.
alias_native :buffered, :bufferedAmount
# @!attribute [r] type
# @return [:blob, :buffer, :string] the type of the socket
def type
%x{
switch (#@native.binaryType) {
case "blob":
return "blob";
case "arraybuffer":
return "buffer";
default:
return "string";
}
}
end
# @!attribute [r] state
# @return [:connecting, :open, :closing, :closed] the state of the socket
def state
%x{
switch (#@native.readyState) {
case window.WebSocket.CONNECTING:
return "connecting";
case window.WebSocket.OPEN:
return "open";
case window.WebSocket.CLOSING:
return "closing";
case window.WebSocket.CLOSED:
return "closed";
}
}
end
# @!attribute [r] extensions
# @return [Array<String>] the extensions used by the socket
def extensions
`#@native.extensions`.split(/\s*,\s*/)
end
# Check if the socket is alive.
def alive?
state == :open
end
# Send data to the socket.
#
# @param data [#to_n] the data to send
def write(data)
`#@native.send(#{data.to_n})`
end
alias << write
alias send write
# Close the socket.
#
# @param code [Integer, nil] the error code
# @param reason [String, nil] the reason for closing
def close(code = nil, reason = nil)
`#@native.close(#{code.to_n}, #{reason.to_n})`
end
end
end