package socket import ( "encoding/json" "g365sfu/logger" "g365sfu/sfu" connection "g365sfu/socket/struct" "g365sfu/utils" "net/http" "os" "github.com/gorilla/websocket" "github.com/pion/webrtc/v4" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { // Разрешаем со всех origin return true }, } // Получение секретного ключа из переменных окружения func getSecret() string { return os.Getenv("SECRET") } // Обработчик WebSocket соединений func HandleWebSocket(w http.ResponseWriter, r *http.Request) { conn, _ := upgrader.Upgrade(w, r, nil) defer conn.Close() // Канал для передачи байтов dataChan := make(chan []byte) var connection = &connection.Connection{ Identificator: randomSocketIdentifier(), Socket: conn, } AddSocket(connection) // Удаление сокета из хранилища при закрытии соединения defer RemoveSocket(connection.Identificator) // Запуск обработчика в горутине go processData(dataChan, connection) for { messageType, p, err := conn.ReadMessage() if err != nil || messageType != websocket.BinaryMessage { break } // Передача байтов для обработки dataChan <- p } } // Генерация случайного идентификатора для сокета func randomSocketIdentifier() string { // Генерация случайного идентификатора для сокета return "sock_" + utils.RandomString(10) } func processData(data <-chan []byte, connection *connection.Connection) { for bytes := range data { // Логика обработки байтов if bytes[0] == 0x01 { // Это рукопожатие, дальше сравниваем секретные ключи // Секретный ключ идет сразу после первого байта и до конца сообщения receivedSecret := string(bytes[1:]) if receivedSecret == getSecret() { logger.LogSuccessMessage("success handshake from " + connection.Socket.RemoteAddr().String()) AddSocket(connection) connection.Socket.WriteMessage(websocket.BinaryMessage, []byte{0x01}) return } connection.Socket.WriteMessage(websocket.BinaryMessage, []byte{0xFF}) logger.LogWarnMessage("failed handshake from " + connection.Socket.RemoteAddr().String() + " because of invalid secret key") connection.Socket.Close() return } // Так как следующие пакеты требуют обязательного завершения рукопожатия, нужно проверять, что сокет уже прошел рукопожатие if _, exists := GetSocket(connection.Identificator); !exists { logger.LogWarnMessage("received data from " + connection.Socket.RemoteAddr().String() + " but it has not completed handshake") connection.Socket.Close() return } // Создание комнаты if bytes[0] == 0x02 { room, _ := sfu.CreateRoom(connection) logger.LogSuccessMessage("room initializated " + room.RoomID) bytes = append([]byte{0x02}, []byte(room.RoomID)...) connection.Socket.WriteMessage(websocket.BinaryMessage, bytes) return } //SDP OFFER для подключения к комнате if bytes[0] == 0x03 { roomIdLen := int(bytes[1]) roomID := string(bytes[2 : 2+roomIdLen]) _, exists := sfu.GetRoom(roomID) if !exists { logger.LogWarnMessage("peer " + connection.Socket.RemoteAddr().String() + " tried to join non existing room " + roomID) return } peerIdLen := int(bytes[2+roomIdLen]) peerID := string(bytes[3+roomIdLen : 3+roomIdLen+peerIdLen]) logger.LogSuccessMessage("peer " + connection.Socket.RemoteAddr().String() + " joined to room " + roomID) var offer webrtc.SessionDescription err := json.Unmarshal(bytes[3+roomIdLen+peerIdLen:], &offer) if err != nil { logger.LogWarnMessage("failed to unmarshal offer from peer " + connection.Socket.RemoteAddr().String() + ": " + err.Error()) return } sfu.JoinWithOffer(roomID, peerID, offer) return } } }