synchronous sockets, no more threads

This commit is contained in:
Yessiest 2024-07-08 03:50:56 +04:00
parent 20c312d9a9
commit 6566c2af5c
2 changed files with 70 additions and 69 deletions

View File

@ -5,9 +5,6 @@ require 'landline/extensions/websocket'
class Test < Landline::App class Test < Landline::App
websocket "/test", version: 7 do |socket| websocket "/test", version: 7 do |socket|
socket.on :message do |msg|
puts "Client wrote: #{msg}"
end
socket.on :error do |err| socket.on :error do |err|
puts "Error occured: #{err.inspect}" puts "Error occured: #{err.inspect}"
puts err.backtrace puts err.backtrace
@ -15,12 +12,17 @@ class Test < Landline::App
socket.on :close do socket.on :close do
puts "Client closed read connection" puts "Client closed read connection"
end end
socket.ready
socket.write("Hi!") socket.write("Hi!")
response = socket.read while (response = socket.read)
if response
puts "Client wrote: #{response.inspect}"
else
puts "Client closed read connection"
end
socket.write("You said: #{response}") socket.write("You said: #{response}")
end
socket.write("Goodbye!") socket.write("Goodbye!")
socket.close socket.close_write
rescue Exception => e rescue Exception => e
puts e.inspect puts e.inspect
puts e.backtrace puts e.backtrace

View File

@ -95,19 +95,6 @@ module Landline
) )
@readable = true @readable = true
@writable = true @writable = true
@data = Queue.new
on :message do |msg|
@data.enq(msg)
end
end
# Start the main loop for the eventifier
# @return [void]
def ready
return if @ready
_loop
@ready = true
end end
# Send data through websocket # Send data through websocket
@ -126,34 +113,30 @@ module Landline
) )
@io.write(frame.to_s) @io.write(frame.to_s)
rescue Errno::EPIPE => e rescue Errno::EPIPE => e
@writable = false
_emit :error, e _emit :error, e
close close
end end
# Read data from socket synchronously # Read data from socket synchronously
# @return [String, nil] nil returned if socket closes # @return [WebSocket::Frame::Base, nil] nil if socket received a close event
def read def read
unless @readable unless @readable
raise self.class::WebSocketError, raise self.class::WebSocketError,
"socket closed for reading" "socket closed for reading"
end end
@data.deq _process_events(proc { _read })
end end
# Close the socket for reading # Read data from socket without blocking
# @return [void] # @return [WebSocket::Frame::Base, nil] nil if socket received a close event
def close_read def read_nonblock
_emit :close unless @readable
@readable = false raise self.class::WebSocketError,
@io.close_read "socket closed for reading"
end end
# Close the socket for writing _process_events(proc { _read_nonblock })
def close_write
@writable = false
@io.close_write
end end
# Establish a connection through handshake # Establish a connection through handshake
@ -183,62 +166,78 @@ module Landline
handshake handshake
end end
# Close the socket # Close socket for reading
# @return [void] def close_read
def close raise WebSocketError, 'socket closed for reading' unless @readable
_close
@writable = false _emit :close
@readable = false @readable = false
@io.close_read
end end
# Close socket for reading
def close_write
raise WebSocketError, 'socket closed for writing' unless @writable
write(nil, type: :close)
@writable = false
@io.close_write
end
# Close the socket entirely
def close
raise WebSocketError, 'socket closed' unless @writable or @readable
close_read if @readable
close_write if @writable
end
attr_reader :io, :readable, :writable
private private
# Event reading loop # Process incoming websocket events
# @return [void] # @param next_frame [#call] callback to get the next frame
def _loop # @return [WebSocket::Frame::Base, nil]
@thread = Thread.new do def _process_events(next_frame)
loop do loop do
msg = _read frame = next_frame.call
if msg and [:text, :binary].include? msg.type case frame.type
_emit :message, msg when :binary, :text, :pong then return frame
elsif msg and msg.type == :close when :ping
_emit :__close, msg write frame.to_s, type: :pong
break when :close
end
end
rescue IOError => e
@writable = false
_emit :error, e
close
ensure
close_read close_read
return nil
else raise WebSocketError, "unknown frame type #{frame.type}"
end
end end
end end
# Receive data through websocket # Receive data through websocket
# @return [String] output from frame # @return [String] output from frame
def _read def _read
while (char = @io.getc) while (char = @io.read(1))
@frame_parser << char @frame_parser << char
frame = @frame_parser.next frame = @frame_parser.next
return frame if frame return frame if frame
end end
rescue Errno::ECONNRESET => e rescue Errno::ECONNRESET => e
@writable = false
_emit :error, e _emit :error, e
close close
end end
# Close the websocket # Receive data through websocket asynchronously
# @return [void] # @return [String] output from frame
def _close def _read_nonblock
frame = ::WebSocket::Frame::Outgoing::Server.new( while (char = @io.read_nonblock(1))
version: @version, @frame_parser << char
type: :close frame = @frame_parser.next
) return frame if frame
@io.write(frame.to_s) if @writable end
sleep 0.1 rescue Errno::ECONNRESET => e
@io.close _emit :error, e
close
end end
end end
end end