Files
kandev/apps/backend/internal/agent/settings/controller/agent_install.go
T
2026-07-27 12:21:47 +01:00

66 lines
2.2 KiB
Go

package controller
import (
"errors"
"strings"
"github.com/kandev/kandev/internal/agent/settings/dto"
)
// ErrInstallScriptEmpty is returned when the agent has no install script defined.
var ErrInstallScriptEmpty = errors.New("agent has no install script")
// ErrJobStoreUnavailable is returned when SetJobBroadcaster hasn't been called
// — i.e. handlers haven't registered yet, so there's no WS hub to stream to.
var ErrJobStoreUnavailable = errors.New("install job store unavailable")
// EnqueueInstall starts (or returns the existing) async install job for the
// named agent. The script is hard-coded by the agent type, so no user input is
// ever shelled. Clients subscribe to WS notifications (agent.install.started,
// agent.install.output, agent.install.finished) for live progress, or poll
// /agent-install/jobs/:id for a snapshot.
func (c *Controller) EnqueueInstall(name string) (*dto.InstallJobDTO, error) {
if c.jobStore == nil {
return nil, ErrJobStoreUnavailable
}
ag, ok := c.agentRegistry.Get(name)
if !ok {
return nil, ErrAgentNotFound
}
script := strings.TrimSpace(ag.InstallScript())
if script == "" {
return nil, ErrInstallScriptEmpty
}
job, err := c.jobStore.Enqueue(name, script)
if err != nil {
return nil, err
}
// Get() takes the store mutex, so it's race-free; calling job.snapshot()
// directly here would read job.Status without the lock while the spawned
// goroutine may be writing it.
if snap, ok := c.jobStore.Get(job.ID); ok {
return snap, nil
}
// Job was evicted between Enqueue and Get (extremely unlikely with the
// configured retention window). Fall back to the unguarded snapshot.
snap := job.snapshot()
return &snap, nil
}
// ListInstallJobs returns a snapshot of every active or recently-finished
// install job. Used by the UI on page mount to recover in-flight installs.
func (c *Controller) ListInstallJobs() []dto.InstallJobDTO {
if c.jobStore == nil {
return nil
}
return c.jobStore.ListAll()
}
// GetInstallJob returns a snapshot of one job by ID, or nil if not found.
func (c *Controller) GetInstallJob(id string) (*dto.InstallJobDTO, bool) {
if c.jobStore == nil {
return nil, false
}
return c.jobStore.Get(id)
}