Files
viettranx 21b6c454ca feat: merge pipeline, per-user credentials, unified picker, group contacts
- Enable merge UI for linking channel contacts to tenant_users
- Contact → tenant_user resolution with cached lookup (60s TTL)
- MCP per-user credentials via user-keyed connection pool
- Secure CLI per-user credentials with AES-256-GCM encryption
- Unified UserPickerCombobox searching contacts + tenant_users
- Group contact collection with chat title in all channels
- Group permission inheritance via wildcard user_id="*"
- Fix heartbeat using wrong userID in group chats
- Filter internal senders from contact collection
- Add contact_type column (user/group) to channel_contacts
- SQLite schema v2 migration for desktop edition
2026-03-29 22:33:17 +07:00

43 lines
1.3 KiB
Go

package http
import (
"encoding/json"
"fmt"
"net/http"
)
// ProgressEvent describes a single SSE progress update for long-running operations.
// Used by export, import, and any future streaming endpoints.
type ProgressEvent struct {
Phase string `json:"phase"`
Status string `json:"status"` // "running", "done", "error"
Detail string `json:"detail,omitempty"`
Current int `json:"current,omitempty"`
Total int `json:"total,omitempty"`
}
// sendSSE writes a named SSE event with JSON payload and flushes.
// The event format follows the standard SSE spec: "event: <name>\ndata: <json>\n\n".
func sendSSE(w http.ResponseWriter, flusher http.Flusher, event string, data any) {
jsonData, err := json.Marshal(data)
if err != nil {
return
}
fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event, jsonData)
flusher.Flush()
}
// initSSE sets standard headers for an SSE response and writes the 200 status.
// Returns the Flusher or nil if streaming is not supported.
func initSSE(w http.ResponseWriter) http.Flusher {
flusher, ok := w.(http.Flusher)
if !ok {
return nil
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.WriteHeader(http.StatusOK)
return flusher
}