Hi! I'm attempting to build a (very simple) proof-of-concept Vapor server that delivers a GET API along with a websocket API. My goal is for clients to connect to a websocket and receive notifications when something interesting happens on the server.
My goal (for now) with a GET endpoint is just an echo… I will just have a simple hello world
GET endpoint that broadcasts that message out to the "current" websockets.
Something I'm not completely clear on is what options should I consider for sharing some kind of state between a GET route and a websocket rote. My vapor server needs some way to "message back" from the GET route to the websockets that are active.
Here is an attempt at this:
import Vapor
final actor Registrar {
private var array = Array<WebSocket>()
func append(_ ws: WebSocket) {
self.array.append(ws)
}
func send<S>(_ text: S) async throws where S: Sendable, S: Collection, S.Element == Character {
for ws in self.array {
try await ws.send(text)
}
}
}
func main() async throws {
let app = try await Application.make(.detect())
let registrar = Registrar()
app.get("hello", "vapor") { req in
try await registrar.send("Hello, vapor!")
return "Hello, vapor!"
}
app.webSocket("echo") { req, ws in
await registrar.append(ws)
ws.onClose.whenComplete { result in
// TODO: REMOVE FROM REGISTRAR
}
}
try await app.execute()
try await app.asyncShutdown()
}
try await main()
This code seems to be doing the right thing (so far)… other than the TODO that I should remove the socket from the stack after the client closes the connection.
Is there any other pattern here the community likes for this problem? I can keep hacking on this approach… but I'm also open to any other ideas or patterns that might be out there for something similar. This does not have to be production scale for my use-case… but I'm open to migrating to a production scale solution if the code is also quick and easy. Thanks!