Connected clients admin API (#217)

* Add support for ending the inbound stream. Closes #191

* Add a simple success response to API requests

* Connected clients API with geo details

* Post-rebase cleanup

* Make setting and reading geo details separate operations to unblock and speed up

* Rename file

* Fire geoip api call behind goroutine

* Add comment

* Post-rebase fixes

* Add support for the MaxMind GeoLite2 GeoIP database
This commit is contained in:
Gabe Kangas
2020-10-06 23:14:33 -07:00
committed by GitHub
parent 1eb7c1985b
commit d7e355bce1
21 changed files with 1926 additions and 37 deletions

View File

@@ -70,3 +70,12 @@ func GetMessages() []models.ChatMessage {
return getChatHistory()
}
func GetClient(clientID string) *Client {
for _, client := range _server.Clients {
if client.ClientID == clientID {
return client
}
}
return nil
}

View File

@@ -9,6 +9,7 @@ import (
log "github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
"github.com/owncast/owncast/geoip"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/utils"
@@ -21,8 +22,12 @@ const channelBufSize = 100
type Client struct {
ConnectedAt time.Time
MessageCount int
UserAgent string
IPAddress string
Username *string
ClientID string // How we identify unique viewers when counting viewer counts.
Geo *geoip.GeoDetails `json:"geo"`
clientID string // How we identify unique viewers when counting viewer counts.
socketID string // How we identify a single websocket client.
ws *websocket.Conn
ch chan models.ChatMessage
@@ -50,10 +55,12 @@ func NewClient(ws *websocket.Conn) *Client {
pingch := make(chan models.PingMessage)
usernameChangeChannel := make(chan models.NameChangeEvent)
ipAddress := utils.GetIPAddressFromRequest(ws.Request())
userAgent := ws.Request().UserAgent()
clientID := utils.GenerateClientIDFromRequest(ws.Request())
socketID, _ := shortid.Generate()
return &Client{time.Now(), 0, clientID, socketID, ws, ch, pingch, usernameChangeChannel, doneCh}
return &Client{time.Now(), 0, userAgent, ipAddress, nil, clientID, nil, socketID, ws, ch, pingch, usernameChangeChannel, doneCh}
}
//GetConnection gets the connection for the client
@@ -66,7 +73,7 @@ func (c *Client) Write(msg models.ChatMessage) {
case c.ch <- msg:
default:
_server.remove(c)
_server.err(fmt.Errorf("client %s is disconnected", c.clientID))
_server.err(fmt.Errorf("client %s is disconnected", c.ClientID))
}
}
@@ -153,6 +160,7 @@ func (c *Client) userChangedName(data []byte) {
msg.Type = NAMECHANGE
msg.ID = shortid.MustGenerate()
_server.usernameChanged(msg)
c.Username = &msg.NewName
}
func (c *Client) chatMessageReceived(data []byte) {
@@ -168,7 +176,21 @@ func (c *Client) chatMessageReceived(data []byte) {
msg.Visible = true
c.MessageCount++
c.Username = &msg.Author
msg.ClientID = c.clientID
msg.ClientID = c.ClientID
_server.SendToAll(msg)
}
// GetViewerClientFromChatClient returns a general models.Client from a chat websocket client.
func (c *Client) GetViewerClientFromChatClient() models.Client {
return models.Client{
ConnectedAt: c.ConnectedAt,
MessageCount: c.MessageCount,
UserAgent: c.UserAgent,
IPAddress: c.IPAddress,
Username: c.Username,
ClientID: c.ClientID,
Geo: geoip.GetGeoFromIP(c.IPAddress),
}
}

View File

@@ -79,7 +79,7 @@ func (s *server) onConnection(ws *websocket.Conn) {
client := NewClient(ws)
defer func() {
log.Tracef("The client was connected for %s and sent %d messages (%s)", time.Since(client.ConnectedAt), client.MessageCount, client.clientID)
log.Tracef("The client was connected for %s and sent %d messages (%s)", time.Since(client.ConnectedAt), client.MessageCount, client.ClientID)
if err := ws.Close(); err != nil {
s.errCh <- err
@@ -102,13 +102,13 @@ func (s *server) Listen() {
// add new a client
case c := <-s.addCh:
s.Clients[c.socketID] = c
s.listener.ClientAdded(c.clientID)
s.listener.ClientAdded(c.GetViewerClientFromChatClient())
s.sendWelcomeMessageToClient(c)
// remove a client
case c := <-s.delCh:
delete(s.Clients, c.socketID)
s.listener.ClientRemoved(c.clientID)
s.listener.ClientRemoved(c.ClientID)
// broadcast a message to all clients
case msg := <-s.sendAllCh:
@@ -138,3 +138,13 @@ func (s *server) sendWelcomeMessageToClient(c *Client) {
}()
}
func (s *server) getClientForClientID(clientID string) *Client {
for _, client := range s.Clients {
if client.ClientID == clientID {
return client
}
}
return nil
}