Namespace API Reference¶
El tipo Namespace representa una conexión a un namespace específico en Socket.IO. Los namespaces permiten multiplexar múltiples conexiones sobre una única conexión WebSocket.
Tabla de Contenidos¶
- Concepto de Namespaces
- Obtención de Namespaces
- Métodos de Eventos
- Métodos de Emisión
- Métodos de Estado
- Ejemplos
Concepto de Namespaces¶
Los namespaces son canales de comunicación separados que comparten la misma conexión física. Permiten:
- Separación lógica: Diferentes áreas de tu aplicación pueden usar diferentes namespaces
- Eficiencia: Una sola conexión WebSocket maneja múltiples namespaces
- Seguridad: Puedes controlar acceso a namespaces específicos
Namespace por Defecto¶
El namespace por defecto es /. Cuando usas métodos directamente en Socket, estás usando este namespace:
// Estos dos códigos son equivalentes
client.On("event", handler)
client.Of("/").On("event", handler)
Obtención de Namespaces¶
Los namespaces se obtienen a través del método Of() de Socket:
// Obtener namespace personalizado
chat := client.Of("/chat")
admin := client.Of("/admin")
notifications := client.Of("/notifications")
Métodos de Eventos¶
On¶
Registra un handler para escuchar un evento específico en este namespace.
Parámetros: - event (string): Nombre del evento - handler (EventHandler): Función que se ejecuta cuando se recibe el evento
Ejemplo:
chat := client.Of("/chat")
chat.On("message", func(data ...interface{}) {
msg := data[0].(string)
fmt.Printf("Mensaje de chat: %s\n", msg)
})
chat.On("user-joined", func(data ...interface{}) {
user := data[0].(map[string]interface{})
fmt.Printf("%s se unió al chat\n", user["name"])
})
OnConnect¶
Registra un handler que se ejecuta cuando este namespace se conecta exitosamente.
Parámetros: - handler (func()): Función que se ejecuta al conectar
Ejemplo:
chat := client.Of("/chat")
chat.OnConnect(func() {
fmt.Println("Conectado al namespace /chat")
// Emitir evento inicial en este namespace
chat.Emit("join-room", "general")
})
OnDisconnect¶
Registra un handler que se ejecuta cuando este namespace se desconecta.
Parámetros: - handler (func(reason string)): Función que recibe la razón de la desconexión
Ejemplo:
chat := client.Of("/chat")
chat.OnDisconnect(func(reason string) {
fmt.Printf("Desconectado de /chat: %s\n", reason)
})
Métodos de Emisión¶
Emit¶
Emite un evento al servidor en este namespace.
Parámetros: - event (string): Nombre del evento - data (...interface{}): Argumentos a enviar
Retorna: - error: Error si la operación falla
Ejemplo:
chat := client.Of("/chat")
// Emitir mensaje simple
chat.Emit("message", "Hola a todos")
// Emitir datos estructurados
chat.Emit("action", map[string]interface{}{
"type": "typing",
"user": "juan",
})
// Múltiples argumentos
chat.Emit("chat-message", "juan", "Hola", time.Now().Unix())
EmitWithAck¶
Emite un evento y espera una respuesta (acknowledgment) del servidor en este namespace.
Parámetros: - event (string): Nombre del evento - ack (AckCallback): Función callback que recibe la respuesta - data (...interface{}): Argumentos a enviar
Retorna: - error: Error si la operación falla
Ejemplo:
chat := client.Of("/chat")
chat.EmitWithAck("get-history", func(response ...interface{}) {
if response == nil {
fmt.Println("Timeout esperando historial")
return
}
history := response[0].([]interface{})
fmt.Printf("Historial recibido: %d mensajes\n", len(history))
}, "sala-general")
EmitBinary¶
Emite un evento con datos binarios en este namespace.
Parámetros: - event (string): Nombre del evento - binaryData ([]byte): Datos binarios a enviar - data (...interface{}): Argumentos adicionales (opcionales)
Retorna: - error: Error si la operación falla
Ejemplo:
chat := client.Of("/chat")
// Leer imagen
imageData, err := os.ReadFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Enviar imagen con metadata
chat.EmitBinary("image", imageData, map[string]interface{}{
"filename": "photo.jpg",
"from": "usuario123",
"size": len(imageData),
})
Métodos de Estado¶
IsConnected¶
Retorna si este namespace está actualmente conectado.
Retorna: - bool: true si está conectado, false en caso contrario
Ejemplo:
chat := client.Of("/chat")
if chat.IsConnected() {
chat.Emit("ping")
} else {
fmt.Println("Chat namespace no está conectado")
}
GetPath¶
Retorna el path de este namespace.
Retorna: - string: Path del namespace (ej: /chat, /admin)
Ejemplo:
Ejemplos¶
Ejemplo Básico: Chat Application¶
package main
import (
"fmt"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
// Namespace de chat
chat := client.Of("/chat")
chat.OnConnect(func() {
fmt.Println("✅ Conectado al chat")
// Unirse a una sala
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 se unió al chat\n", username)
})
chat.On("user-left", func(data ...interface{}) {
username := data[0].(string)
fmt.Printf("👋 %s salió del chat\n", username)
})
// Enviar mensaje
chat.Emit("message", "juan", "Hola a todos!")
select {}
}
Ejemplo: Múltiples Namespaces¶
package main
import (
"fmt"
socketio "github.com/arcaela/socket.io-client-go"
)
func main() {
client := socketio.New("ws://localhost:3000")
defer client.Close()
// Namespace de chat público
publicChat := client.Of("/chat")
publicChat.OnConnect(func() {
fmt.Println("✅ Chat público conectado")
})
publicChat.On("message", func(data ...interface{}) {
fmt.Printf("💬 [Público] %s: %s\n", data[0], data[1])
})
// Namespace de chat privado
privateChat := client.Of("/chat/private")
privateChat.OnConnect(func() {
fmt.Println("✅ Chat privado conectado")
})
privateChat.On("message", func(data ...interface{}) {
fmt.Printf("🔒 [Privado] %s: %s\n", data[0], data[1])
})
// Namespace de notificaciones
notifications := client.Of("/notifications")
notifications.OnConnect(func() {
fmt.Println("✅ Notificaciones conectadas")
})
notifications.On("new", func(data ...interface{}) {
notif := data[0].(map[string]interface{})
fmt.Printf("🔔 Notificación: %s\n", notif["message"])
})
// Namespace de admin (con autenticación específica)
admin := client.Of("/admin")
admin.OnConnect(func() {
fmt.Println("✅ Admin conectado")
admin.Emit("authenticate", map[string]interface{}{
"token": "admin-secret-token",
})
})
admin.On("stats", func(data ...interface{}) {
stats := data[0].(map[string]interface{})
fmt.Printf("📊 Stats: %v usuarios conectados\n", stats["users"])
})
select {}
}
Ejemplo: Namespace con 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 conectado")
// Obtener datos de usuario
api.EmitWithAck("get-user", func(response ...interface{}) {
if response == nil {
fmt.Println("⏱️ Timeout esperando usuario")
return
}
user := response[0].(map[string]interface{})
fmt.Printf("👤 Usuario: %s\n", user["name"])
}, "user-123")
// Crear recurso
api.EmitWithAck("create-post", func(response ...interface{}) {
if response == nil {
fmt.Println("⏱️ Timeout creando post")
return
}
result := response[0].(map[string]interface{})
if result["success"].(bool) {
fmt.Printf("✅ Post creado con ID: %v\n", result["id"])
} else {
fmt.Printf("❌ Error: %s\n", result["error"])
}
}, map[string]interface{}{
"title": "Mi primer post",
"content": "Contenido del post",
})
})
select {}
}
Ejemplo: Namespace con Datos Binarios¶
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 conectado")
// Subir archivo
uploadFile(files, "document.pdf")
})
files.On("upload-progress", func(data ...interface{}) {
progress := data[0].(map[string]interface{})
fmt.Printf("📤 Progreso: %.0f%%\n", progress["percent"])
})
files.On("upload-complete", func(data ...interface{}) {
result := data[0].(map[string]interface{})
fmt.Printf("✅ Archivo subido: %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("📥 Archivo recibido: %s (%d bytes)\n", filename, len(binaryData))
// Guardar archivo
os.WriteFile(filename, binaryData, 0644)
})
select {}
}
func uploadFile(ns *socketio.Namespace, path string) {
data, err := os.ReadFile(path)
if err != nil {
fmt.Printf("Error leyendo archivo: %v\n", err)
return
}
ns.EmitBinary("upload", data, map[string]interface{}{
"filename": path,
"size": len(data),
})
}
Ejemplo: Manejo de Errores por 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 que puede requerir autenticación especial
admin := client.Of("/admin")
admin.OnConnect(func() {
fmt.Println("✅ Intentando autenticar en /admin")
admin.Emit("auth", map[string]interface{}{
"token": "admin-token",
})
})
admin.On("auth-success", func(data ...interface{}) {
fmt.Println("✅ Autenticación exitosa en /admin")
admin.Emit("get-stats")
})
admin.On("auth-failed", func(data ...interface{}) {
reason := data[0].(string)
fmt.Printf("❌ Autenticación fallida: %s\n", reason)
admin.Emit("disconnect") // Desconectar este namespace
})
admin.On("error", func(data ...interface{}) {
err := data[0].(string)
fmt.Printf("⚠️ Error en /admin: %s\n", err)
})
admin.OnDisconnect(func(reason string) {
fmt.Printf("❌ /admin desconectado: %s\n", reason)
})
select {}
}
Thread-Safety¶
Todos los métodos de Namespace son thread-safe y pueden ser llamados desde múltiples goroutines.
chat := client.Of("/chat")
// Emitir desde múltiples goroutines
for i := 0; i < 10; i++ {
go func(id int) {
chat.Emit("worker-message", map[string]interface{}{
"worker": id,
"data": processData(id),
})
}(i)
}
Mejores Prácticas¶
1. Organizar por Funcionalidad¶
// Separar namespaces por funcionalidad
chat := client.Of("/chat")
notifications := client.Of("/notifications")
admin := client.Of("/admin")
2. Verificar Conexión Antes de Emitir¶
chat := client.Of("/chat")
if chat.IsConnected() {
chat.Emit("message", "Hola")
} else {
fmt.Println("Chat no conectado, guardando mensaje para después")
queueMessage("Hola")
}
3. Manejar Eventos de Conexión¶
api := client.Of("/api")
api.OnConnect(func() {
// Suscribirse a eventos cuando se conecta
api.Emit("subscribe", []string{"users", "posts", "comments"})
})
api.OnDisconnect(func(reason string) {
// Limpiar estado cuando se desconecta
clearLocalCache()
})
4. Usar Acknowledgments para Operaciones Críticas¶
api := client.Of("/api")
api.EmitWithAck("important-operation", func(response ...interface{}) {
if response == nil {
fmt.Println("Operación falló (timeout)")
retryOperation()
return
}
if response[0].(map[string]interface{})["success"].(bool) {
fmt.Println("Operación exitosa")
}
}, operationData)