210 lines
5.4 KiB
Go
210 lines
5.4 KiB
Go
package managed
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type Manager struct {
|
|
registry *Registry
|
|
docker DockerRuntime
|
|
remote *RemoteClient
|
|
}
|
|
|
|
type ServiceState struct {
|
|
ID string `json:"id"`
|
|
DisplayName string `json:"display_name"`
|
|
ProjectType string `json:"project_type"`
|
|
ProjectRoot string `json:"project_root"`
|
|
ContainerName string `json:"container_name"`
|
|
APIBaseURL string `json:"api_base_url"`
|
|
ServiceName string `json:"service_name"`
|
|
ConfigPath string `json:"config_path"`
|
|
RTSPField string `json:"rtsp_field"`
|
|
ResultType string `json:"result_type"`
|
|
ResultPaths map[string]string `json:"result_paths"`
|
|
Status string `json:"status"`
|
|
RTSP string `json:"rtsp,omitempty"`
|
|
Summary *ResultSummary `json:"summary,omitempty"`
|
|
ResultFiles []ResultFile `json:"result_files,omitempty"`
|
|
ConfigError string `json:"config_error,omitempty"`
|
|
ResultError string `json:"result_error,omitempty"`
|
|
ServiceError string `json:"service_error,omitempty"`
|
|
}
|
|
|
|
func NewManager(registry *Registry, docker DockerRuntime, remote *RemoteClient) *Manager {
|
|
if registry == nil {
|
|
registry = EmptyRegistry()
|
|
}
|
|
if docker == nil {
|
|
docker = NewDockerController()
|
|
}
|
|
if remote == nil {
|
|
remote = NewRemoteClient(nil)
|
|
}
|
|
return &Manager{
|
|
registry: registry,
|
|
docker: docker,
|
|
remote: remote,
|
|
}
|
|
}
|
|
|
|
func (m *Manager) List() []*ServiceState {
|
|
states := make([]*ServiceState, 0, len(m.registry.Services))
|
|
for _, service := range m.registry.Services {
|
|
states = append(states, m.snapshot(service, false))
|
|
}
|
|
return states
|
|
}
|
|
|
|
func (m *Manager) Detail(id string) (*ServiceState, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.snapshot(service, true), nil
|
|
}
|
|
|
|
func (m *Manager) Summary(id string) (*ResultSummary, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.remote.GetSummary(context.Background(), service)
|
|
}
|
|
|
|
func (m *Manager) Files(id string) ([]ResultFile, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.remote.GetFiles(context.Background(), service)
|
|
}
|
|
|
|
func (m *Manager) PreviewFile(id, path string, lines int) (*FilePreview, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.remote.PreviewFile(context.Background(), service, path, lines)
|
|
}
|
|
|
|
func (m *Manager) Download(ctx context.Context, id, path string) (*http.Response, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.remote.Download(ctx, service, path)
|
|
}
|
|
|
|
func (m *Manager) UpdateRTSP(id, rtsp string) (*ServiceState, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if strings.TrimSpace(rtsp) == "" {
|
|
return nil, fmt.Errorf("rtsp url is required")
|
|
}
|
|
if _, err := m.remote.UpdateRTSP(context.Background(), service, rtsp); err != nil {
|
|
return nil, err
|
|
}
|
|
return m.snapshot(service, true), nil
|
|
}
|
|
|
|
func (m *Manager) Restart(id string) (*ServiceState, error) {
|
|
service, err := m.lookup(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := m.docker.RestartContainer(service.ContainerName); err != nil {
|
|
return nil, err
|
|
}
|
|
return m.snapshot(service, true), nil
|
|
}
|
|
|
|
func (m *Manager) lookup(id string) (Service, error) {
|
|
service, ok := m.registry.Get(id)
|
|
if !ok {
|
|
return Service{}, fmt.Errorf("%w: %s", ErrServiceNotFound, id)
|
|
}
|
|
return service, nil
|
|
}
|
|
|
|
func (m *Manager) snapshot(service Service, includeFiles bool) *ServiceState {
|
|
state := &ServiceState{
|
|
ID: service.ID,
|
|
DisplayName: service.DisplayName,
|
|
ProjectType: service.ProjectType,
|
|
ProjectRoot: service.ProjectRoot,
|
|
ContainerName: service.ContainerName,
|
|
APIBaseURL: service.APIBaseURL,
|
|
ServiceName: service.ServiceName,
|
|
ConfigPath: service.ConfigPath,
|
|
RTSPField: service.RTSPField,
|
|
ResultType: service.ResultType,
|
|
ResultPaths: service.ResultPaths,
|
|
Status: "unknown",
|
|
}
|
|
|
|
if payload, err := m.remote.GetConfig(context.Background(), service); err == nil {
|
|
state.RTSP = extractRTSP(payload)
|
|
state.ConfigPath = extractConfigPath(payload)
|
|
} else {
|
|
state.ConfigError = err.Error()
|
|
}
|
|
|
|
if status, err := m.docker.GetContainerStatus(service.ContainerName); err == nil {
|
|
state.Status = status
|
|
} else {
|
|
state.Status = status
|
|
if !IsDockerUnavailable(err) {
|
|
state.ServiceError = err.Error()
|
|
}
|
|
}
|
|
|
|
if summary, err := m.remote.GetSummary(context.Background(), service); err == nil {
|
|
state.Summary = summary
|
|
} else {
|
|
state.ResultError = err.Error()
|
|
}
|
|
|
|
if includeFiles {
|
|
if files, err := m.remote.GetFiles(context.Background(), service); err == nil {
|
|
state.ResultFiles = files
|
|
} else if state.ResultError == "" {
|
|
state.ResultError = err.Error()
|
|
}
|
|
}
|
|
|
|
return state
|
|
}
|
|
|
|
func extractRTSP(payload map[string]any) string {
|
|
if payload == nil {
|
|
return ""
|
|
}
|
|
if stream, ok := payload["stream"].(map[string]any); ok {
|
|
if rtsp, ok := stream["rtsp_url"].(string); ok {
|
|
return strings.TrimSpace(rtsp)
|
|
}
|
|
}
|
|
if runtime, ok := payload["runtime"].(map[string]any); ok {
|
|
if rtsp, ok := runtime["rtsp_url"].(string); ok {
|
|
return strings.TrimSpace(rtsp)
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func extractConfigPath(payload map[string]any) string {
|
|
if payload == nil {
|
|
return ""
|
|
}
|
|
if configPath, ok := payload["config_path"].(string); ok {
|
|
return strings.TrimSpace(configPath)
|
|
}
|
|
return ""
|
|
}
|