slogan3

Help me een realtime notificatiesysteem implementeren in Go.

description

Door een realtime notificatiesysteem te implementeren, kan ik de betrokkenheid van gebruikers vergroten en tijdige updates bieden, wat de algehele gebruikerservaring in mijn toepassing verbetert.

prompt

try_prompt

Guideer me door het proces van het maken van een realtime notificatiesysteem in mijn Go-toepassing. Leg uit hoe WebSocket-verbindingen te implementeren, gebruikersabonnementen te beheren en notificatie ... more
generate_helper
disclaimerOnPageApi image_legal_disclaimer...

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een stapsgewijze gids voor het maken van een realtime notificatiesysteem in jouw Go-toepassing, inclusief voorbeeldcode. 1. WebSocket-verbindingen implementeren 2. Gebruikersabonnementen beheren 3. Notificaties sturen op basis van gebeurtenissen 4. Voorbeeldcode voor WebSocket-server en berichtenafhandeling --- ### 1. WebSocket-verbindingen implementeren Gebruik een bibliotheek zoals [gorilla/websocket](https://github.com/gorilla/websocket). Deze biedt een eenvoudige API voor het opzetten en beheren van WebSocket-verbindingen. **Installatie:** ```bash go get github.com/gorilla/websocket ``` --- ### 2. WebSocket-server opzetten en inkomende berichten afhandelen Hier is een voorbeeld van een eenvoudige WebSocket-server: ```go package main import ( "log" "net/http" "sync" "github.com/gorilla/websocket" ) // Client vertegenwoordigt een verbonden gebruiker type Client struct { conn *websocket.Conn send chan []byte } // Hub beheert alle clients en berichten type Hub struct { clients map[*Client]bool broadcast chan []byte register chan *Client unregister chan *Client mu sync.Mutex } var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true // voor testdoeleinden, in productie beperk dit }, } func main() { hub := newHub() go hub.run() http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) { serveWs(hub, w, r) }) log.Println("Server gestart op :8080") err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } } // Nieuwe Hub initialiseren func newHub() *Hub { return &Hub{ clients: make(map[*Client]bool), broadcast: make(chan []byte), register: make(chan *Client), unregister: make(chan *Client), } } // Hub run loop func (h *Hub) run() { for { select { case client := <-h.register: h.mu.Lock() h.clients[client] = true h.mu.Unlock() case client := <-h.unregister: h.mu.Lock() if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } h.mu.Unlock() case message := <-h.broadcast: h.mu.Lock() for client := range h.clients { select { case client.send <- message: default: close(client.send) delete(h.clients, client) } } h.mu.Unlock() } } } // WebSocket verbinding tot stand brengen func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println("Upgrade error:", err) return } client := &Client{conn: conn, send: make(chan []byte, 256)} hub.register <- client go client.writePump() go client.readPump(hub) } // Lezen van berichten van client func (c *Client) readPump(hub *Hub) { defer func() { hub.unregister <- c c.conn.Close() }() for { _, message, err := c.conn.ReadMessage() if err != nil { log.Println("Read error:", err) break } // Hier kan je inkomende berichten verwerken log.Printf("Ontvangen bericht: %s\n", message) // Bijvoorbeeld: broadcast het ontvangen bericht hub.broadcast <- message } } // Schrijven van berichten naar client func (c *Client) writePump() { defer c.conn.Close() for { message, ok := <-c.send if !ok { // kanaal gesloten c.conn.WriteMessage(websocket.CloseMessage, []byte{}) return } err := c.conn.WriteMessage(websocket.TextMessage, message) if err != nil { log.Println("Write error:", err) return } } } ``` --- ### 3. Gebruikersabonnementen beheren en notificaties sturen Je kunt bijvoorbeeld per gebruiker een lijst van abonnementen bijhouden. Zodra een gebeurtenis plaatsvindt (bijvoorbeeld een nieuw bericht), stuur je een notificatie naar alle relevante clients. Voorbeeld: ```go type Subscription struct { UserID string // meer velden indien nodig } // In het Hub kun je een map bijhouden van UserID naar clients // Bijvoorbeeld: type Hub struct { // ... userClients map[string][]*Client // ... } // Bij het registreren van een client: func (h *Hub) registerClient(userID string, client *Client) { h.mu.Lock() defer h.mu.Unlock() h.userClients[userID] = append(h.userClients[userID], client) } // Notificatie sturen aan specifieke gebruikers: func (h *Hub) sendNotification(userID string, message []byte) { h.mu.Lock() defer h.mu.Unlock() clients := h.userClients[userID] for _, client := range clients { select { case client.send <- message: default: close(client.send) // Verwijder client indien nodig } } } ``` **Let op:** Je moet bij het verbinden van een client ook het `userID` weten en opslaan. --- ### 4. Notificaties sturen op basis van gebeurtenissen Wanneer een gebeurtenis plaatsvindt (bijvoorbeeld een nieuw bericht in een chat), roep je de `sendNotification` functie aan met de juiste gebruikers. Voorbeeld: ```go // Gebeurtenis: nieuw bericht ontvangen func nieuwBericht(userID string, bericht string, hub *Hub) { notificatie := []byte("Nieuw bericht: " + bericht) hub.sendNotification(userID, notificatie) } ``` --- ### Samenvatting - Gebruik Gorilla WebSocket voor verbindingen. - Beheer verbonden clients en abonnementsinformatie in de Hub. - Verzend notificaties door specifieke clients te targeten. - Verwerk gebeurtenissen en stuur relevante notificaties. Wil je nog meer details over bijvoorbeeld authenticatie, beveiliging, of het opslaan van abonnementen?
provider: deepseek
model: deepseek-chat
Ik zal je stap voor stap begeleiden bij het bouwen van een realtime notificatiesysteem in Go met WebSockets. Hier is een complete implementatie: ## 1. Basisstructuur en dependencies ```go package main import ( "encoding/json" "log" "net/http" "sync" "time" "github.com/gorilla/websocket" ) // Notificatiestructuur type Notification struct { Type string `json:"type"` Message string `json:"message"` Data interface{} `json:"data,omitempty"` Time time.Time `json:"time"` } // Client vertegenwoordigt een WebSocket-verbinding type Client struct { ID string Conn *websocket.Conn Send chan Notification UserID string // Optioneel: voor gebruikersspecifieke notificaties } // NotificatieManager beheert alle clients type NotificationManager struct { Clients map[string]*Client Broadcast chan Notification Register chan *Client Unregister chan *Client Mutex sync.RWMutex } var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true // Pas aan voor productie! }, } ``` ## 2. NotificatieManager implementatie ```go func NewNotificationManager() *NotificationManager { return &NotificationManager{ Clients: make(map[string]*Client), Broadcast: make(chan Notification), Register: make(chan *Client), Unregister: make(chan *Client), } } func (manager *NotificationManager) Run() { for { select { case client := <-manager.Register: manager.Mutex.Lock() manager.Clients[client.ID] = client manager.Mutex.Unlock() log.Printf("Client geregistreerd: %s", client.ID) case client := <-manager.Unregister: manager.Mutex.Lock() if _, ok := manager.Clients[client.ID]; ok { close(client.Send) delete(manager.Clients, client.ID) } manager.Mutex.Unlock() log.Printf("Client uitgeschreven: %s", client.ID) case notification := <-manager.Broadcast: manager.Mutex.RLock() for _, client := range manager.Clients { select { case client.Send <- notification: default: close(client.Send) delete(manager.Clients, client.ID) } } manager.Mutex.RUnlock() } } } // Stuur notificatie naar specifieke gebruiker func (manager *NotificationManager) SendToUser(userID string, notification Notification) { manager.Mutex.RLock() defer manager.Mutex.RUnlock() for _, client := range manager.Clients { if client.UserID == userID { select { case client.Send <- notification: default: close(client.Send) delete(manager.Clients, client.ID) } } } } ``` ## 3. Client handlers ```go func (client *Client) ReadPump(manager *NotificationManager) { defer func() { manager.Unregister <- client client.Conn.Close() }() for { _, message, err := client.Conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { log.Printf("error: %v", err) } break } // Verwerk inkomende berichten (bijv. abonnementen) var msg map[string]interface{} if err := json.Unmarshal(message, &msg); err == nil { client.HandleMessage(msg, manager) } } } func (client *Client) WritePump() { defer func() { client.Conn.Close() }() for { select { case notification, ok := <-client.Send: if !ok { client.Conn.WriteMessage(websocket.CloseMessage, []byte{}) return } jsonData, err := json.Marshal(notification) if err != nil { log.Printf("JSON marshal error: %v", err) continue } if err := client.Conn.WriteMessage(websocket.TextMessage, jsonData); err != nil { log.Printf("Write error: %v", err) return } } } } func (client *Client) HandleMessage(msg map[string]interface{}, manager *NotificationManager) { if action, ok := msg["action"].(string); ok { switch action { case "subscribe": if userID, ok := msg["user_id"].(string); ok { client.UserID = userID log.Printf("Client %s geabonneerd op gebruiker %s", client.ID, userID) } case "unsubscribe": client.UserID = "" log.Printf("Client %s uitgeschreven", client.ID) } } } ``` ## 4. HTTP handlers en WebSocket endpoint ```go func generateClientID() string { return time.Now().Format("20060102150405") + "-" + string(rune(time.Now().Nanosecond())) } func serveWebSocket(manager *NotificationManager) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("WebSocket upgrade error: %v", err) return } client := &Client{ ID: generateClientID(), Conn: conn, Send: make(chan Notification, 256), } manager.Register <- client // Start goroutines voor lezen en schrijven go client.WritePump() go client.ReadPump(manager) } } // HTTP endpoint voor het sturen van notificaties func sendNotificationHandler(manager *NotificationManager) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { Type string `json:"type"` Message string `json:"message"` Data interface{} `json:"data"` UserID string `json:"user_id,omitempty"` // Leeg voor broadcast } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } notification := Notification{ Type: req.Type, Message: req.Message, Data: req.Data, Time: time.Now(), } if req.UserID != "" { // Stuur naar specifieke gebruiker manager.SendToUser(req.UserID, notification) log.Printf("Notificatie verzonden naar gebruiker %s: %s", req.UserID, req.Message) } else { // Broadcast naar alle clients manager.Broadcast <- notification log.Printf("Broadcast notificatie: %s", req.Message) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"status": "success"}) } } ``` ## 5. Hoofdapplicatie ```go func main() { manager := NewNotificationManager() go manager.Run() // WebSocket endpoint http.HandleFunc("/ws", serveWebSocket(manager)) // HTTP endpoint voor notificaties sturen http.HandleFunc("/api/notifications/send", sendNotificationHandler(manager)) // Statische bestanden voor demo http.Handle("/", http.FileServer(http.Dir("./static"))) log.Println("Server gestart op :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } ``` ## 6. Gebruiksvoorbeelden ### Notificatie sturen via HTTP POST: ```bash # Broadcast notificatie curl -X POST http://localhost:8080/api/notifications/send \ -H "Content-Type: application/json" \ -d '{ "type": "message", "message": "Nieuw bericht ontvangen", "data": {"from": "gebruiker123", "content": "Hallo wereld!"} }' # Gebruikersspecifieke notificatie curl -X POST http://localhost:8080/api/notifications/send \ -H "Content-Type: application/json" \ -d '{ "type": "message", "message": "Je hebt een nieuw bericht", "user_id": "gebruiker456", "data": {"from": "gebruiker123", "content": "Privé bericht"} }' ``` ### JavaScript client voorbeeld (static/index.html): ```html <!DOCTYPE html> <html> <body> <div id="notifications"></div> <script> const ws = new WebSocket('ws://localhost:8080/ws'); ws.onopen = function() { console.log('Verbonden met WebSocket'); // Abonneren op gebruiker ws.send(JSON.stringify({ action: 'subscribe', user_id: 'gebruiker456' })); }; ws.onmessage = function(event) { const notification = JSON.parse(event.data); const div = document.getElementById('notifications'); div.innerHTML += `<div class="notification"> <strong>${notification.type}</strong>: ${notification.message} <br><small>${new Date(notification.time).toLocaleString()}</small> </div>`; }; ws.onclose = function() { console.log('WebSocket verbinding gesloten'); }; </script> </body> </html> ``` ## Belangrijke kenmerken: 1. **Concurrentie-veilig**: Gebruikt mutex voor thread-safe operaties 2. **Schaalbaar**: Kan uitgebreid worden met Redis voor distributed notificaties 3. **Flexibel**: Ondersteunt zowel broadcast als gebruikersspecifieke notificaties 4. **Foutafhandeling**: Goede error handling en connection cleanup 5. **Abonnementsbeheer**: Clients kunnen zich abonneren op specifieke gebruikers Dit systeem biedt een solide basis voor realtime notificaties in je Go-toepassing!