Files
langship.sh/pkg/api/runs_bus.go
T
patel-lyzr 6b1a13ecdc feat: implement environment management features
- Added environment creation and editing pages with forms for name and description.
- Integrated environment listing with options to edit and delete environments.
- Updated agent detail page to manage environments followed by agents.
- Enhanced API to support environment operations including listing, creating, updating, and deleting environments.
- Refactored related components and state management for improved clarity and functionality.
2026-05-13 22:15:08 +05:30

73 lines
2.0 KiB
Go

package api
import (
"encoding/json"
"sync"
"time"
)
// RunCreatedEvent is the payload broadcast on /api/runs/stream whenever a
// new run is dispatched (manual API call or GitHub webhook).
type RunCreatedEvent struct {
Type string `json:"type"` // "run_created"
ExecutionID string `json:"executionId"`
PipelineID string `json:"pipelineId,omitempty"`
PipelineName string `json:"pipelineName,omitempty"`
AgentID string `json:"agentId,omitempty"`
Environment string `json:"environment,omitempty"`
Source string `json:"source,omitempty"` // "manual" | "github_push"
StartedAt time.Time `json:"startedAt"`
}
// runsBus is a tiny broadcast bus for cross-execution UI events. The SSE
// stream handler subscribes; dispatchers publish. All in-memory; one bus
// per process.
type runsBus struct {
mu sync.RWMutex
subscribers map[chan RunCreatedEvent]struct{}
}
func newRunsBus() *runsBus {
return &runsBus{subscribers: map[chan RunCreatedEvent]struct{}{}}
}
// Publish fans an event out to every active subscriber. Non-blocking — slow
// subscribers drop the event so dispatchers never stall.
func (b *runsBus) Publish(ev RunCreatedEvent) {
b.mu.RLock()
subs := make([]chan RunCreatedEvent, 0, len(b.subscribers))
for c := range b.subscribers {
subs = append(subs, c)
}
b.mu.RUnlock()
for _, c := range subs {
select {
case c <- ev:
default:
}
}
}
// Subscribe registers a buffered channel and returns it + an unsubscribe
// func that closes the channel exactly once.
func (b *runsBus) Subscribe() (<-chan RunCreatedEvent, func()) {
ch := make(chan RunCreatedEvent, 16)
b.mu.Lock()
b.subscribers[ch] = struct{}{}
b.mu.Unlock()
var once sync.Once
cancel := func() {
once.Do(func() {
b.mu.Lock()
delete(b.subscribers, ch)
b.mu.Unlock()
close(ch)
})
}
return ch, cancel
}
// marshal is a small helper so handlers don't import encoding/json just for
// the event payload format.
func (e RunCreatedEvent) marshal() ([]byte, error) { return json.Marshal(e) }