66 lines
2.2 KiB
Go
66 lines
2.2 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// AgentEndpoint is deployment-only Dispatcher configuration. It is not a SaaS
|
|
// command field and cannot be supplied by a tenant or a call task.
|
|
type AgentEndpoint struct {
|
|
AgentID string `json:"agent_id"`
|
|
CellID string `json:"cell_id"`
|
|
Address string `json:"address"`
|
|
ServerName string `json:"server_name"`
|
|
}
|
|
|
|
// LoadAgentEndpoints reads the Dispatcher-owned endpoint inventory. Strict JSON
|
|
// decoding prevents silently accepting misspelled authorization or identity
|
|
// fields.
|
|
func LoadAgentEndpoints(path string) ([]AgentEndpoint, error) {
|
|
if strings.TrimSpace(path) == "" {
|
|
return nil, nil
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read Agent endpoint inventory: %w", err)
|
|
}
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
decoder.DisallowUnknownFields()
|
|
var endpoints []AgentEndpoint
|
|
if err := decoder.Decode(&endpoints); err != nil {
|
|
return nil, fmt.Errorf("decode Agent endpoint inventory: %w", err)
|
|
}
|
|
var trailing any
|
|
if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) {
|
|
if err == nil {
|
|
return nil, errors.New("Agent endpoint inventory contains trailing JSON")
|
|
}
|
|
return nil, fmt.Errorf("read Agent endpoint inventory trailer: %w", err)
|
|
}
|
|
if len(endpoints) == 0 {
|
|
return nil, errors.New("Agent endpoint inventory must not be empty")
|
|
}
|
|
seenAgents := make(map[string]struct{}, len(endpoints))
|
|
seenCells := make(map[string]struct{}, len(endpoints))
|
|
for index, endpoint := range endpoints {
|
|
if strings.TrimSpace(endpoint.AgentID) == "" || strings.TrimSpace(endpoint.CellID) == "" || strings.TrimSpace(endpoint.Address) == "" || strings.TrimSpace(endpoint.ServerName) == "" {
|
|
return nil, fmt.Errorf("Agent endpoint %d requires agent_id, cell_id, address, and server_name", index)
|
|
}
|
|
if _, exists := seenAgents[endpoint.AgentID]; exists {
|
|
return nil, fmt.Errorf("duplicate Agent ID %q", endpoint.AgentID)
|
|
}
|
|
if _, exists := seenCells[endpoint.CellID]; exists {
|
|
return nil, fmt.Errorf("duplicate Cell ID %q", endpoint.CellID)
|
|
}
|
|
seenAgents[endpoint.AgentID] = struct{}{}
|
|
seenCells[endpoint.CellID] = struct{}{}
|
|
}
|
|
return endpoints, nil
|
|
}
|