package socket import ( "g365sfu/logger" "math/rand" "net/http" "os" "github.com/gorilla/websocket" ) 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{ 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_" + randomString(10) } // Генерация случайной строки заданной длины func randomString(n int) string { const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, n) for i := range b { b[i] = letters[rand.Intn(len(letters))] } return string(b) } func processData(data <-chan []byte, 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") return } // Так как следующие пакеты требуют обязательного завершения рукопожатия, нужно проверять, что сокет уже прошел рукопожатие if _, exists := GetSocket(connection.Identificator); !exists { logger.LogWarnMessage("received data from " + connection.Socket.RemoteAddr().String() + " but it has not completed handshake") return } // Следующие типы сообщений } }