161 lines
5.3 KiB
Go
161 lines
5.3 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"supply-intelligence/internal/admission"
|
|
"supply-intelligence/internal/discovery"
|
|
"supply-intelligence/internal/domain"
|
|
"supply-intelligence/internal/gatewayconsumer"
|
|
"supply-intelligence/internal/httpapi"
|
|
"supply-intelligence/internal/poller"
|
|
"supply-intelligence/internal/probe"
|
|
"supply-intelligence/internal/publish"
|
|
"supply-intelligence/internal/repository"
|
|
)
|
|
|
|
type Application struct {
|
|
Repo *repository.MemoryRepository
|
|
ProbeService *probe.Service
|
|
PublishService *publish.Service
|
|
DiscoveryService *discovery.Service
|
|
GatewayConsumerService *gatewayconsumer.Service
|
|
GatewayPoller *poller.GatewayPackagePoller
|
|
GatewayRuntime *poller.Runtime
|
|
AdmissionService *admission.Service
|
|
Server *httpapi.Server
|
|
}
|
|
|
|
func New() *Application {
|
|
repo := repository.NewMemoryRepository()
|
|
probeService := probe.NewService(repo)
|
|
publishService := publish.NewService(repo)
|
|
discoveryService := discovery.NewService(repo)
|
|
gatewayConsumerService := gatewayconsumer.NewService(repo)
|
|
gatewayPoller := poller.NewGatewayPackagePoller(gatewayConsumerService)
|
|
gatewayRuntime := poller.NewRuntime(gatewayPoller, time.Second)
|
|
|
|
// Wire MemoryRepository as admission's CandidateRepository
|
|
candidateRepo := &admissionMemoryRepoAdapter{repo: repo}
|
|
packageRepo := &admissionSupplyPackageAdapter{repo: repo}
|
|
runner := admission.NewHTTPTestRunner()
|
|
|
|
// Build test suites for known platforms (in real use, loaded from config)
|
|
suites := []admission.TestSuite{
|
|
admission.BuildTestSuiteForPlatform("openai", "https://api.openai.com", ""),
|
|
admission.BuildTestSuiteForPlatform("anthropic", "https://api.anthropic.com", ""),
|
|
}
|
|
|
|
admissionService := admission.NewService(candidateRepo, packageRepo, suites, runner)
|
|
|
|
return &Application{
|
|
Repo: repo,
|
|
ProbeService: probeService,
|
|
PublishService: publishService,
|
|
DiscoveryService: discoveryService,
|
|
GatewayConsumerService: gatewayConsumerService,
|
|
GatewayPoller: gatewayPoller,
|
|
GatewayRuntime: gatewayRuntime,
|
|
AdmissionService: admissionService,
|
|
Server: httpapi.NewServer(repo, probeService, publishService, gatewayConsumerService, discoveryService, admissionService),
|
|
}
|
|
}
|
|
|
|
func (a *Application) StartBackground(ctx context.Context) {
|
|
if a == nil || a.GatewayRuntime == nil {
|
|
return
|
|
}
|
|
a.GatewayRuntime.Start(ctx)
|
|
}
|
|
|
|
func (a *Application) StopBackground() {
|
|
if a == nil || a.GatewayRuntime == nil {
|
|
return
|
|
}
|
|
a.GatewayRuntime.Stop()
|
|
}
|
|
|
|
func (a *Application) IsInMemoryGatewayState() bool {
|
|
return a != nil && a.Repo != nil
|
|
}
|
|
|
|
// --- Adapters that bridge MemoryRepository to admission.Repository interfaces ---
|
|
|
|
// admissionMemoryRepoAdapter adapts MemoryRepository to admission.CandidateRepository
|
|
type admissionMemoryRepoAdapter struct {
|
|
repo *repository.MemoryRepository
|
|
}
|
|
|
|
func (a *admissionMemoryRepoAdapter) GetCandidateByIDContext(ctx context.Context, candidateID string) (admission.Candidate, bool) {
|
|
c, ok := a.repo.GetDiscoveryCandidateByIDContext(ctx, candidateID)
|
|
if !ok {
|
|
return admission.Candidate{}, false
|
|
}
|
|
return toAdmissionCandidate(c), true
|
|
}
|
|
|
|
func (a *admissionMemoryRepoAdapter) UpdateCandidateStatus(ctx context.Context, candidateID string, status admission.CandidateStatus, failureCode, failureSummary string) error {
|
|
return a.repo.UpdateCandidateStatus(ctx, candidateID, domain.DiscoveryCandidateStatus(status), failureCode, failureSummary)
|
|
}
|
|
|
|
func (a *admissionMemoryRepoAdapter) ListCandidatesByStatus(ctx context.Context, status admission.CandidateStatus) []admission.Candidate {
|
|
candidates := a.repo.ListDiscoveryCandidatesContext(ctx, domain.DiscoveryCandidateStatus(status))
|
|
result := make([]admission.Candidate, len(candidates))
|
|
for i, c := range candidates {
|
|
result[i] = toAdmissionCandidate(c)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func toAdmissionCandidate(c domain.DiscoveryCandidate) admission.Candidate {
|
|
return admission.Candidate{
|
|
CandidateID: c.CandidateID,
|
|
AccountID: c.AccountID,
|
|
Platform: c.Platform,
|
|
Model: c.Model,
|
|
Status: admission.CandidateStatus(c.Status),
|
|
Source: c.Source,
|
|
ReasonCode: c.ReasonCode,
|
|
DiscoveredAt: c.DiscoveredAt,
|
|
UpdatedAt: c.UpdatedAt,
|
|
Version: c.Version,
|
|
}
|
|
}
|
|
|
|
// admissionSupplyPackageAdapter adapts MemoryRepository to admission.SupplyPackageRepository
|
|
type admissionSupplyPackageAdapter struct {
|
|
repo *repository.MemoryRepository
|
|
}
|
|
|
|
func (a *admissionSupplyPackageAdapter) UpsertDraftPackage(ctx context.Context, platform, model, source string) (int64, error) {
|
|
if existing, ok := a.repo.GetSupplyPackage(platform, model); ok {
|
|
return existing.PackageID, nil
|
|
}
|
|
pkg := domain.SupplyPackage{
|
|
Platform: platform,
|
|
Model: model,
|
|
Status: "draft",
|
|
Source: source,
|
|
}
|
|
a.repo.UpsertSupplyPackage(pkg)
|
|
if newPkg, ok := a.repo.GetSupplyPackage(platform, model); ok {
|
|
return newPkg.PackageID, nil
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (a *admissionSupplyPackageAdapter) GetDraftPackage(ctx context.Context, platform, model string) (admission.DraftPackage, bool) {
|
|
pkg, ok := a.repo.GetSupplyPackage(platform, model)
|
|
if !ok {
|
|
return admission.DraftPackage{}, false
|
|
}
|
|
return admission.DraftPackage{
|
|
PackageID: pkg.PackageID,
|
|
Platform: pkg.Platform,
|
|
Model: pkg.Model,
|
|
Status: pkg.Status,
|
|
Source: pkg.Source,
|
|
}, true
|
|
}
|