mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Refactor websocket session sync (#44)
* refactor websocket peer and comment functions. * update comments. * add DestroyWebSocketPeer.
This commit is contained in:
parent
43f8fe339f
commit
0ea1c2870f
@ -142,7 +142,7 @@ func (manager *SessionManagerCtx) Delete(id string) error {
|
|||||||
manager.sessionsMu.Unlock()
|
manager.sessionsMu.Unlock()
|
||||||
|
|
||||||
if session.State().IsConnected {
|
if session.State().IsConnected {
|
||||||
session.GetWebSocketPeer().Destroy("session deleted")
|
session.DestroyWebSocketPeer("session deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.State().IsWatching {
|
if session.State().IsWatching {
|
||||||
|
@ -51,7 +51,7 @@ func (session *SessionCtx) profileChanged() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!session.profile.CanConnect || !session.profile.CanLogin) && session.state.IsConnected {
|
if (!session.profile.CanConnect || !session.profile.CanLogin) && session.state.IsConnected {
|
||||||
session.GetWebSocketPeer().Destroy("profile changed")
|
session.DestroyWebSocketPeer("profile changed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// update webrtc paused state
|
// update webrtc paused state
|
||||||
@ -82,30 +82,49 @@ func (session *SessionCtx) SetCursor(cursor types.Cursor) {
|
|||||||
// websocket
|
// websocket
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
func (session *SessionCtx) SetWebSocketPeer(websocketPeer types.WebSocketPeer) {
|
//
|
||||||
|
// Connect WebSocket peer sets current peer and emits connected event. It also destroys the
|
||||||
|
// previous peer, if there was one. If the peer is already set, it will be ignored.
|
||||||
|
//
|
||||||
|
func (session *SessionCtx) ConnectWebSocketPeer(websocketPeer types.WebSocketPeer) {
|
||||||
session.websocketMu.Lock()
|
session.websocketMu.Lock()
|
||||||
|
isCurrentPeer := websocketPeer == session.websocketPeer
|
||||||
session.websocketPeer, websocketPeer = websocketPeer, session.websocketPeer
|
session.websocketPeer, websocketPeer = websocketPeer, session.websocketPeer
|
||||||
session.websocketMu.Unlock()
|
session.websocketMu.Unlock()
|
||||||
|
|
||||||
if websocketPeer != nil && websocketPeer != session.websocketPeer {
|
// ignore if already set
|
||||||
|
if isCurrentPeer {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session.logger.Info().Msg("set websocket connected")
|
||||||
|
session.state.IsConnected = true
|
||||||
|
session.manager.emmiter.Emit("connected", session)
|
||||||
|
|
||||||
|
// if there is a previous peer, destroy it
|
||||||
|
if websocketPeer != nil {
|
||||||
websocketPeer.Destroy("connection replaced")
|
websocketPeer.Destroy("connection replaced")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *SessionCtx) SetWebSocketConnected(websocketPeer types.WebSocketPeer, connected bool, delayed bool) {
|
//
|
||||||
|
// Disconnect WebSocket peer sets current peer to nil and emits disconnected event. It also
|
||||||
|
// allows for a delayed disconnect. That means, the peer will not be disconnected immediately,
|
||||||
|
// but after a delay. If the peer is connected again before the delay, the disconnect will be
|
||||||
|
// cancelled.
|
||||||
|
//
|
||||||
|
// If the peer is not the current peer or the peer is nil, it will be ignored.
|
||||||
|
//
|
||||||
|
func (session *SessionCtx) DisconnectWebSocketPeer(websocketPeer types.WebSocketPeer, delayed bool) {
|
||||||
session.websocketMu.Lock()
|
session.websocketMu.Lock()
|
||||||
isCurrentPeer := websocketPeer == session.websocketPeer
|
isCurrentPeer := websocketPeer == session.websocketPeer && websocketPeer != nil
|
||||||
session.websocketMu.Unlock()
|
session.websocketMu.Unlock()
|
||||||
|
|
||||||
|
// ignore if not current peer
|
||||||
if !isCurrentPeer {
|
if !isCurrentPeer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
session.logger.Info().
|
|
||||||
Bool("connected", connected).
|
|
||||||
Bool("delayed", delayed).
|
|
||||||
Msg("set websocket connected")
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// ws delayed
|
// ws delayed
|
||||||
//
|
//
|
||||||
@ -114,7 +133,7 @@ func (session *SessionCtx) SetWebSocketConnected(websocketPeer types.WebSocketPe
|
|||||||
|
|
||||||
if delayed {
|
if delayed {
|
||||||
wsDelayedTimer = time.AfterFunc(WS_DELAYED_DURATION, func() {
|
wsDelayedTimer = time.AfterFunc(WS_DELAYED_DURATION, func() {
|
||||||
session.SetWebSocketConnected(websocketPeer, connected, false)
|
session.DisconnectWebSocketPeer(websocketPeer, false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +145,7 @@ func (session *SessionCtx) SetWebSocketConnected(websocketPeer types.WebSocketPe
|
|||||||
session.wsDelayedMu.Unlock()
|
session.wsDelayedMu.Unlock()
|
||||||
|
|
||||||
if delayed {
|
if delayed {
|
||||||
|
session.logger.Info().Msg("delayed websocket disconnected")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,13 +153,8 @@ func (session *SessionCtx) SetWebSocketConnected(websocketPeer types.WebSocketPe
|
|||||||
// not delayed
|
// not delayed
|
||||||
//
|
//
|
||||||
|
|
||||||
session.state.IsConnected = connected
|
session.logger.Info().Msg("set websocket disconnected")
|
||||||
|
session.state.IsConnected = false
|
||||||
if connected {
|
|
||||||
session.manager.emmiter.Emit("connected", session)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
session.manager.emmiter.Emit("disconnected", session)
|
session.manager.emmiter.Emit("disconnected", session)
|
||||||
|
|
||||||
session.websocketMu.Lock()
|
session.websocketMu.Lock()
|
||||||
@ -149,15 +164,34 @@ func (session *SessionCtx) SetWebSocketConnected(websocketPeer types.WebSocketPe
|
|||||||
session.websocketMu.Unlock()
|
session.websocketMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *SessionCtx) GetWebSocketPeer() types.WebSocketPeer {
|
//
|
||||||
|
// Destroy WebSocket peer disconnects the peer and destroys it. It ensures that the peer is
|
||||||
|
// disconnected immediately even though normal flow would be to disconnect it delayed.
|
||||||
|
//
|
||||||
|
func (session *SessionCtx) DestroyWebSocketPeer(reason string) {
|
||||||
session.websocketMu.Lock()
|
session.websocketMu.Lock()
|
||||||
defer session.websocketMu.Unlock()
|
peer := session.websocketPeer
|
||||||
|
session.websocketMu.Unlock()
|
||||||
|
|
||||||
return session.websocketPeer
|
if peer == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disconnect peer first, so that it is not used anymore
|
||||||
|
session.DisconnectWebSocketPeer(peer, false)
|
||||||
|
|
||||||
|
// destroy it afterwards
|
||||||
|
peer.Destroy(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send event to websocket peer.
|
||||||
|
//
|
||||||
func (session *SessionCtx) Send(event string, payload any) {
|
func (session *SessionCtx) Send(event string, payload any) {
|
||||||
peer := session.GetWebSocketPeer()
|
session.websocketMu.Lock()
|
||||||
|
peer := session.websocketPeer
|
||||||
|
session.websocketMu.Unlock()
|
||||||
|
|
||||||
if peer != nil {
|
if peer != nil {
|
||||||
peer.Send(event, payload)
|
peer.Send(event, payload)
|
||||||
}
|
}
|
||||||
@ -167,6 +201,9 @@ func (session *SessionCtx) Send(event string, payload any) {
|
|||||||
// webrtc
|
// webrtc
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set webrtc peer and destroy the old one, if there is old one.
|
||||||
|
//
|
||||||
func (session *SessionCtx) SetWebRTCPeer(webrtcPeer types.WebRTCPeer) {
|
func (session *SessionCtx) SetWebRTCPeer(webrtcPeer types.WebRTCPeer) {
|
||||||
session.webrtcMu.Lock()
|
session.webrtcMu.Lock()
|
||||||
session.webrtcPeer, webrtcPeer = webrtcPeer, session.webrtcPeer
|
session.webrtcPeer, webrtcPeer = webrtcPeer, session.webrtcPeer
|
||||||
@ -177,6 +214,14 @@ func (session *SessionCtx) SetWebRTCPeer(webrtcPeer types.WebRTCPeer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set if current webrtc peer is connected or not. Since there might be lefover calls from
|
||||||
|
// webrtc peer, that are not used anymore, we need to check if the webrtc peer is still the
|
||||||
|
// same as the one we are setting the connected state for.
|
||||||
|
//
|
||||||
|
// If webrtc peer is disconnected, we don't expect it to be reconnected, so we set it to nil
|
||||||
|
// and send a signal close to the client. New connection is expected to use a new webrtc peer.
|
||||||
|
//
|
||||||
func (session *SessionCtx) SetWebRTCConnected(webrtcPeer types.WebRTCPeer, connected bool) {
|
func (session *SessionCtx) SetWebRTCConnected(webrtcPeer types.WebRTCPeer, connected bool) {
|
||||||
session.webrtcMu.Lock()
|
session.webrtcMu.Lock()
|
||||||
isCurrentPeer := webrtcPeer == session.webrtcPeer
|
isCurrentPeer := webrtcPeer == session.webrtcPeer
|
||||||
@ -209,6 +254,9 @@ func (session *SessionCtx) SetWebRTCConnected(webrtcPeer types.WebRTCPeer, conne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get current WebRTC peer. Nil if not connected.
|
||||||
|
//
|
||||||
func (session *SessionCtx) GetWebRTCPeer() types.WebRTCPeer {
|
func (session *SessionCtx) GetWebRTCPeer() types.WebRTCPeer {
|
||||||
session.webrtcMu.Lock()
|
session.webrtcMu.Lock()
|
||||||
defer session.webrtcMu.Unlock()
|
defer session.webrtcMu.Unlock()
|
||||||
|
@ -207,19 +207,18 @@ func (manager *WebSocketManagerCtx) Upgrade(checkOrigin types.CheckOrigin) types
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (manager *WebSocketManagerCtx) connect(connection *websocket.Conn, r *http.Request) {
|
func (manager *WebSocketManagerCtx) connect(connection *websocket.Conn, r *http.Request) {
|
||||||
// create new peer
|
|
||||||
peer := newPeer(connection)
|
|
||||||
|
|
||||||
session, err := manager.sessions.Authenticate(r)
|
session, err := manager.sessions.Authenticate(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
manager.logger.Warn().Err(err).Msg("authentication failed")
|
manager.logger.Warn().Err(err).Msg("authentication failed")
|
||||||
peer.Destroy(err.Error())
|
newPeer(manager.logger, connection).Destroy(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// add session id to all log messages
|
// add session id to all log messages
|
||||||
logger := manager.logger.With().Str("session_id", session.ID()).Logger()
|
logger := manager.logger.With().Str("session_id", session.ID()).Logger()
|
||||||
peer.setSessionID(session.ID())
|
|
||||||
|
// create new peer
|
||||||
|
peer := newPeer(logger, connection)
|
||||||
|
|
||||||
if !session.Profile().CanConnect {
|
if !session.Profile().CanConnect {
|
||||||
logger.Warn().Msg("connection disabled")
|
logger.Warn().Msg("connection disabled")
|
||||||
@ -238,14 +237,12 @@ func (manager *WebSocketManagerCtx) connect(connection *websocket.Conn, r *http.
|
|||||||
logger.Info().Msg("replacing peer connection")
|
logger.Info().Msg("replacing peer connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.SetWebSocketPeer(peer)
|
|
||||||
|
|
||||||
logger.Info().
|
logger.Info().
|
||||||
Str("address", connection.RemoteAddr().String()).
|
Str("address", connection.RemoteAddr().String()).
|
||||||
Str("agent", r.UserAgent()).
|
Str("agent", r.UserAgent()).
|
||||||
Msg("connection started")
|
Msg("connection started")
|
||||||
|
|
||||||
session.SetWebSocketConnected(peer, true, false)
|
session.ConnectWebSocketPeer(peer)
|
||||||
|
|
||||||
// this is a blocking function that lives
|
// this is a blocking function that lives
|
||||||
// throughout whole websocket connection
|
// throughout whole websocket connection
|
||||||
@ -277,7 +274,7 @@ func (manager *WebSocketManagerCtx) connect(connection *websocket.Conn, r *http.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
session.SetWebSocketConnected(peer, false, delayedDisconnect)
|
session.DisconnectWebSocketPeer(peer, delayedDisconnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *WebSocketManagerCtx) handle(connection *websocket.Conn, peer types.WebSocketPeer, session types.Session) error {
|
func (manager *WebSocketManagerCtx) handle(connection *websocket.Conn, peer types.WebSocketPeer, session types.Session) error {
|
||||||
|
@ -2,12 +2,10 @@ package websocket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"github.com/demodesk/neko/pkg/types"
|
"github.com/demodesk/neko/pkg/types"
|
||||||
"github.com/demodesk/neko/pkg/types/event"
|
"github.com/demodesk/neko/pkg/types/event"
|
||||||
@ -21,30 +19,17 @@ type WebSocketPeerCtx struct {
|
|||||||
connection *websocket.Conn
|
connection *websocket.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPeer(connection *websocket.Conn) *WebSocketPeerCtx {
|
func newPeer(logger zerolog.Logger, connection *websocket.Conn) *WebSocketPeerCtx {
|
||||||
logger := log.With().
|
|
||||||
Str("module", "websocket").
|
|
||||||
Str("submodule", "peer").
|
|
||||||
Logger()
|
|
||||||
|
|
||||||
return &WebSocketPeerCtx{
|
return &WebSocketPeerCtx{
|
||||||
logger: logger,
|
logger: logger.With().Str("submodule", "peer").Logger(),
|
||||||
connection: connection,
|
connection: connection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (peer *WebSocketPeerCtx) setSessionID(sessionId string) {
|
|
||||||
peer.logger = peer.logger.With().Str("session_id", sessionId).Logger()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (peer *WebSocketPeerCtx) Send(event string, payload any) {
|
func (peer *WebSocketPeerCtx) Send(event string, payload any) {
|
||||||
peer.mu.Lock()
|
peer.mu.Lock()
|
||||||
defer peer.mu.Unlock()
|
defer peer.mu.Unlock()
|
||||||
|
|
||||||
if peer.connection == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
raw, err := json.Marshal(payload)
|
raw, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
peer.logger.Err(err).Str("event", event).Msg("message marshalling has failed")
|
peer.logger.Err(err).Str("event", event).Msg("message marshalling has failed")
|
||||||
@ -79,10 +64,6 @@ func (peer *WebSocketPeerCtx) Ping() error {
|
|||||||
peer.mu.Lock()
|
peer.mu.Lock()
|
||||||
defer peer.mu.Unlock()
|
defer peer.mu.Unlock()
|
||||||
|
|
||||||
if peer.connection == nil {
|
|
||||||
return errors.New("peer connection not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// application level heartbeat
|
// application level heartbeat
|
||||||
if err := peer.connection.WriteJSON(types.WebSocketMessage{
|
if err := peer.connection.WriteJSON(types.WebSocketMessage{
|
||||||
Event: event.SYSTEM_HEARTBEAT,
|
Event: event.SYSTEM_HEARTBEAT,
|
||||||
@ -103,9 +84,6 @@ func (peer *WebSocketPeerCtx) Destroy(reason string) {
|
|||||||
peer.mu.Lock()
|
peer.mu.Lock()
|
||||||
defer peer.mu.Unlock()
|
defer peer.mu.Unlock()
|
||||||
|
|
||||||
if peer.connection != nil {
|
|
||||||
err := peer.connection.Close()
|
err := peer.connection.Close()
|
||||||
peer.logger.Err(err).Msg("peer connection destroyed")
|
peer.logger.Err(err).Msg("peer connection destroyed")
|
||||||
peer.connection = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,9 @@ type Session interface {
|
|||||||
SetCursor(cursor Cursor)
|
SetCursor(cursor Cursor)
|
||||||
|
|
||||||
// websocket
|
// websocket
|
||||||
SetWebSocketPeer(websocketPeer WebSocketPeer)
|
ConnectWebSocketPeer(websocketPeer WebSocketPeer)
|
||||||
SetWebSocketConnected(websocketPeer WebSocketPeer, connected bool, delayed bool)
|
DisconnectWebSocketPeer(websocketPeer WebSocketPeer, delayed bool)
|
||||||
GetWebSocketPeer() WebSocketPeer
|
DestroyWebSocketPeer(reason string)
|
||||||
Send(event string, payload any)
|
Send(event string, payload any)
|
||||||
|
|
||||||
// webrtc
|
// webrtc
|
||||||
|
Loading…
Reference in New Issue
Block a user