make json abstraction for server
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func SaveJson(file string, data any) error {
|
||||
f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Write(b)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func OpenJson(file string, data any) (err error) {
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
21
models/jsonData.go
Normal file
21
models/jsonData.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
type JsonData struct {
|
||||
Get *[]Get `json:"get,omitempty"`
|
||||
Set *[]Set `json:"set,omitempty"`
|
||||
}
|
||||
|
||||
type Get struct {
|
||||
Path string `json:"path"`
|
||||
Query *Query `json:"query,omitempty"`
|
||||
}
|
||||
|
||||
type Set struct {
|
||||
Path string `json:"path"`
|
||||
Value any `json:"value"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
Depth int `json:"depth,omitempty"`
|
||||
RegExp string `json:"regExp,omitempty"`
|
||||
}
|
49
server/clients.go
Normal file
49
server/clients.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/coder/websocket/wsjson"
|
||||
"github.com/zuadi/tecamino-dbm.git/models"
|
||||
)
|
||||
|
||||
var (
|
||||
clients = make(map[*Client]bool)
|
||||
clientsMu sync.Mutex
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conn *websocket.Conn
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func registerClient(c *Client) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
clients[c] = true
|
||||
log.Printf("Client connected (%d total)", len(clients))
|
||||
}
|
||||
|
||||
func unregisterClient(c *Client) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
delete(clients, c)
|
||||
log.Printf("Client disconnected (%d total)", len(clients))
|
||||
}
|
||||
|
||||
func broadcast(data models.JsonData) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
for c := range clients {
|
||||
go func(client *Client) {
|
||||
err := wsjson.Write(client.ctx, client.conn, data)
|
||||
if err != nil {
|
||||
log.Printf("Broadcast error: %v", err)
|
||||
}
|
||||
}(c)
|
||||
}
|
||||
}
|
13
server/routes.go
Normal file
13
server/routes.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package server
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func (s *Server) AddRoutes() {
|
||||
s.engine.GET("/json_data", func(c *gin.Context) {
|
||||
handleWebSocket(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
s.engine.GET("/", func(c *gin.Context) {
|
||||
c.String(200, "WebSocket Broadcast Server is running!")
|
||||
})
|
||||
}
|
@@ -1,15 +1,8 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/coder/websocket/wsjson"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -17,28 +10,11 @@ type Server struct {
|
||||
engine *gin.Engine
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
conn *websocket.Conn
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
var (
|
||||
clients = make(map[*Client]bool)
|
||||
clientsMu sync.Mutex
|
||||
)
|
||||
|
||||
func NewServer() *Server {
|
||||
s := Server{}
|
||||
|
||||
s.engine = gin.Default()
|
||||
|
||||
s.engine.GET("/ws", func(c *gin.Context) {
|
||||
handleWebSocket(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
s.engine.GET("/", func(c *gin.Context) {
|
||||
c.String(200, "WebSocket Broadcast Server is running!")
|
||||
})
|
||||
s := Server{
|
||||
engine: gin.Default(),
|
||||
}
|
||||
s.AddRoutes()
|
||||
return &s
|
||||
}
|
||||
|
||||
@@ -48,68 +24,3 @@ func (s *Server) Serve(port uint) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||
OriginPatterns: []string{"*"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Println("WebSocket accept error:", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close(websocket.StatusInternalError, "Internal error")
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
client := &Client{conn: conn, ctx: ctx}
|
||||
|
||||
// Register client
|
||||
registerClient(client)
|
||||
defer unregisterClient(client)
|
||||
|
||||
// Read loop
|
||||
for {
|
||||
var msg string
|
||||
err := wsjson.Read(ctx, conn, &msg)
|
||||
if err != nil {
|
||||
log.Println("Read error:", err)
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Received: %s", msg)
|
||||
|
||||
// Broadcast to all
|
||||
broadcast("Broadcast: " + msg)
|
||||
}
|
||||
|
||||
conn.Close(websocket.StatusNormalClosure, "Normal closure")
|
||||
}
|
||||
|
||||
func registerClient(c *Client) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
clients[c] = true
|
||||
log.Printf("Client connected (%d total)", len(clients))
|
||||
}
|
||||
|
||||
func unregisterClient(c *Client) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
delete(clients, c)
|
||||
log.Printf("Client disconnected (%d total)", len(clients))
|
||||
}
|
||||
|
||||
func broadcast(message string) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
for c := range clients {
|
||||
go func(client *Client) {
|
||||
err := wsjson.Write(client.ctx, client.conn, message)
|
||||
if err != nil {
|
||||
log.Printf("Broadcast error: %v", err)
|
||||
}
|
||||
}(c)
|
||||
}
|
||||
}
|
||||
|
62
server/webSocket.go
Normal file
62
server/webSocket.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/coder/websocket/wsjson"
|
||||
"github.com/zuadi/tecamino-dbm.git/models"
|
||||
)
|
||||
|
||||
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||
OriginPatterns: []string{"*"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Println("WebSocket accept error:", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close(websocket.StatusInternalError, "Internal error")
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
client := &Client{conn: conn, ctx: ctx}
|
||||
|
||||
// Register client
|
||||
registerClient(client)
|
||||
defer unregisterClient(client)
|
||||
|
||||
// Read loop
|
||||
for {
|
||||
var data models.JsonData
|
||||
err := wsjson.Read(ctx, conn, &data)
|
||||
if err != nil {
|
||||
log.Println("Read error:", err)
|
||||
var response struct {
|
||||
Code int `json:"errorCode"`
|
||||
Message string `json:"message"`
|
||||
Error bool `json:"error"`
|
||||
}
|
||||
response.Code = 404
|
||||
response.Error = true
|
||||
response.Message = err.Error()
|
||||
|
||||
err = wsjson.Write(ctx, conn, response)
|
||||
if err != nil {
|
||||
log.Println("Read error:", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Received: %v", data)
|
||||
|
||||
// Broadcast to all
|
||||
broadcast(data)
|
||||
}
|
||||
|
||||
conn.Close(websocket.StatusNormalClosure, "Normal closure")
|
||||
}
|
Reference in New Issue
Block a user