Compare commits
4 Commits
572155d08f
...
c9aade2be3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9aade2be3 | ||
|
|
1f706385f8 | ||
|
|
153240912a | ||
|
|
db17ef8581 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
1
go.mod
1
go.mod
@@ -5,6 +5,7 @@ go 1.24.0
|
|||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
github.com/pion/datachannel v1.6.0 // indirect
|
github.com/pion/datachannel v1.6.0 // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||||
github.com/pion/dtls/v3 v3.1.2 // indirect
|
github.com/pion/dtls/v3 v3.1.2 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -7,6 +7,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
|||||||
66
logger/logger.go
Normal file
66
logger/logger.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
colorReset = "\033[0m"
|
||||||
|
colorRed = "\033[31m"
|
||||||
|
colorGreen = "\033[32m"
|
||||||
|
colorYellow = "\033[33m"
|
||||||
|
colorBlue = "\033[34m"
|
||||||
|
colorCyan = "\033[36m"
|
||||||
|
colorGray = "\033[90m"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogInfoMessage(message string) {
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
fmt.Printf("%s[g365sfu] %s[%s]%s %s[INFO]%s %s\n",
|
||||||
|
colorBlue,
|
||||||
|
colorGray, timestamp, colorReset,
|
||||||
|
colorGreen, colorReset,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogErrorMessage(message string) {
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
fmt.Printf("%s[g365sfu] %s[%s]%s %s[ERROR]%s %s\n",
|
||||||
|
colorBlue,
|
||||||
|
colorGray, timestamp, colorReset,
|
||||||
|
colorRed, colorReset,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogWarnMessage(message string) {
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
fmt.Printf("%s[g365sfu] %s[%s]%s %s[WARN]%s %s\n",
|
||||||
|
colorBlue,
|
||||||
|
colorGray, timestamp, colorReset,
|
||||||
|
colorYellow, colorReset,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogDebugMessage(message string) {
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
fmt.Printf("%s[g365sfu] %s[%s]%s %s[DEBUG]%s %s\n",
|
||||||
|
colorBlue,
|
||||||
|
colorGray, timestamp, colorReset,
|
||||||
|
colorBlue, colorReset,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogSuccessMessage(message string) {
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
fmt.Printf("%s[g365sfu] %s[%s]%s %s[SUCCESS]%s %s\n",
|
||||||
|
colorBlue,
|
||||||
|
colorGray, timestamp, colorReset,
|
||||||
|
colorCyan, colorReset,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
9
main.go
9
main.go
@@ -1,16 +1,25 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"g365sfu/logger"
|
||||||
"g365sfu/socket"
|
"g365sfu/socket"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
godotenv.Load()
|
||||||
|
if os.Getenv("SECRET") == "" {
|
||||||
|
logger.LogErrorMessage("server failed to start because not set secret key in .env variables")
|
||||||
|
return
|
||||||
|
}
|
||||||
http.HandleFunc("/", socket.HandleWebSocket)
|
http.HandleFunc("/", socket.HandleWebSocket)
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
if port == "" {
|
if port == "" {
|
||||||
port = "1001"
|
port = "1001"
|
||||||
}
|
}
|
||||||
|
logger.LogInfoMessage("server started at x.x.x.x:" + port)
|
||||||
http.ListenAndServe(":"+port, nil)
|
http.ListenAndServe(":"+port, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
59
socket/connections.go
Normal file
59
socket/connections.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package socket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Это хранилище для всех подключённых сокетов.
|
||||||
|
// Оно обеспечивает потокобезопасный доступ к ним,
|
||||||
|
// позволяя добавлять, удалять и получать сокеты без риска
|
||||||
|
// гонок данных.
|
||||||
|
|
||||||
|
// Здесь содержатся только соединения прошедшие рукопожатие
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
Identificator string
|
||||||
|
//Подсоединенный сокет
|
||||||
|
Socket *websocket.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Потокобезопасное хранилище подключённых сокетов
|
||||||
|
var (
|
||||||
|
handshakeCompletedSockets = make(map[string]*Connection)
|
||||||
|
socketsMutex = sync.RWMutex{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Добавление сокета в хранилище
|
||||||
|
func AddSocket(conn *Connection) {
|
||||||
|
socketsMutex.Lock()
|
||||||
|
defer socketsMutex.Unlock()
|
||||||
|
handshakeCompletedSockets[conn.Identificator] = conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаление сокета из хранилища
|
||||||
|
func RemoveSocket(identificator string) {
|
||||||
|
socketsMutex.Lock()
|
||||||
|
defer socketsMutex.Unlock()
|
||||||
|
delete(handshakeCompletedSockets, identificator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение сокета по идентификатору
|
||||||
|
func GetSocket(identificator string) (*Connection, bool) {
|
||||||
|
socketsMutex.RLock()
|
||||||
|
defer socketsMutex.RUnlock()
|
||||||
|
conn, exists := handshakeCompletedSockets[identificator]
|
||||||
|
return conn, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение всех сокетов
|
||||||
|
func GetAllSockets() []*Connection {
|
||||||
|
socketsMutex.RLock()
|
||||||
|
defer socketsMutex.RUnlock()
|
||||||
|
connections := make([]*Connection, 0, len(handshakeCompletedSockets))
|
||||||
|
for _, conn := range handshakeCompletedSockets {
|
||||||
|
connections = append(connections, conn)
|
||||||
|
}
|
||||||
|
return connections
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"g365sfu/logger"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
@@ -16,6 +18,10 @@ var upgrader = websocket.Upgrader{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSecret() string {
|
||||||
|
return os.Getenv("SECRET")
|
||||||
|
}
|
||||||
|
|
||||||
// Обработчик WebSocket соединений
|
// Обработчик WebSocket соединений
|
||||||
func HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
func HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||||
conn, _ := upgrader.Upgrade(w, r, nil)
|
conn, _ := upgrader.Upgrade(w, r, nil)
|
||||||
@@ -24,8 +30,16 @@ func HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Канал для передачи байтов
|
// Канал для передачи байтов
|
||||||
dataChan := make(chan []byte)
|
dataChan := make(chan []byte)
|
||||||
|
|
||||||
|
var connection = &Connection{
|
||||||
|
Identificator: randomSocketIdentifier(),
|
||||||
|
Socket: conn,
|
||||||
|
}
|
||||||
|
AddSocket(connection)
|
||||||
|
// Удаление сокета из хранилища при закрытии соединения
|
||||||
|
defer RemoveSocket(connection.Identificator)
|
||||||
|
|
||||||
// Запуск обработчика в горутине
|
// Запуск обработчика в горутине
|
||||||
go processData(dataChan)
|
go processData(dataChan, connection)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
messageType, p, err := conn.ReadMessage()
|
messageType, p, err := conn.ReadMessage()
|
||||||
@@ -37,11 +51,46 @@ func HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func processData(data <-chan []byte) {
|
// Генерация случайного идентификатора для сокета
|
||||||
|
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 {
|
for bytes := range data {
|
||||||
// Логика обработки байтов
|
// Логика обработки байтов
|
||||||
if bytes[0] == 0x01 {
|
if bytes[0] == 0x01 {
|
||||||
fmt.Print("Type 0x01 received")
|
// Это рукопожатие, дальше сравниваем секретные ключи
|
||||||
}
|
// Секретный ключ идет сразу после первого байта и до конца сообщения
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Следующие типы сообщений
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user