Closed daniel-abramov closed 4 years ago
I think it sounds good, just at the moment don't want to completely change how the API's are now as this is quite Apple like style.
Maybe you can build on top of Starscream such approach?
Perhaps. There are also Futures/Promises in Swift (they have been introduced not that far ago as far as I know), probably they would help to implement such an approach.
Thanks for the suggestion. I think 4.0.0 resolves a lot of this with its state management happening through enum events. It still behaves like an Apple API versus a rust one. Certainly something we will keep in mind as we make changes moving forward. Thanks again!
I've just thought on how the API could be improved to provide more robust invariants and avoid "wrong" state by having different data types for different websocket states.
To be more precise I've encountered some issues (and workarounded them on the client code)
delegate
is set after the object is created, but theoretically it's possible to miss some events / notifications on adelegate
if the event happens before thedelegate
is set. While it is rather a rare scenario, there is a way to avoid it (this can certainly be alleviated by the fact that we have aconnect()
function inWebSocket
, but this is a runtime "check", we can do it on compile time instead).WebSocket
is initialised, a user can access all its methods, includingwrite()
. The problem is: you can't send data unless theWebSocket
is connected, i.e. the handshake must be finished before we even try to callwrite()
. There is no backpressure or queue of messages whichWebSocket
maintains to store the "scheduled" messages, which means that it'll silently drop a message in such case. We can design the API in a way that forbids callingwrite()
on aWebSocket
which is not yet connected.I made some thoughts on how to implement this API and I had in mind something similar to
tungstenite-rs
/tokio-tungstenite
(Rust WebSockets). We can't quite get the same API due to the fact that ADT in Swift are a bit different and there is no async/futures concept in Swift (there are promises in Swift, but I'm not sure if they would help), but we can try to avoid impossible state by applying the following principles:connect(request: URLRequest, connected: (Result<WebSocket, Error>) -> ())
. By doing this we ensure that theWebSocket
represents a valid and complete WebSocket connection.write()
and similar functions may check the state and return an error immediately if we know that we can't write to the socket right now (like if the connection has already been closed), alternatively we can letwrite(competion: (Result<(), Error>) -> ()
accept a closure which is called when thewrite()
completes the execution, which means that this function is always called, resolving to either "Successfully Sent" or "Was Not Sent Due To XXX".This probably can be applied to the rest of the API as well. What do you think?