feat: add diagnostics and safe reset maintenance
This commit is contained in:
+38
-5
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"proxyctl/internal/profile"
|
||||
"proxyctl/internal/target"
|
||||
@@ -55,10 +56,12 @@ type Module interface {
|
||||
}
|
||||
|
||||
type Application struct {
|
||||
store profile.Store
|
||||
state profile.State
|
||||
targets []target.Target
|
||||
inspections map[string]target.Inspection
|
||||
store profile.Store
|
||||
state profile.State
|
||||
targets []target.Target
|
||||
inspections map[string]target.Inspection
|
||||
mutationLock MutationLock
|
||||
logger OperationLogger
|
||||
}
|
||||
|
||||
func New(store profile.Store) (*Application, error) {
|
||||
@@ -66,11 +69,23 @@ func New(store profile.Store) (*Application, error) {
|
||||
}
|
||||
|
||||
func NewWithTargets(store profile.Store, targets []target.Target) (*Application, error) {
|
||||
return NewWithTargetsAndLock(store, targets, nil)
|
||||
}
|
||||
|
||||
// NewWithTargetsAndLock configures the cross-process lock used by every
|
||||
// Profile or Target mutation. A nil lock is intended only for isolated tests.
|
||||
func NewWithTargetsAndLock(store profile.Store, targets []target.Target, mutationLock MutationLock) (*Application, error) {
|
||||
return NewWithTargetsAndRuntime(store, targets, mutationLock, nil)
|
||||
}
|
||||
|
||||
// NewWithTargetsAndRuntime configures shared mutation serialization and local
|
||||
// operation diagnostics for production callers.
|
||||
func NewWithTargetsAndRuntime(store profile.Store, targets []target.Target, mutationLock MutationLock, logger OperationLogger) (*Application, error) {
|
||||
state, err := store.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a := &Application{store: store, state: state, targets: append([]target.Target(nil), targets...), inspections: make(map[string]target.Inspection)}
|
||||
a := &Application{store: store, state: state, targets: append([]target.Target(nil), targets...), inspections: make(map[string]target.Inspection), mutationLock: mutationLock, logger: logger}
|
||||
a.refreshTargets()
|
||||
return a, nil
|
||||
}
|
||||
@@ -87,6 +102,13 @@ func (a *Application) Snapshot() Snapshot {
|
||||
}
|
||||
|
||||
func (a *Application) Dispatch(intent Intent) Result {
|
||||
if a.mutationLock != nil {
|
||||
unlock, err := a.mutationLock.Lock(context.Background())
|
||||
if err != nil {
|
||||
return Result{Snapshot: a.Snapshot(), Err: fmt.Errorf("lock proxyctl mutation: %w", err)}
|
||||
}
|
||||
defer unlock()
|
||||
}
|
||||
if intent.Kind == SetTargetDesired {
|
||||
return a.setTargetDesired(intent)
|
||||
}
|
||||
@@ -161,6 +183,17 @@ func (a *Application) setTargetDesired(intent Intent) Result {
|
||||
}
|
||||
result := selected.SetDesired(context.Background(), intent.Enabled, active)
|
||||
a.inspections[selected.ID()] = result.Inspection
|
||||
outcome, detail := "success", result.Inspection.Evidence
|
||||
if result.Err != nil {
|
||||
outcome, detail = "failure", result.Err.Error()
|
||||
}
|
||||
if a.logger != nil {
|
||||
operation := "disable"
|
||||
if intent.Enabled {
|
||||
operation = "enable"
|
||||
}
|
||||
_ = a.logger.Write(LogEntry{Time: time.Now(), Operation: operation, Target: selected.ID(), Result: outcome, Detail: RedactLogDetail(detail)})
|
||||
}
|
||||
notice := ""
|
||||
if result.Err == nil {
|
||||
notice = fmt.Sprintf("%s Target is now %s", selected.Description().Name, result.Inspection.State)
|
||||
|
||||
Reference in New Issue
Block a user