Tweaks to the writer, including documentation.

main
Mari 3 years ago
parent 6608c10e79
commit 41f882190f
  1. 31
      server/websocket/writer.go

@ -10,22 +10,34 @@ import (
)
type writer struct {
conn *websocket.Conn
channel chan ServerMessage
// conn is the websocket connection that this writer is responsible for writing on.
conn *websocket.Conn
// channel is the channel used to receive server messages to be sent to the client.
// When it receives a SocketClosed, the process on the sending end promises not to send any further messages, as the writer will close it right after.
channel chan ServerMessage
// readNotifications is the channel used to receive pings when the reader receives a message, so that a ping will be sent out before the reader is ready to time out.
// When it is closed, the reader has shut down.
readNotifications <-chan time.Duration
timer *time.Ticker
logger *zap.Logger
// timer is the timer used to send pings when the reader is close to timing out, to make sure the other end of the connection is still listening.
timer *time.Timer
// logger is the logger used to record the state of the writer, primarily in Debug level.
logger *zap.Logger
}
// act is the function responsible for actually doing the writing.
func (w *writer) act() {
defer w.gracefulShutdown()
w.logger.Debug("Starting up")
w.timer = time.NewTicker(PingDelay)
w.timer = time.NewTimer(PingDelay)
for {
select {
case _, open := <-w.readNotifications:
if open {
w.logger.Debug("Received reader read, extending ping")
if !w.timer.Stop() {
// The timer went off while we were doing this, so drain the channel before resetting
<-w.timer.C
}
w.timer.Reset(PingDelay)
} else {
w.logger.Debug("Received reader close, shutting down")
@ -46,6 +58,7 @@ func (w *writer) act() {
}
case <-w.timer.C:
w.sendPing()
w.timer.Reset(PingDelay)
}
w.logger.Debug("Awakening handled, resuming listening")
}
@ -83,6 +96,8 @@ func (w *writer) send(msg ServerMessage) {
}
}
// sendClose sends a close message on the websocket connection, but does not actually close the connection.
// It does, however, close the incoming message channel.
func (w *writer) sendClose(msg SocketClosed) {
w.logger.Debug("Shutting down the writer channel")
close(w.channel)
@ -94,6 +109,7 @@ func (w *writer) sendClose(msg SocketClosed) {
}
}
// sendPing sends a ping message on the websocket connection. The content is arbitrary.
func (w *writer) sendPing() {
w.logger.Debug("Sending ping")
err := w.conn.WriteControl(websocket.PingMessage, []byte("are you still there?"), time.Now().Add(ControlTimeLimit))
@ -104,12 +120,12 @@ func (w *writer) sendPing() {
// gracefulShutdown causes the writer to wait for the close handshake to finish and then shut down.
// It waits for the reader's readNotifications to close, indicating that it has also shut down, and for the channel to
// receive a SocketClosed message indicating that the client has shut down.
// receive a SocketClosed message indicating that the main process has shut down.
// During this time, the writer ignores all other messages from the channel and sends no pings.
func (w *writer) gracefulShutdown() {
defer w.finalShutdown()
w.timer = nil
w.logger.Debug("Waiting for all channels to shut down")
w.timer.Stop()
for {
if w.channel == nil && w.readNotifications == nil {
w.logger.Debug("All channels closed, beginning final shutdown")
@ -134,6 +150,7 @@ func (w *writer) gracefulShutdown() {
}
}
// finalShutdown closes the socket and finishes cleanup.
func (w *writer) finalShutdown() {
w.logger.Debug("Closing WebSocket connection")
err := w.conn.Close()

Loading…
Cancel
Save