Class: Landline::WebSocket::WSockWrapper

Inherits:
Object
  • Object
show all
Includes:
Eventifier
Defined in:
lib/landline/extensions/websocket.rb

Overview

Socket-like object representing websocket interface

Defined Under Namespace

Classes: WebSocketError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Eventifier

#off, #on

Constructor Details

#initialize(io, version: 7) ⇒ WSockWrapper

Returns a new instance of WSockWrapper.



68
69
70
71
72
73
74
75
76
# File 'lib/landline/extensions/websocket.rb', line 68

def initialize(io, version: 7)
  @io = io
  @version = version
  @frame_parser = ::WebSocket::Frame::Incoming::Server.new(
    version: version
  )
  @readable = true
  @writable = true
end

Instance Attribute Details

#ioObject (readonly)

Returns the value of attribute io.



181
182
183
# File 'lib/landline/extensions/websocket.rb', line 181

def io
  @io
end

#readableObject (readonly)

Returns the value of attribute readable.



181
182
183
# File 'lib/landline/extensions/websocket.rb', line 181

def readable
  @readable
end

#writableObject (readonly)

Returns the value of attribute writable.



181
182
183
# File 'lib/landline/extensions/websocket.rb', line 181

def writable
  @writable
end

Class Method Details

.create_handshake(request, **opts) ⇒ Object

Initiate a handshake



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/landline/extensions/websocket.rb', line 136

def self.create_handshake(request, **opts)
  handshake = ::WebSocket::Handshake::Server.new(**opts)
  handshake.from_hash({
                        headers: request.headers,
                        path: request.path_info,
                        query: request.query.query,
                        body: request.body
                      })
  return nil unless handshake.finished? and handshake.valid?

  handshake
end

.handshake(request, version: 7, **opts) ⇒ self

Establish a connection through handshake

Returns:

  • (self)

Raises:

  • (StandardError)


124
125
126
127
128
129
130
131
132
133
# File 'lib/landline/extensions/websocket.rb', line 124

def self.handshake(request, version: 7, **opts)
  raise StandardError, "stream cannot be hijacked" unless request.hijack

  handshake = create_handshake(request, version: version, **opts)
  return nil unless handshake

  io = request.hijack.call
  io.sendmsg(handshake.to_s)
  new(io, version: version)
end

Instance Method Details

#closeObject

Close the socket entirely

Raises:



168
169
170
171
172
173
# File 'lib/landline/extensions/websocket.rb', line 168

def close
  raise WebSocketError, 'socket closed' unless @writable or @readable

  close_read if @readable
  close_write if @writable
end

#close_readObject

Close socket for reading

Raises:



150
151
152
153
154
155
156
# File 'lib/landline/extensions/websocket.rb', line 150

def close_read
  raise WebSocketError, 'socket closed for reading' unless @readable

  _emit :close
  @readable = false
  @io.close_read
end

#close_writeObject

Close socket for reading

Raises:



159
160
161
162
163
164
165
# File 'lib/landline/extensions/websocket.rb', line 159

def close_write
  raise WebSocketError, 'socket closed for writing' unless @writable

  write(nil, type: :close)
  @writable = false
  @io.close_write
end

#readWebSocket::Frame::Base?

Read data from socket synchronously

Returns:

  • (WebSocket::Frame::Base, nil)

    nil if socket received a close event



102
103
104
105
106
107
108
109
# File 'lib/landline/extensions/websocket.rb', line 102

def read
  unless @readable
    raise self.class::WebSocketError,
          "socket closed for reading"
  end

  _process_events(proc { _read })
end

#read_nonblockWebSocket::Frame::Base?

Read data from socket without blocking

Returns:

  • (WebSocket::Frame::Base, nil)

    nil if socket received a close event



113
114
115
116
117
118
119
120
# File 'lib/landline/extensions/websocket.rb', line 113

def read_nonblock
  unless @readable
    raise self.class::WebSocketError,
          "socket closed for reading"
  end

  _process_events(proc { _read_nonblock })
end

#to_ioIO

Obtain internal IO object

Returns:

  • (IO)


177
178
179
# File 'lib/landline/extensions/websocket.rb', line 177

def to_io
  io
end

#write(data, type: :text) ⇒ void

This method returns an undefined value.

Send data through websocket

Parameters:

  • data (String)

    binary data



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/landline/extensions/websocket.rb', line 81

def write(data, type: :text)
  unless @writable
    raise self.class::WebSocketError,
          "socket closed for writing"
  end

  frame = ::WebSocket::Frame::Outgoing::Server.new(
    version: @version,
    data: data,
    type: type
  )
  @io.write(frame.to_s)
rescue Errno::EPIPE => e
  @writable = false
  _emit :error, e
  close if @readable
  nil
end