feat: initialize managed portal
This commit is contained in:
134
internal/managed/registry.go
Normal file
134
internal/managed/registry.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package managed
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var ErrServiceNotFound = errors.New("managed service not found")
|
||||
|
||||
type Registry struct {
|
||||
Services []Service `yaml:"services"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
ID string `yaml:"id" json:"id"`
|
||||
DisplayName string `yaml:"display_name" json:"display_name"`
|
||||
ProjectType string `yaml:"project_type" json:"project_type"`
|
||||
ProjectRoot string `yaml:"project_root" json:"project_root"`
|
||||
ContainerName string `yaml:"container_name" json:"container_name"`
|
||||
APIBaseURL string `yaml:"api_base_url" json:"api_base_url"`
|
||||
ServiceName string `yaml:"service_name" json:"service_name"`
|
||||
ConfigPath string `yaml:"config_path" json:"config_path"`
|
||||
RTSPField string `yaml:"rtsp_field" json:"rtsp_field"`
|
||||
ResultType string `yaml:"result_type" json:"result_type"`
|
||||
ResultPaths map[string]string `yaml:"result_paths" json:"result_paths"`
|
||||
}
|
||||
|
||||
func EmptyRegistry() *Registry {
|
||||
return &Registry{Services: []Service{}}
|
||||
}
|
||||
|
||||
func LoadRegistry(path string) (*Registry, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read managed registry: %w", err)
|
||||
}
|
||||
|
||||
var registry Registry
|
||||
if err := yaml.Unmarshal(data, ®istry); err != nil {
|
||||
return nil, fmt.Errorf("parse managed registry: %w", err)
|
||||
}
|
||||
|
||||
baseDir := filepath.Dir(path)
|
||||
ids := make(map[string]struct{}, len(registry.Services))
|
||||
for i := range registry.Services {
|
||||
svc := ®istry.Services[i]
|
||||
if err := normalizeService(baseDir, svc); err != nil {
|
||||
return nil, fmt.Errorf("service[%d]: %w", i, err)
|
||||
}
|
||||
if _, exists := ids[svc.ID]; exists {
|
||||
return nil, fmt.Errorf("duplicate service id %q", svc.ID)
|
||||
}
|
||||
ids[svc.ID] = struct{}{}
|
||||
}
|
||||
|
||||
if registry.Services == nil {
|
||||
registry.Services = []Service{}
|
||||
}
|
||||
|
||||
return ®istry, nil
|
||||
}
|
||||
|
||||
func (r *Registry) Get(id string) (Service, bool) {
|
||||
for _, svc := range r.Services {
|
||||
if svc.ID == id {
|
||||
return svc, true
|
||||
}
|
||||
}
|
||||
return Service{}, false
|
||||
}
|
||||
|
||||
func normalizeService(baseDir string, svc *Service) error {
|
||||
svc.ID = strings.TrimSpace(svc.ID)
|
||||
svc.DisplayName = strings.TrimSpace(svc.DisplayName)
|
||||
svc.ProjectType = strings.TrimSpace(svc.ProjectType)
|
||||
svc.ContainerName = strings.TrimSpace(svc.ContainerName)
|
||||
svc.APIBaseURL = strings.TrimSpace(svc.APIBaseURL)
|
||||
svc.ServiceName = strings.TrimSpace(svc.ServiceName)
|
||||
svc.ConfigPath = strings.TrimSpace(svc.ConfigPath)
|
||||
svc.RTSPField = strings.TrimSpace(svc.RTSPField)
|
||||
svc.ResultType = strings.TrimSpace(svc.ResultType)
|
||||
|
||||
if svc.ID == "" {
|
||||
return errors.New("id is required")
|
||||
}
|
||||
if svc.DisplayName == "" {
|
||||
return errors.New("display_name is required")
|
||||
}
|
||||
if svc.ProjectType == "" {
|
||||
return errors.New("project_type is required")
|
||||
}
|
||||
if svc.ContainerName == "" {
|
||||
return errors.New("container_name is required")
|
||||
}
|
||||
if svc.APIBaseURL == "" {
|
||||
return errors.New("api_base_url is required")
|
||||
}
|
||||
if svc.ResultType == "" {
|
||||
return errors.New("result_type is required")
|
||||
}
|
||||
|
||||
projectRoot := strings.TrimSpace(svc.ProjectRoot)
|
||||
if projectRoot == "" {
|
||||
return errors.New("project_root is required")
|
||||
}
|
||||
svc.ProjectRoot = resolvePath(baseDir, projectRoot)
|
||||
if svc.ServiceName == "" {
|
||||
svc.ServiceName = svc.ContainerName
|
||||
}
|
||||
if svc.ConfigPath != "" {
|
||||
svc.ConfigPath = resolvePath(baseDir, svc.ConfigPath)
|
||||
}
|
||||
|
||||
if svc.ResultPaths == nil {
|
||||
svc.ResultPaths = map[string]string{}
|
||||
}
|
||||
for key, path := range svc.ResultPaths {
|
||||
svc.ResultPaths[key] = resolvePath(baseDir, strings.TrimSpace(path))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolvePath(baseDir, path string) string {
|
||||
if filepath.IsAbs(path) {
|
||||
return filepath.Clean(path)
|
||||
}
|
||||
return filepath.Clean(filepath.Join(baseDir, path))
|
||||
}
|
||||
Reference in New Issue
Block a user