package device import ( "context" "fmt" "sync/atomic" ) type Credential struct { Username string Password string } type DisplayInfo struct { Name string Location string } var activeService atomic.Pointer[Service] // ReadCredential is an internal adapter port. Credentials must never be // returned from HTTP handlers, logged, or placed in a URL. func ReadCredential(ctx context.Context, id string) (Credential, error) { return ReadONVIFCredential(ctx, id) } func ReadONVIFCredential(ctx context.Context, id string) (Credential, error) { service := activeService.Load() if service == nil { return Credential{}, fmt.Errorf("device service is not ready") } item, err := service.store.Get(ctx, id) if err != nil { return Credential{}, err } if len(item.CredentialCiphertext) == 0 { return Credential{}, fmt.Errorf("device credential is not configured") } username, password, err := service.vault.Decrypt(item.CredentialCiphertext) return Credential{Username: username, Password: password}, err } func ReadRTSPCredential(ctx context.Context, id string) (Credential, error) { service := activeService.Load() if service == nil { return Credential{}, fmt.Errorf("device service is not ready") } item, err := service.store.Get(ctx, id) if err != nil { return Credential{}, err } if len(item.RTSPCredentialCiphertext) == 0 { return Credential{}, fmt.Errorf("RTSP credential is not configured") } username, password, err := service.vault.Decrypt(item.RTSPCredentialCiphertext) return Credential{Username: username, Password: password}, err } func Describe(ctx context.Context, id string) (DisplayInfo, error) { service := activeService.Load() if service == nil { return DisplayInfo{}, fmt.Errorf("device service is not ready") } item, err := service.store.Get(ctx, id) if err != nil { return DisplayInfo{}, err } return DisplayInfo{Name: item.Name, Location: item.Location}, nil } func MarkActive(ctx context.Context, id string) error { service := activeService.Load() if service == nil { return fmt.Errorf("device service is not ready") } item, err := service.store.Get(ctx, id) if err != nil { return err } if item.Status == StatusDisabled || item.Status == StatusActive { return nil } expected := item.Version item.Status = StatusActive item.Version++ item.UpdatedAt = service.now().UTC() return service.store.Update(ctx, item, expected) }