I have been trying to create a non-blocking server using Crystal and Kemal which will (a) listen for a stream of UDP messages being sent to it, and (b) then forwarding that message to a WebSocket to any browsers who have started a ws connection.
So far, the best I can manage is:
require "kemal"
require "socket"
server = UDPSocket.new
server.bind "localhost", 1234
puts "Started..."
ws "/" do |socket|
udp_working = true
while udp_working
message, client_addr = server.receive
socket.send message
end
socket.on_close do
puts "Goodbye..."
udp_working = false
end
end
This all seems a little inelegant, and indeed, doesn't work as expected because:
- All UDP packets sent in between the Crystal server being started and the first web browser connecting to the Crystal server is cached and sent in one huge backlog
- Browsers disconnecting from WebSockets are not handled properly, i.e. socket.on_close is not being triggered, and the loop continues until I terminate the Crystal server
I was hoping for a server.on_message type handling which would enable me to run code only when UDP packets were received, rather than continual polling which blocks the server. Is there another way to achieve this using Crystal/Kemal?
Thanks!