Browse Source

Fix a memory leak with the chat aspect. (#23)

Essentially, the for loop wasn't being returned out
of and that caused the read listener to never be
let up and released to the gc
pull/24/head
Bradley Hilton 5 years ago committed by GitHub
parent
commit
fe96739f60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      core/chat/client.go
  2. 45
      core/chat/server.go
  3. 2
      router/router.go
  4. 4
      webroot/js/app.js

8
core/chat/client.go

@ -3,6 +3,7 @@ package chat @@ -3,6 +3,7 @@ package chat
import (
"fmt"
"io"
"time"
log "github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
@ -15,6 +16,9 @@ const channelBufSize = 100 @@ -15,6 +16,9 @@ const channelBufSize = 100
//Client represents a chat client.
type Client struct {
ConnectedAt time.Time
MessageCount int
id string
ws *websocket.Conn
server *Server
@ -39,7 +43,7 @@ func NewClient(ws *websocket.Conn, server *Server) *Client { @@ -39,7 +43,7 @@ func NewClient(ws *websocket.Conn, server *Server) *Client {
pingch := make(chan models.PingMessage)
clientID := utils.GenerateClientIDFromRequest(ws.Request())
return &Client{clientID, ws, server, ch, pingch, doneCh}
return &Client{time.Now(), 0, clientID, ws, server, ch, pingch, doneCh}
}
//GetConnection gets the connection for the client
@ -106,9 +110,11 @@ func (c *Client) listenRead() { @@ -106,9 +110,11 @@ func (c *Client) listenRead() {
if err := websocket.JSON.Receive(c.ws, &msg); err == io.EOF {
c.doneCh <- true
return
} else if err != nil {
c.server.Err(err)
} else {
c.MessageCount++
c.server.SendToAll(msg)
}
}

45
core/chat/server.go

@ -5,19 +5,19 @@ import ( @@ -5,19 +5,19 @@ import (
"net/http"
"time"
"github.com/gabek/owncast/core"
"github.com/gabek/owncast/models"
log "github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
"github.com/gabek/owncast/core"
"github.com/gabek/owncast/models"
)
//Server represents the server which handles the chat
type Server struct {
Pattern string
Messages []models.ChatMessage
Clients map[string]*Client
pattern string
addCh chan *Client
delCh chan *Client
sendAllCh chan models.ChatMessage
@ -27,7 +27,7 @@ type Server struct { @@ -27,7 +27,7 @@ type Server struct {
}
//NewServer creates a new chat server
func NewServer(pattern string) *Server {
func NewServer() *Server {
messages := []models.ChatMessage{}
clients := make(map[string]*Client)
addCh := make(chan *Client)
@ -46,9 +46,9 @@ func NewServer(pattern string) *Server { @@ -46,9 +46,9 @@ func NewServer(pattern string) *Server {
messages = append(messages, models.ChatMessage{"Blathers", "Blathers is an owl with brown feathers. His face is white and he has a yellow beak. His arms are wing shaped and he has yellow talons. His eyes are very big with small black irises. He also has big pink cheek circles on his cheeks. His belly appears to be checkered in diamonds with light brown and white squares, similar to an argyle vest, which is traditionally associated with academia. His green bowtie further alludes to his academic nature.", "https://vignette.wikia.nocookie.net/animalcrossing/images/b/b3/NH-character-Blathers.png/revision/latest?cb=20200229053519", "demo-message-6", "ChatMessage"})
server := &Server{
pattern,
messages,
clients,
"/entry", //hardcoded due to the UI requiring this and it is not configurable
addCh,
delCh,
sendAllCh,
@ -116,26 +116,27 @@ func (s *Server) ping() { @@ -116,26 +116,27 @@ func (s *Server) ping() {
}
}
func (s *Server) onConnection(ws *websocket.Conn) {
client := NewClient(ws, s)
defer func() {
log.Printf("The client was connected for %s and sent %d messages (%s)", time.Since(client.ConnectedAt), client.MessageCount, client.id)
if err := ws.Close(); err != nil {
s.errCh <- err
}
}()
s.Add(client)
client.Listen()
}
// Listen and serve.
// It serves client connection and broadcast request.
func (s *Server) Listen() {
// websocket handler
onConnected := func(ws *websocket.Conn) {
defer func() {
err := ws.Close()
if err != nil {
s.errCh <- err
}
}()
client := NewClient(ws, s)
s.Add(client)
client.Listen()
}
http.Handle(s.Pattern, websocket.Handler(onConnected))
http.Handle(s.pattern, websocket.Handler(s.onConnection))
log.Printf("Starting the websocket listener on: %s", s.Pattern)
log.Printf("Starting the websocket listener on: %s", s.pattern)
for {
select {

2
router/router.go

@ -15,7 +15,7 @@ import ( @@ -15,7 +15,7 @@ import (
//Start starts the router for the http, ws, and rtmp
func Start() error {
// websocket server
chatServer := chat.NewServer("/entry")
chatServer := chat.NewServer()
go chatServer.Listen()
// start the rtmp server

4
webroot/js/app.js

@ -66,9 +66,9 @@ function setupWebsocket() { @@ -66,9 +66,9 @@ function setupWebsocket() {
// Uncomment to point to somewhere other than goth.land
const protocol = location.protocol == "https:" ? "wss" : "ws"
// var ws = new WebSocket(protocol + "://" + location.host + "/entry")
var ws = new WebSocket(protocol + "://" + location.host + "/entry")
var ws = new WebSocket("wss://goth.land/entry")
// var ws = new WebSocket("wss://goth.land/entry")
ws.onmessage = (e) => {
const model = JSON.parse(e.data)

Loading…
Cancel
Save