added websocket
parent
8f76aa49bd
commit
f5f9e4f619
2
go.mod
2
go.mod
|
@ -4,11 +4,13 @@ go 1.20
|
|||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/fasthttp/websocket v1.5.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.12.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.44.0 // indirect
|
||||
github.com/gofiber/websocket/v2 v2.1.6 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -3,6 +3,8 @@ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
|
|||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fasthttp/websocket v1.5.2 h1:KdCb0EpLpdJpfE3IPA5YLK/aYBO3dhZcvwxz6tXe2LQ=
|
||||
github.com/fasthttp/websocket v1.5.2/go.mod h1:S0KC1VBlx1SaXGXq7yi1wKz4jMub58qEnHQG9oHuqBw=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
|
@ -14,6 +16,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
|
|||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofiber/fiber/v2 v2.44.0 h1:Z90bEvPcJM5GFJnu1py0E1ojoerkyew3iiNJ78MQCM8=
|
||||
github.com/gofiber/fiber/v2 v2.44.0/go.mod h1:VTMtb/au8g01iqvHyaCzftuM/xmZgKOZCtFzz6CdV9w=
|
||||
github.com/gofiber/websocket/v2 v2.1.6 h1:k4z+YqzGUwbCQJCIW+mDJF2iCcBfRY7BJGUa2k+VHXo=
|
||||
github.com/gofiber/websocket/v2 v2.1.6/go.mod h1:o+oXFwHjavIiM2KWo/MNpcIOruS0am16h3efqnjXLis=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "Janex Device Acryl Led Lamp"
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "Produktionstask 1",
|
||||
"inputs": [
|
||||
{
|
||||
"parameterName": "irgendwas",
|
||||
"type": "string",
|
||||
"displayName": "Irgendwas tolles"
|
||||
},
|
||||
{
|
||||
"parameterName": "kiste",
|
||||
"type": "number",
|
||||
"displayName": "Nummer der Kiste"
|
||||
}
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"name": "Bild zu Label konvertieren",
|
||||
"onFinish": "pause",
|
||||
"undoPossible": false,
|
||||
"scriptPath": "",
|
||||
"parameter": [
|
||||
{
|
||||
"parameterName": "labelformat",
|
||||
"type": "string",
|
||||
"displayName": "Format des Labels",
|
||||
"global": false
|
||||
},
|
||||
{
|
||||
"parameterName": "kiste",
|
||||
"type": "number",
|
||||
"displayName": "Nummer der Kiste",
|
||||
"global": true
|
||||
}
|
||||
],
|
||||
"feedback": "image"
|
||||
},
|
||||
{
|
||||
"name": "Label drucken",
|
||||
"onFinish": "nextStep",
|
||||
"undoPossible": false,
|
||||
"scriptPath": "",
|
||||
"parameter": [],
|
||||
"feedback": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "Roese"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "Umbach"
|
||||
}
|
48
main.go
48
main.go
|
@ -4,12 +4,16 @@ import (
|
|||
"janex/admin-dashboard-backend/modules/config"
|
||||
"janex/admin-dashboard-backend/modules/database"
|
||||
"janex/admin-dashboard-backend/modules/logger"
|
||||
"janex/admin-dashboard-backend/modules/structs"
|
||||
"janex/admin-dashboard-backend/modules/utils"
|
||||
"janex/admin-dashboard-backend/routers/router"
|
||||
"janex/admin-dashboard-backend/socketserver"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
flogger "github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -32,6 +36,50 @@ func main() {
|
|||
|
||||
router.SetupRoutes(app)
|
||||
|
||||
app.Use("/ws", func(c *fiber.Ctx) error {
|
||||
// IsWebSocketUpgrade returns true if the client
|
||||
// requested upgrade to the WebSocket protocol.
|
||||
if websocket.IsWebSocketUpgrade(c) {
|
||||
sessionId := c.Query("auth")
|
||||
|
||||
if len(sessionId) != utils.LenHeaderXAuthorization {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
// validate ws session
|
||||
|
||||
var userSession structs.UserSession
|
||||
|
||||
database.DB.First(&userSession, "id = ?", sessionId)
|
||||
|
||||
if userSession.Id == "" {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
log.Info().Msg("session id: " + userSession.Id + " user: " + userSession.Id)
|
||||
|
||||
var user structs.User
|
||||
|
||||
database.DB.First(&user, "id = ?", userSession.UserId)
|
||||
|
||||
if user.Id == "" {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
log.Info().Msg("user " + user.Id + user.Username)
|
||||
|
||||
c.Locals("sessionId", sessionId)
|
||||
c.Locals("userId", user.Id)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
return fiber.ErrUpgradeRequired
|
||||
})
|
||||
|
||||
go socketserver.RunHub()
|
||||
go socketserver.WebSocketServer(app)
|
||||
|
||||
app.Listen(config.Cfg.Host + ":" + config.Cfg.Port)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"janex/admin-dashboard-backend/modules/structs"
|
||||
"sync"
|
||||
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
||||
var socketClients []*structs.SocketClient
|
||||
var mu sync.RWMutex
|
||||
|
||||
func AddSocketClient(sessionId string, socketClient *structs.SocketClient) {
|
||||
mu.Lock()
|
||||
socketClients = append(socketClients, socketClient)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func DeleteClientByConn(conn *websocket.Conn) {
|
||||
mu.Lock()
|
||||
|
||||
for i := 0; i < len(socketClients); i++ {
|
||||
if socketClients[i].Conn == conn {
|
||||
socketClients = remove(socketClients, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func remove(s []*structs.SocketClient, i int) []*structs.SocketClient {
|
||||
return append(s[:i], s[i+1:]...)
|
||||
}
|
||||
|
||||
func GetSocketClients() []*structs.SocketClient {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
|
||||
return socketClients
|
||||
}
|
||||
|
||||
/*
|
||||
func GetSocketClient(sessionId string) (socketClient *structs.SocketClient, ok bool) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
|
||||
client, ok := socketClients[sessionId]
|
||||
|
||||
return client, ok
|
||||
}
|
||||
|
||||
func GetSocketClientByConn(conn *websocket.Conn) (socketClient *structs.SocketClient, err error) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
|
||||
for _, client := range socketClients {
|
||||
if client.Conn == conn {
|
||||
return client, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("Failed to find socket client by ws conn")
|
||||
}*/
|
|
@ -0,0 +1,73 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type SocketClient struct {
|
||||
SessionId string
|
||||
UserId string
|
||||
Conn *websocket.Conn
|
||||
connMu sync.Mutex
|
||||
}
|
||||
|
||||
type SocketMessage struct {
|
||||
Conn *websocket.Conn
|
||||
Msg []byte
|
||||
}
|
||||
|
||||
type SendSocketMessage struct {
|
||||
Cmd int
|
||||
Body any
|
||||
}
|
||||
|
||||
type ReceivedMessage struct {
|
||||
Cmd int
|
||||
Body any
|
||||
}
|
||||
|
||||
func (socketClient *SocketClient) SendCloseMessage() error {
|
||||
return socketClient.writeMessage(websocket.CloseMessage, SendSocketMessage{}, true)
|
||||
}
|
||||
|
||||
func (socketClient *SocketClient) SendMessage(message SendSocketMessage) error {
|
||||
return socketClient.writeMessage(websocket.TextMessage, message, false)
|
||||
}
|
||||
|
||||
func (socketClient *SocketClient) writeMessage(messageType int, message SendSocketMessage, closeMessage bool) error {
|
||||
var marshaledMessage []byte
|
||||
var err error
|
||||
|
||||
if closeMessage {
|
||||
//marshaledMessage = websocket.FormatCloseMessage(utils.WsCloseCodeNewConnectionWasMade, "")
|
||||
} else {
|
||||
marshaledMessage, err = json.Marshal(message)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Msgf("Failed to marshal ws message, err: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
socketClient.connMu.Lock()
|
||||
defer socketClient.connMu.Unlock()
|
||||
|
||||
if socketClient.Conn == nil {
|
||||
log.Error().Msgf("Failed to ws message because conn is nil")
|
||||
return errors.New("ws client conn is nil")
|
||||
}
|
||||
|
||||
err = socketClient.Conn.WriteMessage(messageType, marshaledMessage)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Msgf("Failed to write ws message, err: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -2,12 +2,9 @@ package structs
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Id string
|
||||
Username string
|
||||
Email string
|
||||
|
@ -16,7 +13,6 @@ type User struct {
|
|||
}
|
||||
|
||||
type UserSession struct {
|
||||
gorm.Model
|
||||
Id string
|
||||
UserId string
|
||||
UserAgent string
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Request on web startup
|
||||
// Requested on web startup
|
||||
func User(c *fiber.Ctx) error {
|
||||
xAuthorization := utils.GetXAuhorizationHeader(c)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ func SetupRoutes(app *fiber.App) {
|
|||
|
||||
u := v1.Group("/user")
|
||||
u.Post("/auth/login", user.UserLogin)
|
||||
u.Delete("/auth/logout", user.UserLogout)
|
||||
u.Get("/", userSessionValidation, user.User)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package socketclients
|
||||
|
||||
import (
|
||||
"janex/admin-dashboard-backend/modules/cache"
|
||||
"janex/admin-dashboard-backend/modules/structs"
|
||||
)
|
||||
|
||||
const (
|
||||
SentCmdUpdateConnectedUsers = 1
|
||||
)
|
||||
|
||||
func BroadcastMessage(sendSocketMessage structs.SendSocketMessage) {
|
||||
for _, client := range cache.GetSocketClients() {
|
||||
client.SendMessage(sendSocketMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateConnectedUsers() {
|
||||
BroadcastMessage(structs.SendSocketMessage{
|
||||
Cmd: SentCmdUpdateConnectedUsers,
|
||||
Body: len(cache.GetSocketClients()),
|
||||
})
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package socketserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"janex/admin-dashboard-backend/modules/cache"
|
||||
"janex/admin-dashboard-backend/modules/structs"
|
||||
"janex/admin-dashboard-backend/socketclients"
|
||||
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var register = make(chan *structs.SocketClient)
|
||||
var broadcast = make(chan structs.SocketMessage)
|
||||
var unregister = make(chan *websocket.Conn)
|
||||
|
||||
func RunHub() {
|
||||
for {
|
||||
select {
|
||||
case newSocketClient := <-register:
|
||||
userId := fmt.Sprintf("%v", newSocketClient.Conn.Locals("userId"))
|
||||
sessionId := fmt.Sprintf("%v", newSocketClient.Conn.Locals("sessionId"))
|
||||
|
||||
newSocketClient.SessionId = sessionId
|
||||
newSocketClient.UserId = userId
|
||||
|
||||
cache.AddSocketClient(sessionId, newSocketClient)
|
||||
|
||||
log.Debug().Msgf("clients: %d", len(cache.GetSocketClients()))
|
||||
log.Debug().Msgf("REGISTER CLIENT: %s", sessionId)
|
||||
|
||||
socketclients.UpdateConnectedUsers()
|
||||
|
||||
case data := <-broadcast:
|
||||
var receivedMessage structs.ReceivedMessage
|
||||
|
||||
if err := json.Unmarshal(data.Msg, &receivedMessage); err != nil {
|
||||
log.Error().Msgf("Failed to unmarshal received msg, err: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info().Msgf("Received message: %s", receivedMessage)
|
||||
|
||||
case connection := <-unregister:
|
||||
cache.DeleteClientByConn(connection)
|
||||
|
||||
socketclients.UpdateConnectedUsers()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package socketserver
|
||||
|
||||
import (
|
||||
"janex/admin-dashboard-backend/modules/structs"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func WebSocketServer(app *fiber.App) {
|
||||
app.Get("/ws", websocket.New(func(c *websocket.Conn) {
|
||||
defer func() {
|
||||
unregister <- c
|
||||
c.Close()
|
||||
}()
|
||||
|
||||
register <- &structs.SocketClient{Conn: c}
|
||||
|
||||
for {
|
||||
messageType, msg, err := c.ReadMessage()
|
||||
|
||||
if err != nil {
|
||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
||||
log.Error().Msgf("Read err: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if messageType == websocket.TextMessage {
|
||||
broadcast <- structs.SocketMessage{Conn: c, Msg: msg}
|
||||
} else {
|
||||
log.Error().Msgf("websocket message received of type %s", messageType)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
Loading…
Reference in New Issue