add fields to stats.
This commit is contained in:
parent
6d7486ab57
commit
f59128cf72
@ -7,6 +7,7 @@
|
|||||||
- Ability to set locks from config `NEKO_LOCKS=control login`.
|
- Ability to set locks from config `NEKO_LOCKS=control login`.
|
||||||
- Added control protection - users can gain control only if at least one admin is in the room `NEKO_CONTROL_PROTECTION=true`.
|
- Added control protection - users can gain control only if at least one admin is in the room `NEKO_CONTROL_PROTECTION=true`.
|
||||||
- Emotes sending on mouse down holding.
|
- Emotes sending on mouse down holding.
|
||||||
|
- Include `banned`, `locked`, `server_started_at`, `last_admin_left_at`, `last_user_left_at`, `control_protection` data in stats.
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
- ARM-based images not bound to Raspberry Pi only.
|
- ARM-based images not bound to Raspberry Pi only.
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
Connections uint32 `json:"connections"`
|
Connections uint32 `json:"connections"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Members []*Member `json:"members"`
|
Members []*Member `json:"members"`
|
||||||
|
|
||||||
|
Banned map[string]string `json:"banned"` // IP -> session ID (that banned it)
|
||||||
|
Locked map[string]string `json:"locked"` // resource name -> session ID (that locked it)
|
||||||
|
|
||||||
|
ServerStartedAt time.Time `json:"server_started_at"`
|
||||||
|
LastAdminLeftAt *time.Time `json:"last_admin_left_at"`
|
||||||
|
LastUserLeftAt *time.Time `json:"last_user_left_at"`
|
||||||
|
|
||||||
|
ControlProtection bool `json:"control_protection"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebSocket interface {
|
type WebSocket interface {
|
||||||
|
@ -292,8 +292,7 @@ func (h *MessageHandler) adminBan(id string, session types.Session, payload *mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
h.logger.Debug().Str("address", remote).Msg("adding address to banned")
|
h.logger.Debug().Str("address", remote).Msg("adding address to banned")
|
||||||
|
h.banned[address[0]] = id
|
||||||
h.banned[address[0]] = true
|
|
||||||
|
|
||||||
if err := target.Kick("banned"); err != nil {
|
if err := target.Kick("banned"); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -18,8 +18,8 @@ type MessageHandler struct {
|
|||||||
webrtc types.WebRTCManager
|
webrtc types.WebRTCManager
|
||||||
remote types.RemoteManager
|
remote types.RemoteManager
|
||||||
broadcast types.BroadcastManager
|
broadcast types.BroadcastManager
|
||||||
banned map[string]bool
|
banned map[string]string // IP -> session ID (that banned it)
|
||||||
locked map[string]string
|
locked map[string]string // resource name -> session ID (that locked it)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) Connected(admin bool, socket *WebSocket) (bool, string) {
|
func (h *MessageHandler) Connected(admin bool, socket *WebSocket) (bool, string) {
|
||||||
@ -27,8 +27,8 @@ func (h *MessageHandler) Connected(admin bool, socket *WebSocket) (bool, string)
|
|||||||
if address == "" {
|
if address == "" {
|
||||||
h.logger.Debug().Msg("no remote address")
|
h.logger.Debug().Msg("no remote address")
|
||||||
} else {
|
} else {
|
||||||
ok, banned := h.banned[address]
|
_, ok := h.banned[address]
|
||||||
if ok && banned {
|
if ok {
|
||||||
h.logger.Debug().Str("address", address).Msg("banned")
|
h.logger.Debug().Str("address", address).Msg("banned")
|
||||||
return false, "banned"
|
return false, "banned"
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,20 @@ import (
|
|||||||
"m1k1o/neko/internal/utils"
|
"m1k1o/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CONTROL_PROTECTION_SESSION = "control_protection"
|
const CONTROL_PROTECTION_SESSION = "by_control_protection"
|
||||||
|
|
||||||
func New(sessions types.SessionManager, remote types.RemoteManager, broadcast types.BroadcastManager, webrtc types.WebRTCManager, conf *config.WebSocket) *WebSocketHandler {
|
func New(sessions types.SessionManager, remote types.RemoteManager, broadcast types.BroadcastManager, webrtc types.WebRTCManager, conf *config.WebSocket) *WebSocketHandler {
|
||||||
logger := log.With().Str("module", "websocket").Logger()
|
logger := log.With().Str("module", "websocket").Logger()
|
||||||
|
|
||||||
locks := make(map[string]string)
|
locks := make(map[string]string)
|
||||||
|
|
||||||
|
// if control protection is enabled
|
||||||
|
if conf.ControlProtection {
|
||||||
|
locks["control"] = CONTROL_PROTECTION_SESSION
|
||||||
|
logger.Info().Msgf("control locked on behalf of control protection")
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply default locks
|
||||||
for _, lock := range conf.Locks {
|
for _, lock := range conf.Locks {
|
||||||
locks[lock] = "" // empty session ID
|
locks[lock] = "" // empty session ID
|
||||||
}
|
}
|
||||||
@ -32,12 +40,6 @@ func New(sessions types.SessionManager, remote types.RemoteManager, broadcast ty
|
|||||||
logger.Info().Msgf("locked resources: %+v", conf.Locks)
|
logger.Info().Msgf("locked resources: %+v", conf.Locks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if control protection is enabled
|
|
||||||
if conf.ControlProtection {
|
|
||||||
locks["control"] = CONTROL_PROTECTION_SESSION
|
|
||||||
logger.Info().Msgf("control locked on behalf of control protection")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &WebSocketHandler{
|
return &WebSocketHandler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
shutdown: make(chan interface{}),
|
shutdown: make(chan interface{}),
|
||||||
@ -55,10 +57,10 @@ func New(sessions types.SessionManager, remote types.RemoteManager, broadcast ty
|
|||||||
broadcast: broadcast,
|
broadcast: broadcast,
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
webrtc: webrtc,
|
webrtc: webrtc,
|
||||||
banned: make(map[string]bool),
|
banned: make(map[string]string),
|
||||||
locked: locks,
|
locked: locks,
|
||||||
},
|
},
|
||||||
conns: 0,
|
serverStartedAt: time.Now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +76,12 @@ type WebSocketHandler struct {
|
|||||||
remote types.RemoteManager
|
remote types.RemoteManager
|
||||||
conf *config.WebSocket
|
conf *config.WebSocket
|
||||||
handler *MessageHandler
|
handler *MessageHandler
|
||||||
conns uint32
|
|
||||||
|
// stats
|
||||||
|
conns uint32
|
||||||
|
serverStartedAt time.Time
|
||||||
|
lastAdminLeftAt *time.Time
|
||||||
|
lastUserLeftAt *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebSocketHandler) Start() {
|
func (ws *WebSocketHandler) Start() {
|
||||||
@ -109,6 +116,13 @@ func (ws *WebSocketHandler) Start() {
|
|||||||
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_UNLOCK)
|
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_UNLOCK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove outdated stats
|
||||||
|
if session.Admin() {
|
||||||
|
ws.lastAdminLeftAt = nil
|
||||||
|
} else {
|
||||||
|
ws.lastUserLeftAt = nil
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ws.sessions.OnDestroy(func(id string, session types.Session) {
|
ws.sessions.OnDestroy(func(id string, session types.Session) {
|
||||||
@ -118,8 +132,13 @@ func (ws *WebSocketHandler) Start() {
|
|||||||
ws.logger.Debug().Str("id", id).Msg("session destroyed")
|
ws.logger.Debug().Str("id", id).Msg("session destroyed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
membersCount := len(ws.sessions.Members())
|
||||||
|
adminCount := len(ws.sessions.Admins())
|
||||||
|
|
||||||
// if control protection is enabled and no admin
|
// if control protection is enabled and no admin
|
||||||
if ws.conf.ControlProtection && len(ws.sessions.Admins()) == 0 {
|
// and room is not locked, lock
|
||||||
|
_, ok := ws.handler.locked["control"]
|
||||||
|
if !ok && ws.conf.ControlProtection && adminCount == 0 {
|
||||||
ws.handler.locked["control"] = CONTROL_PROTECTION_SESSION
|
ws.handler.locked["control"] = CONTROL_PROTECTION_SESSION
|
||||||
ws.logger.Info().Msgf("control locked and released on behalf of control protection")
|
ws.logger.Info().Msgf("control locked and released on behalf of control protection")
|
||||||
ws.handler.adminRelease(id, session)
|
ws.handler.adminRelease(id, session)
|
||||||
@ -133,6 +152,18 @@ func (ws *WebSocketHandler) Start() {
|
|||||||
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_LOCK)
|
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_LOCK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this was the last admin
|
||||||
|
if session.Admin() && adminCount == 0 {
|
||||||
|
now := time.Now()
|
||||||
|
ws.lastAdminLeftAt = &now
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this was the last user
|
||||||
|
if !session.Admin() && membersCount-adminCount == 0 {
|
||||||
|
now := time.Now()
|
||||||
|
ws.lastUserLeftAt = &now
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ws.wg.Add(1)
|
ws.wg.Add(1)
|
||||||
@ -274,6 +305,15 @@ func (ws *WebSocketHandler) Stats() types.Stats {
|
|||||||
Connections: atomic.LoadUint32(&ws.conns),
|
Connections: atomic.LoadUint32(&ws.conns),
|
||||||
Host: host,
|
Host: host,
|
||||||
Members: ws.sessions.Members(),
|
Members: ws.sessions.Members(),
|
||||||
|
|
||||||
|
Banned: ws.handler.banned,
|
||||||
|
Locked: ws.handler.locked,
|
||||||
|
|
||||||
|
ServerStartedAt: ws.serverStartedAt,
|
||||||
|
LastAdminLeftAt: ws.lastAdminLeftAt,
|
||||||
|
LastUserLeftAt: ws.lastUserLeftAt,
|
||||||
|
|
||||||
|
ControlProtection: ws.conf.ControlProtection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user