76ba500417
CI / docker (push) Successful in 2m4s
OpenAI-compatible AI gateway with Vue admin UI, multi-provider egress, ingress key governance, monitoring, and security controls. Co-authored-by: Cursor <cursoragent@cursor.com>
58 lines
1.1 KiB
Go
58 lines
1.1 KiB
Go
package prediction
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
type Event struct {
|
|
Status string `json:"status"`
|
|
Logs string `json:"logs,omitempty"`
|
|
Metrics map[string]any `json:"metrics,omitempty"`
|
|
Output any `json:"output,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
Done bool `json:"-"`
|
|
}
|
|
|
|
type Hub struct {
|
|
mu sync.RWMutex
|
|
subs map[string]map[chan Event]struct{}
|
|
}
|
|
|
|
func NewHub() *Hub {
|
|
return &Hub{subs: make(map[string]map[chan Event]struct{})}
|
|
}
|
|
|
|
func (h *Hub) Subscribe(predictionID string) chan Event {
|
|
ch := make(chan Event, 16)
|
|
h.mu.Lock()
|
|
if h.subs[predictionID] == nil {
|
|
h.subs[predictionID] = make(map[chan Event]struct{})
|
|
}
|
|
h.subs[predictionID][ch] = struct{}{}
|
|
h.mu.Unlock()
|
|
return ch
|
|
}
|
|
|
|
func (h *Hub) Unsubscribe(predictionID string, ch chan Event) {
|
|
h.mu.Lock()
|
|
if m := h.subs[predictionID]; m != nil {
|
|
delete(m, ch)
|
|
if len(m) == 0 {
|
|
delete(h.subs, predictionID)
|
|
}
|
|
}
|
|
h.mu.Unlock()
|
|
close(ch)
|
|
}
|
|
|
|
func (h *Hub) Publish(predictionID string, ev Event) {
|
|
h.mu.RLock()
|
|
defer h.mu.RUnlock()
|
|
for ch := range h.subs[predictionID] {
|
|
select {
|
|
case ch <- ev:
|
|
default:
|
|
}
|
|
}
|
|
}
|