ResolveSpec/pkg/websocketspec/example_test.go
2025-12-12 16:14:47 +02:00

240 lines
6.8 KiB
Go

package websocketspec_test
import (
"fmt"
"log"
"net/http"
"github.com/bitechdev/ResolveSpec/pkg/websocketspec"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// User model example
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
Name string `json:"name"`
Email string `json:"email"`
Status string `json:"status"`
}
// Post model example
type Post struct {
ID uint `json:"id" gorm:"primaryKey"`
Title string `json:"title"`
Content string `json:"content"`
UserID uint `json:"user_id"`
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
}
// Example_basicSetup demonstrates basic WebSocketSpec setup
func Example_basicSetup() {
// Connect to database
db, err := gorm.Open(postgres.Open("your-connection-string"), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
// Create WebSocket handler
handler := websocketspec.NewHandlerWithGORM(db)
// Register models
handler.Registry().RegisterModel("public.users", &User{})
handler.Registry().RegisterModel("public.posts", &Post{})
// Setup WebSocket endpoint
http.HandleFunc("/ws", handler.HandleWebSocket)
// Start server
log.Println("WebSocket server starting on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
// Example_withHooks demonstrates using lifecycle hooks
func Example_withHooks() {
db, _ := gorm.Open(postgres.Open("your-connection-string"), &gorm.Config{})
handler := websocketspec.NewHandlerWithGORM(db)
// Register models
handler.Registry().RegisterModel("public.users", &User{})
// Add authentication hook
handler.Hooks().Register(websocketspec.BeforeConnect, func(ctx *websocketspec.HookContext) error {
// Validate authentication token
// (In real implementation, extract from query params or headers)
userID := uint(123) // From token
// Store in connection metadata
ctx.Connection.SetMetadata("user_id", userID)
log.Printf("User %d connected", userID)
return nil
})
// Add authorization hook for read operations
handler.Hooks().RegisterBefore(websocketspec.OperationRead, func(ctx *websocketspec.HookContext) error {
userID, ok := ctx.Connection.GetMetadata("user_id")
if !ok {
return fmt.Errorf("unauthorized: not authenticated")
}
log.Printf("User %v reading %s.%s", userID, ctx.Schema, ctx.Entity)
// Add filter to only show user's own records
if ctx.Entity == "posts" {
// ctx.Options.Filters = append(ctx.Options.Filters, common.FilterOption{
// Column: "user_id",
// Operator: "eq",
// Value: userID,
// })
}
return nil
})
// Add logging hook after create
handler.Hooks().RegisterAfter(websocketspec.OperationCreate, func(ctx *websocketspec.HookContext) error {
userID, _ := ctx.Connection.GetMetadata("user_id")
log.Printf("User %v created record in %s.%s", userID, ctx.Schema, ctx.Entity)
return nil
})
// Add validation hook before create
handler.Hooks().RegisterBefore(websocketspec.OperationCreate, func(ctx *websocketspec.HookContext) error {
// Validate required fields
if data, ok := ctx.Data.(map[string]interface{}); ok {
if ctx.Entity == "users" {
if email, exists := data["email"]; !exists || email == "" {
return fmt.Errorf("validation error: email is required")
}
if name, exists := data["name"]; !exists || name == "" {
return fmt.Errorf("validation error: name is required")
}
}
}
return nil
})
// Add limit hook for subscriptions
handler.Hooks().Register(websocketspec.BeforeSubscribe, func(ctx *websocketspec.HookContext) error {
// Limit subscriptions per connection
maxSubscriptions := 10
currentCount := len(ctx.Connection.subscriptions)
if currentCount >= maxSubscriptions {
return fmt.Errorf("maximum subscriptions reached (%d)", maxSubscriptions)
}
log.Printf("Creating subscription %d/%d", currentCount+1, maxSubscriptions)
return nil
})
http.HandleFunc("/ws", handler.HandleWebSocket)
log.Println("Server with hooks starting on :8080")
http.ListenAndServe(":8080", nil)
}
// Example_monitoring demonstrates monitoring connections and subscriptions
func Example_monitoring() {
db, _ := gorm.Open(postgres.Open("your-connection-string"), &gorm.Config{})
handler := websocketspec.NewHandlerWithGORM(db)
handler.Registry.RegisterModel("public.users", &User{})
// Add connection tracking
handler.Hooks().Register(websocketspec.AfterConnect, func(ctx *websocketspec.HookContext) error {
count := handler.GetConnectionCount()
log.Printf("Client connected. Total connections: %d", count)
return nil
})
handler.Hooks().Register(websocketspec.AfterDisconnect, func(ctx *websocketspec.HookContext) error {
count := handler.GetConnectionCount()
log.Printf("Client disconnected. Total connections: %d", count)
return nil
})
// Add subscription tracking
handler.Hooks().Register(websocketspec.AfterSubscribe, func(ctx *websocketspec.HookContext) error {
count := handler.GetSubscriptionCount()
log.Printf("New subscription. Total subscriptions: %d", count)
return nil
})
// Monitoring endpoint
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Active Connections: %d\n", handler.GetConnectionCount())
fmt.Fprintf(w, "Active Subscriptions: %d\n", handler.GetSubscriptionCount())
})
http.HandleFunc("/ws", handler.HandleWebSocket)
log.Println("Server with monitoring starting on :8080")
http.ListenAndServe(":8080", nil)
}
// Example_clientSide shows client-side usage example
func Example_clientSide() {
// This is JavaScript code for documentation purposes
jsCode := `
// JavaScript WebSocket Client Example
const ws = new WebSocket("ws://localhost:8080/ws");
ws.onopen = () => {
console.log("Connected to WebSocket");
// Read users
ws.send(JSON.stringify({
id: "msg-1",
type: "request",
operation: "read",
schema: "public",
entity: "users",
options: {
filters: [{column: "status", operator: "eq", value: "active"}],
limit: 10
}
}));
// Subscribe to user changes
ws.send(JSON.stringify({
id: "sub-1",
type: "subscription",
operation: "subscribe",
schema: "public",
entity: "users",
options: {
filters: [{column: "status", operator: "eq", value: "active"}]
}
}));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === "response") {
if (message.success) {
console.log("Response:", message.data);
} else {
console.error("Error:", message.error);
}
} else if (message.type === "notification") {
console.log("Notification:", message.operation, message.data);
}
};
ws.onerror = (error) => {
console.error("WebSocket error:", error);
};
ws.onclose = () => {
console.log("WebSocket connection closed");
// Implement reconnection logic here
};
`
fmt.Println(jsCode)
}