node build fixed

This commit is contained in:
ra_ma
2025-09-20 14:08:38 +01:00
parent c6ebbe069d
commit 3d298fa434
1516 changed files with 535727 additions and 2 deletions

View File

@@ -0,0 +1,238 @@
package nakama
import (
"net/http"
"seanime/internal/constants"
"seanime/internal/events"
"seanime/internal/util"
"time"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // Allow connections from any origin
},
}
// startHostServices initializes the host services
func (m *Manager) startHostServices() {
if m.settings == nil || !m.settings.IsHost || !m.settings.Enabled {
return
}
m.logger.Info().Msg("nakama: Starting host services")
// Clean up any existing watch party session
m.watchPartyManager.Cleanup()
// Start ping routine for connected peers
go m.hostPingRoutine()
// Start stale connection cleanup routine
go m.staleConnectionCleanupRoutine()
// Send event to client about host mode being enabled
m.wsEventManager.SendEvent(events.NakamaHostStarted, map[string]interface{}{
"enabled": true,
})
}
// stopHostServices stops the host services
func (m *Manager) stopHostServices() {
m.logger.Info().Msg("nakama: Stopping host services")
// Disconnect all peers
m.peerConnections.Range(func(id string, conn *PeerConnection) bool {
conn.Close()
return true
})
m.peerConnections.Clear()
// Send event to client about host mode being disabled
m.wsEventManager.SendEvent(events.NakamaHostStopped, map[string]interface{}{
"enabled": false,
})
}
// HandlePeerConnection handles incoming WebSocket connections from peers
func (m *Manager) HandlePeerConnection(w http.ResponseWriter, r *http.Request) {
if m.settings == nil || !m.settings.IsHost || !m.settings.Enabled {
http.Error(w, "Host mode not enabled", http.StatusForbidden)
return
}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
m.logger.Error().Err(err).Msg("nakama: Failed to upgrade WebSocket connection")
return
}
username := r.Header.Get("X-Seanime-Nakama-Username")
// Generate a random username if username is not set (this shouldn't be the case because the peer will generate its own username)
if username == "" {
username = "Peer_" + util.RandomStringWithAlphabet(8, "bcdefhijklmnopqrstuvwxyz0123456789")
}
peerID := r.Header.Get("X-Seanime-Nakama-Peer-Id")
if peerID == "" {
m.logger.Error().Msg("nakama: Peer connection missing PeerID header")
http.Error(w, "Missing PeerID header", http.StatusBadRequest)
return
}
serverVersion := r.Header.Get("X-Seanime-Nakama-Server-Version")
if serverVersion != constants.Version {
http.Error(w, "Server version mismatch", http.StatusBadRequest)
return
}
// Check for existing connection with the same PeerID (reconnection scenario)
var existingConnID string
m.peerConnections.Range(func(id string, existingConn *PeerConnection) bool {
if existingConn.PeerId == peerID {
existingConnID = id
return false // Stop iteration
}
return true
})
// Remove existing connection for this PeerID to handle reconnection
if existingConnID != "" {
if oldConn, exists := m.peerConnections.Get(existingConnID); exists {
m.logger.Info().Str("peerID", peerID).Str("oldConnID", existingConnID).Msg("nakama: Removing old connection for reconnecting peer")
m.peerConnections.Delete(existingConnID)
oldConn.Close()
}
}
// Generate new internal connection ID
internalConnID := generateConnectionID()
peerConn := &PeerConnection{
ID: internalConnID,
PeerId: peerID,
Username: username,
Conn: conn,
ConnectionType: ConnectionTypePeer,
Authenticated: false,
LastPing: time.Now(),
}
m.logger.Info().Str("internalConnID", internalConnID).Str("peerID", peerID).Str("username", username).Msg("nakama: New peer connection")
// Add to connections using internal connection ID as key
m.peerConnections.Set(internalConnID, peerConn)
// Handle the connection in a goroutine
go m.handlePeerConnection(peerConn)
}
// handlePeerConnection handles messages from a specific peer
func (m *Manager) handlePeerConnection(peerConn *PeerConnection) {
defer func() {
m.logger.Info().Str("peerId", peerConn.PeerId).Str("internalConnID", peerConn.ID).Msg("nakama: Peer disconnected")
// Remove from connections (safe to call multiple times)
if _, exists := m.peerConnections.Get(peerConn.ID); exists {
m.peerConnections.Delete(peerConn.ID)
// Remove peer from watch party if they were participating
m.watchPartyManager.HandlePeerDisconnected(peerConn.PeerId)
// Send event to client about peer disconnection (only if we actually removed it)
m.wsEventManager.SendEvent(events.NakamaPeerDisconnected, map[string]interface{}{
"peerId": peerConn.PeerId,
})
}
// Close connection (safe to call multiple times)
peerConn.Close()
}()
// Set up ping/pong handler
peerConn.Conn.SetPongHandler(func(appData string) error {
peerConn.LastPing = time.Now()
return nil
})
// Set read deadline
peerConn.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
for {
select {
case <-m.ctx.Done():
return
default:
var message Message
err := peerConn.Conn.ReadJSON(&message)
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
m.logger.Error().Err(err).Str("peerId", peerConn.PeerId).Msg("nakama: Unexpected close error")
}
return
}
// Handle the message using internal connection ID for message routing
if err := m.handleMessage(&message, peerConn.ID); err != nil {
m.logger.Error().Err(err).Str("peerId", peerConn.PeerId).Str("messageType", string(message.Type)).Msg("nakama: Failed to handle message")
// Send error response
errorMsg := &Message{
Type: MessageTypeError,
Payload: ErrorPayload{
Message: err.Error(),
},
Timestamp: time.Now(),
}
peerConn.SendMessage(errorMsg)
}
// Reset read deadline
peerConn.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
}
}
}
// hostPingRoutine sends ping messages to all connected peers
func (m *Manager) hostPingRoutine() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
select {
case <-m.ctx.Done():
return
case <-ticker.C:
m.peerConnections.Range(func(id string, conn *PeerConnection) bool {
// Send ping
message := &Message{
Type: MessageTypePing,
Payload: nil,
Timestamp: time.Now(),
}
if err := conn.SendMessage(message); err != nil {
m.logger.Error().Err(err).Str("peerId", conn.PeerId).Msg("nakama: Failed to send ping")
// Don't close here, let the stale connection cleanup handle it
}
return true
})
}
}
}
// staleConnectionCleanupRoutine periodically removes stale connections
func (m *Manager) staleConnectionCleanupRoutine() {
ticker := time.NewTicker(120 * time.Second) // Run every 2 minutes
defer ticker.Stop()
for {
select {
case <-m.ctx.Done():
return
case <-ticker.C:
m.RemoveStaleConnections()
}
}
}