Skip to content

Commit

Permalink
Merge pull request #39 from alberts-s/implement-server-pings
Browse files Browse the repository at this point in the history
Add support for server heartbeats
  • Loading branch information
d-Rickyy-b authored Jul 14, 2024
2 parents 122fc7b + f5ecce4 commit 2b5971c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### Added
- Support for non-browsers by implementing server initiated heartbeats (#39)
### Changed
### Fixed
### Docs
Expand Down
59 changes: 40 additions & 19 deletions internal/web/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,45 @@ func newClient(conn *websocket.Conn, subType SubscriptionType, name string, cert

// Each client has a broadcastHandler that runs in the background and sends out the broadcast messages to the client.
func (c *client) broadcastHandler() {
writeWait := 60 * time.Second
pingTicker := time.NewTicker(30 * time.Second)

defer func() {
log.Println("Closing broadcast handler for client:", c.conn.RemoteAddr())

pingTicker.Stop()

_ = c.conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
_ = c.conn.WriteMessage(websocket.CloseMessage, []byte{})
_ = c.conn.Close()
}()

for message := range c.broadcastChan {
_ = c.conn.SetWriteDeadline(time.Now().Add(60 * time.Second))
for {
select {
case <-pingTicker.C:
_ = c.conn.SetWriteDeadline(time.Now().Add(writeWait))

w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
log.Printf("Error while getting next writer: %v\n", err)
return
}
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
return
}
case message := <-c.broadcastChan:
_ = c.conn.SetWriteDeadline(time.Now().Add(writeWait))

_, writeErr := w.Write(message)
if writeErr != nil {
log.Printf("Error while writing: %v\n", writeErr)
}
w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
log.Printf("Error while getting next writer: %v\n", err)
return
}

_, writeErr := w.Write(message)
if writeErr != nil {
log.Printf("Error while writing: %v\n", writeErr)
}

if closeErr := w.Close(); closeErr != nil {
log.Printf("Error while closing: %v\n", closeErr)
return
if closeErr := w.Close(); closeErr != nil {
log.Printf("Error while closing: %v\n", closeErr)
return
}
}
}
}
Expand All @@ -73,18 +88,24 @@ func (c *client) listenWebsocket() {
ClientHandler.unregisterClient(c)
}()

readWait := 65 * time.Second

c.conn.SetReadLimit(512)
_ = c.conn.SetReadDeadline(time.Now().Add(65 * time.Second))
_ = c.conn.SetReadDeadline(time.Now().Add(readWait))

defaultPingHandler := c.conn.PingHandler()
c.conn.SetPingHandler(func(appData string) error {
// Ping received - reset the ping deadline to 65 seconds
_ = c.conn.SetReadDeadline(time.Now().Add(65 * time.Second))
// Ping received - reset the deadline
err := c.conn.SetReadDeadline(time.Now().Add(readWait))
if err != nil {
return err
}
return defaultPingHandler(appData)
})
c.conn.SetPongHandler(func(string) error {
// Pong received
return nil
// Pong received - reset the deadline
err := c.conn.SetReadDeadline(time.Now().Add(readWait))
return err
})

// Handle messages from the client
Expand Down

0 comments on commit 2b5971c

Please sign in to comment.