Namespace API Reference¶
Der Typ Namespace repräsentiert eine Verbindung zu einem bestimmten Namespace in Socket.IO. Namespaces ermöglichen das Multiplexen mehrerer Verbindungen über eine einzelne WebSocket-Verbindung.
Inhaltsverzeichnis¶
- Konzept der Namespaces
- Abrufen von Namespaces
- Ereignismethoden
- Sendemethoden
- Statusmethoden
- Beispiele
Konzept der Namespaces¶
Namespaces sind separate Kommunikationskanäle, die dieselbe physische Verbindung teilen. Sie ermöglichen:
- Logische Trennung: Verschiedene Bereiche Ihrer Anwendung können verschiedene Namespaces verwenden
- Effizienz: Eine einzelne WebSocket-Verbindung verarbeitet mehrere Namespaces
- Sicherheit: Sie können den Zugriff auf bestimmte Namespaces steuern
Standard-Namespace¶
Der Standard-Namespace ist /. Wenn Sie Methoden direkt auf Socket verwenden, verwenden Sie diesen Namespace:
// Diese beiden Codes sind äquivalent
client.On("event", handler)
client.Of("/").On("event", handler)
Abrufen von Namespaces¶
Namespaces werden über die Methode Of() von Socket abgerufen:
// Benutzerdefinierten Namespace abrufen
chat := client.Of("/chat")
admin := client.Of("/admin")
notifications := client.Of("/notifications")
Ereignismethoden¶
On¶
Registriert einen Handler zum Abhören eines bestimmten Ereignisses in diesem Namespace.
Parameter: - event (string): Ereignisname - handler (EventHandler): Funktion, die beim Empfang des Ereignisses ausgeführt wird
Beispiel:
chat := client.Of("/chat")
chat.On("message", func(data ...interface{}) {
msg := data[0].(string)
fmt.Printf("Chat-Nachricht: %s\n", msg)
})
chat.On("user-joined", func(data ...interface{}) {
user := data[0].(map[string]interface{})
fmt.Printf("%s ist dem Chat beigetreten\n", user["name"])
})
OnConnect¶
Registriert einen Handler, der ausgeführt wird, wenn dieser Namespace erfolgreich verbunden ist.
Parameter: - handler (func()): Funktion, die beim Verbinden ausgeführt wird
Beispiel:
chat := client.Of("/chat")
chat.OnConnect(func() {
fmt.Println("Mit Namespace /chat verbunden")
// Initiales Ereignis in diesem Namespace senden
chat.Emit("join-room", "general")
})
OnDisconnect¶
Registriert einen Handler, der ausgeführt wird, wenn dieser Namespace getrennt wird.
Parameter: - handler (func(reason string)): Funktion, die den Grund für die Trennung erhält
Beispiel:
chat := client.Of("/chat")
chat.OnDisconnect(func(reason string) {
fmt.Printf("Von /chat getrennt: %s\n", reason)
})
Sendemethoden¶
Emit¶
Sendet ein Ereignis an den Server in diesem Namespace.
Parameter: - event (string): Ereignisname - data (...interface{}): Zu sendende Argumente
Rückgabewert: - error: Fehler, falls die Operation fehlschlägt
Beispiel:
chat := client.Of("/chat")
// Einfache Nachricht senden
chat.Emit("message", "Hallo an alle")
// Strukturierte Daten senden
chat.Emit("action", map[string]interface{}{
"type": "typing",
"user": "juan",
})
// Mehrere Argumente
chat.Emit("chat-message", "juan", "Hallo", time.Now().Unix())
EmitWithAck¶
Sendet ein Ereignis und wartet auf eine Antwort (Acknowledgment) vom Server in diesem Namespace.
Parameter: - event (string): Ereignisname - ack (AckCallback): Callback-Funktion, die die Antwort erhält - data (...interface{}): Zu sendende Argumente
Rückgabewert: - error: Fehler, falls die Operation fehlschlägt
Beispiel:
chat := client.Of("/chat")
chat.EmitWithAck("get-history", func(response ...interface{}) {
if response == nil {
fmt.Println("Timeout beim Warten auf Verlauf")
return
}
history := response[0].([]interface{})
fmt.Printf("Verlauf erhalten: %d Nachrichten\n", len(history))
}, "sala-general")
EmitBinary¶
Sendet ein Ereignis mit Binärdaten in diesem Namespace.
Parameter: - event (string): Ereignisname - binaryData ([]byte): Zu sendende Binärdaten - data (...interface{}): Zusätzliche Argumente (optional)
Rückgabewert: - error: Fehler, falls die Operation fehlschlägt
Beispiel:
chat := client.Of("/chat")
// Bild lesen
imageData, err := os.ReadFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Bild mit Metadaten senden
chat.EmitBinary("image", imageData, map[string]interface{}{
"filename": "photo.jpg",
"from": "usuario123",
"size": len(imageData),
})
Statusmethoden¶
IsConnected¶
Gibt zurück, ob dieser Namespace derzeit verbunden ist.
Rückgabewert: - bool: true wenn verbunden, false andernfalls
Beispiel:
chat := client.Of("/chat")
if chat.IsConnected() {
chat.Emit("ping")
} else {
fmt.Println("Chat-Namespace ist nicht verbunden")
}
GetPath¶
Gibt den Pfad dieses Namespace zurück.
Rückgabewert: - string: Namespace-Pfad (z.B.: /chat, /admin)
Beispiel:
Beispiele¶
Grundlegendes Beispiel: Chat-Anwendung¶
package main
import (
"fmt"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
// Chat-Namespace
chat := client.Of("/chat")
chat.OnConnect(func() {
fmt.Println("✅ Mit Chat verbunden")
// Einem Raum beitreten
chat.Emit("join-room", "general")
})
chat.On("message", func(data ...interface{}) {
username := data[0].(string)
message := data[1].(string)
fmt.Printf("💬 [%s]: %s\n", username, message)
})
chat.On("user-joined", func(data ...interface{}) {
username := data[0].(string)
fmt.Printf("👤 %s ist dem Chat beigetreten\n", username)
})
chat.On("user-left", func(data ...interface{}) {
username := data[0].(string)
fmt.Printf("👋 %s hat den Chat verlassen\n", username)
})
// Nachricht senden
chat.Emit("message", "juan", "Hallo an alle!")
select {}
}
Beispiel: Mehrere Namespaces¶
package main
import (
"fmt"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
// Öffentlicher Chat-Namespace
publicChat := client.Of("/chat")
publicChat.OnConnect(func() {
fmt.Println("✅ Öffentlicher Chat verbunden")
})
publicChat.On("message", func(data ...interface{}) {
fmt.Printf("💬 [Öffentlich] %s: %s\n", data[0], data[1])
})
// Privater Chat-Namespace
privateChat := client.Of("/chat/private")
privateChat.OnConnect(func() {
fmt.Println("✅ Privater Chat verbunden")
})
privateChat.On("message", func(data ...interface{}) {
fmt.Printf("🔒 [Privat] %s: %s\n", data[0], data[1])
})
// Benachrichtigungs-Namespace
notifications := client.Of("/notifications")
notifications.OnConnect(func() {
fmt.Println("✅ Benachrichtigungen verbunden")
})
notifications.On("new", func(data ...interface{}) {
notif := data[0].(map[string]interface{})
fmt.Printf("🔔 Benachrichtigung: %s\n", notif["message"])
})
// Admin-Namespace (mit spezifischer Authentifizierung)
admin := client.Of("/admin")
admin.OnConnect(func() {
fmt.Println("✅ Admin verbunden")
admin.Emit("authenticate", map[string]interface{}{
"token": "admin-secret-token",
})
})
admin.On("stats", func(data ...interface{}) {
stats := data[0].(map[string]interface{})
fmt.Printf("📊 Statistik: %v verbundene Benutzer\n", stats["users"])
})
select {}
}
Beispiel: Namespace mit Acknowledgments¶
package main
import (
"fmt"
"time"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
api := client.Of("/api")
api.OnConnect(func() {
fmt.Println("✅ API-Namespace verbunden")
// Benutzerdaten abrufen
api.EmitWithAck("get-user", func(response ...interface{}) {
if response == nil {
fmt.Println("⏱️ Timeout beim Warten auf Benutzer")
return
}
user := response[0].(map[string]interface{})
fmt.Printf("👤 Benutzer: %s\n", user["name"])
}, "user-123")
// Ressource erstellen
api.EmitWithAck("create-post", func(response ...interface{}) {
if response == nil {
fmt.Println("⏱️ Timeout beim Erstellen des Beitrags")
return
}
result := response[0].(map[string]interface{})
if result["success"].(bool) {
fmt.Printf("✅ Beitrag erstellt mit ID: %v\n", result["id"])
} else {
fmt.Printf("❌ Fehler: %s\n", result["error"])
}
}, map[string]interface{}{
"title": "Mi primer post",
"content": "Contenido del post",
})
})
select {}
}
Beispiel: Namespace mit Binärdaten¶
package main
import (
"fmt"
"os"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
files := client.Of("/files")
files.OnConnect(func() {
fmt.Println("✅ Files-Namespace verbunden")
// Datei hochladen
uploadFile(files, "document.pdf")
})
files.On("upload-progress", func(data ...interface{}) {
progress := data[0].(map[string]interface{})
fmt.Printf("📤 Fortschritt: %.0f%%\n", progress["percent"])
})
files.On("upload-complete", func(data ...interface{}) {
result := data[0].(map[string]interface{})
fmt.Printf("✅ Datei hochgeladen: %s\n", result["url"])
})
files.On("file-received", func(data ...interface{}) {
binaryData := data[0].([]byte)
metadata := data[1].(map[string]interface{})
filename := metadata["filename"].(string)
fmt.Printf("📥 Datei empfangen: %s (%d Bytes)\n", filename, len(binaryData))
// Datei speichern
os.WriteFile(filename, binaryData, 0644)
})
select {}
}
func uploadFile(ns *socketio.Namespace, path string) {
data, err := os.ReadFile(path)
if err != nil {
fmt.Printf("Fehler beim Lesen der Datei: %v\n", err)
return
}
ns.EmitBinary("upload", data, map[string]interface{}{
"filename": path,
"size": len(data),
})
}
Beispiel: Fehlerbehandlung nach Namespace¶
package main
import (
"fmt"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
// Namespace, der spezielle Authentifizierung erfordern kann
admin := client.Of("/admin")
admin.OnConnect(func() {
fmt.Println("✅ Authentifizierung in /admin wird versucht")
admin.Emit("auth", map[string]interface{}{
"token": "admin-token",
})
})
admin.On("auth-success", func(data ...interface{}) {
fmt.Println("✅ Authentifizierung in /admin erfolgreich")
admin.Emit("get-stats")
})
admin.On("auth-failed", func(data ...interface{}) {
reason := data[0].(string)
fmt.Printf("❌ Authentifizierung fehlgeschlagen: %s\n", reason)
admin.Emit("disconnect") // Diesen Namespace trennen
})
admin.On("error", func(data ...interface{}) {
err := data[0].(string)
fmt.Printf("⚠️ Fehler in /admin: %s\n", err)
})
admin.OnDisconnect(func(reason string) {
fmt.Printf("❌ /admin getrennt: %s\n", reason)
})
select {}
}
Thread-Sicherheit¶
Alle Methoden von Namespace sind thread-sicher und können von mehreren Goroutinen aufgerufen werden.
chat := client.Of("/chat")
// Von mehreren Goroutinen senden
for i := 0; i < 10; i++ {
go func(id int) {
chat.Emit("worker-message", map[string]interface{}{
"worker": id,
"data": processData(id),
})
}(i)
}
Best Practices¶
1. Nach Funktionalität organisieren¶
// Namespaces nach Funktionalität trennen
chat := client.Of("/chat")
notifications := client.Of("/notifications")
admin := client.Of("/admin")
2. Verbindung vor dem Senden überprüfen¶
chat := client.Of("/chat")
if chat.IsConnected() {
chat.Emit("message", "Hallo")
} else {
fmt.Println("Chat nicht verbunden, Nachricht für später speichern")
queueMessage("Hallo")
}
3. Verbindungsereignisse behandeln¶
api := client.Of("/api")
api.OnConnect(func() {
// Bei Verbindung Ereignisse abonnieren
api.Emit("subscribe", []string{"users", "posts", "comments"})
})
api.OnDisconnect(func(reason string) {
// Status bei Trennung bereinigen
clearLocalCache()
})
4. Acknowledgments für kritische Operationen verwenden¶
api := client.Of("/api")
api.EmitWithAck("important-operation", func(response ...interface{}) {
if response == nil {
fmt.Println("Operation fehlgeschlagen (Timeout)")
retryOperation()
return
}
if response[0].(map[string]interface{})["success"].(bool) {
fmt.Println("Operation erfolgreich")
}
}, operationData)