package boot import ( "encoding/json" "g365sfu/bytebuffer" "g365sfu/logger" "g365sfu/network" "g365sfu/sfu" "g365sfu/socket" connection "g365sfu/socket/struct" "g365sfu/turn" "g365sfu/utils" "net/http" "os" "github.com/joho/godotenv" "github.com/pion/webrtc/v4" ) func Bootstrap() { godotenv.Load() sfu.InitWebRTCEngines() if os.Getenv("SECRET") == "" { logger.LogErrorMessage("server failed to start because not set secret key in .env variables") return } http.HandleFunc("/", socket.HandleWebSocket) port := os.Getenv("PORT") if port == "" { port = "1001" } sfu.OnLocalICECandidate = OnLocalICECandidate sfu.OnServerOffer = OnServerOffer sfu.OnRoomDelete = OnRoomDelete sfu.OnPeerDisconnected = OnPeerDisconnected if os.Getenv("TURN_ALLOW") == "true" { turnServer, err := turn.Start(turn.Config{ ListenAddr: "0.0.0.0:3478", PublicIP: os.Getenv("TURN_PUBLIC_IP"), Realm: "g365sfu", Username: os.Getenv("TURN_USER"), Password: os.Getenv("TURN_PASS"), MinRelayPort: uint16(utils.AtoiOrDefault(os.Getenv("TURN_PORT_RANGE_FROM"), 40000)), MaxRelayPort: uint16(utils.AtoiOrDefault(os.Getenv("TURN_PORT_RANGE_TO"), 50000)), }) if err != nil { logger.LogWarnMessage("error while starting TURN server: " + err.Error()) logger.LogInfoMessage("starting without TURN server, peer connections may fail if clients are behind symmetric NATs") } else { logger.LogInfoMessage("server TURN started at 0.0.0.0:3478") // Заполняем глобальные переменные для TURN провайдера, чтобы их могли использовать другие части приложения // Обратите внимание, заполняем их только в случе успешного старта Turn сервера turn.TURN_PASS = os.Getenv("TURN_PASS") turn.TURN_USER = os.Getenv("TURN_USER") turn.TURN_PUBLIC_IP = os.Getenv("TURN_PUBLIC_IP") defer turnServer.Close() } } else { // TURN сервер выключен в конфиге, что может влиять на соединение некоторых пользователей logger.LogInfoMessage("starting without TURN server, peer connections may fail if clients are behind symmetric NATs") } logger.LogInfoMessage("server SFU started at x.x.x.x:" + port) http.ListenAndServe(":"+port, nil) } // Коллбек для обработки новых ICE кандидатов от сервера к пиру func OnLocalICECandidate(roomID string, peerID string, candidate webrtc.ICECandidateInit) { room, exists := sfu.GetRoom(roomID) if !exists { logger.LogWarnMessage("tried to send local ICE candidate to non existing room " + roomID) return } jsonCandidate, _ := json.Marshal(candidate) buffer := bytebuffer.Allocate( 1 + 4 + len([]byte(roomID)) + 4 + len([]byte(peerID)) + 4 + len(jsonCandidate), ) buffer.Put(byte(network.ON_LOCAL_ICE_CANDIDATE)) buffer.PutUint32(uint32(len([]byte(roomID)))) buffer.PutBytes([]byte(roomID)) buffer.PutUint32(uint32(len([]byte(peerID)))) buffer.PutBytes([]byte(peerID)) buffer.PutUint32(uint32(len([]byte(jsonCandidate)))) buffer.PutBytes([]byte(jsonCandidate)) buffer.Flip() room.Server.WriteBinary(buffer.Bytes()) } // Обработка нового оффера от сервера для конкретного пира (при renegotiation) func OnServerOffer(roomID string, peerID string, offer webrtc.SessionDescription) { room, exists := sfu.GetRoom(roomID) if !exists { logger.LogWarnMessage("tried to send server offer to non existing room " + roomID) return } jsonOffer, _ := json.Marshal(offer) buffer := bytebuffer.Allocate( 1 + 4 + len([]byte(roomID)) + 4 + len([]byte(peerID)) + 4 + len(jsonOffer), ) buffer.Put(byte(network.ON_SERVER_OFFER)) buffer.PutUint32(uint32(len([]byte(roomID)))) buffer.PutBytes([]byte(roomID)) buffer.PutUint32(uint32(len([]byte(peerID)))) buffer.PutBytes([]byte(peerID)) buffer.PutUint32(uint32(len([]byte(jsonOffer)))) buffer.PutBytes([]byte(jsonOffer)) buffer.Flip() room.Server.WriteBinary(buffer.Bytes()) } func OnRoomDelete(roomID string, server *connection.Connection) { buffer := bytebuffer.Allocate(1 + 4 + len([]byte(roomID))) buffer.Put(byte(network.ON_ROOM_DELETE)) buffer.PutUint32(uint32(len([]byte(roomID)))) buffer.PutBytes([]byte(roomID)) buffer.Flip() server.WriteBinary(buffer.Bytes()) } func OnPeerDisconnected(roomID string, peerID string, server *connection.Connection, reason sfu.DisconnectReason) { buffer := bytebuffer.Allocate(1 + 4 + len([]byte(roomID)) + 4 + len([]byte(peerID)) + 4) buffer.Put(byte(network.ON_PEER_DISCONNECTED)) buffer.PutUint32(uint32(len([]byte(roomID)))) buffer.PutBytes([]byte(roomID)) buffer.PutUint32(uint32(len([]byte(peerID)))) buffer.PutBytes([]byte(peerID)) buffer.PutUint32(uint32(reason)) buffer.Flip() server.WriteBinary(buffer.Bytes()) }