diff --git a/internal/ipc/server.go b/internal/ipc/server.go index 6e7d590..4d035a3 100644 --- a/internal/ipc/server.go +++ b/internal/ipc/server.go @@ -583,180 +583,113 @@ func (s *Server) dispatch(ctx context.Context, req Request) (json.RawMessage, er return marshalResult(PingResp{Alive: true, Locked: locked}), nil case MethodAssertStepUp: - if s.StepUp != nil { - return marshalResult(nil), s.StepUp(ctx) + if s.StepUp == nil { + return nil, unknownMethod(req.Method) } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) + return marshalResult(nil), s.StepUp(ctx) case MethodStoreEncryptionKey: - if s.WrapKeyFn != nil { - var p storeEncryptionKeyReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - return marshalResult(nil), s.WrapKeyFn(ctx, p.Secret, p.Explicit) + if s.WrapKeyFn == nil { + return nil, unknownMethod(req.Method) } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) + var p storeEncryptionKeyReq + if err := unmarshalParams(req.Params, &p); err != nil { + return nil, err + } + return marshalResult(nil), s.WrapKeyFn(ctx, p.Secret, p.Explicit) case MethodUnlock: - if s.UnlockFn != nil { - var p unlockReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - return marshalResult(nil), s.UnlockFn(ctx, p.Secret) + if s.UnlockFn == nil { + return nil, unknownMethod(req.Method) } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) + var p unlockReq + if err := unmarshalParams(req.Params, &p); err != nil { + return nil, err + } + return marshalResult(nil), s.UnlockFn(ctx, p.Secret) case MethodIngestMail: - if s.IngestMailFn != nil { - var p IngestMailReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.IngestMailFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.IngestMailFn) case MethodSwapModel: - if s.SwapModelFn != nil { - var p SwapModelReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.SwapModelFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.SwapModelFn) case MethodDescribeImage: - if s.DescribeImageFn != nil { - var p DescribeImageReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.DescribeImageFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.DescribeImageFn) case MethodCaptureStart: - if s.CaptureStartFn != nil { - var p CaptureStartReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.CaptureStartFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.CaptureStartFn) case MethodCaptureAppend: - if s.CaptureAppendFn != nil { - var p CaptureAppendReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.CaptureAppendFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.CaptureAppendFn) case MethodCaptureStop: - if s.CaptureStopFn != nil { - var p CaptureStopReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.CaptureStopFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - - case MethodCaptureStatus: - if s.CaptureStatusFn != nil { - resp, err := s.CaptureStatusFn(ctx) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.CaptureStopFn) case MethodEnrollSpeaker: - if s.EnrollSpeakerFn != nil { - var p EnrollSpeakerReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - resp, err := s.EnrollSpeakerFn(ctx, p) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirect(ctx, req, s.EnrollSpeakerFn) + case MethodCaptureStatus: + return callDirectNoParams(ctx, req, s.CaptureStatusFn) case MethodListSpeakers: - if s.ListSpeakersFn != nil { - resp, err := s.ListSpeakersFn(ctx) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - - case MethodForgetSpeaker: - if s.ForgetSpeakerFn != nil { - var p ForgetSpeakerReq - if err := unmarshalParams(req.Params, &p); err != nil { - return nil, err - } - if err := s.ForgetSpeakerFn(ctx, p); err != nil { - return nil, err - } - return marshalResult(nil), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) - + return callDirectNoParams(ctx, req, s.ListSpeakersFn) case MethodModelStatus: - if s.ModelStatusFn != nil { - resp, err := s.ModelStatusFn(ctx) - if err != nil { - return nil, err - } - return marshalResult(resp), nil - } - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) + return callDirectNoParams(ctx, req, s.ModelStatusFn) + case MethodForgetSpeaker: + return callDirectVoid(ctx, req, s.ForgetSpeakerFn) } h, ok := methodTable[req.Method] if !ok { - return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method) + return nil, unknownMethod(req.Method) } return h(ctx, api, req.Params) } +// callDirect runs a daemon-supplied handler that bypasses CoreAPI: unmarshal +// the params, call it, marshal the reply. A nil handler is the capability being +// unconfigured on this box, and the wire says so as an unknown method. +func callDirect[P any, R any](ctx context.Context, req Request, fn func(context.Context, P) (R, error)) (json.RawMessage, error) { + if fn == nil { + return nil, unknownMethod(req.Method) + } + var p P + if err := unmarshalParams(req.Params, &p); err != nil { + return nil, err + } + r, err := fn(ctx, p) + if err != nil { + return nil, err + } + return marshalResult(r), nil +} + +// callDirectNoParams is callDirect for a handler that reads no params. Like +// withoutParams it never touches req.Params. +func callDirectNoParams[R any](ctx context.Context, req Request, fn func(context.Context) (R, error)) (json.RawMessage, error) { + if fn == nil { + return nil, unknownMethod(req.Method) + } + r, err := fn(ctx) + if err != nil { + return nil, err + } + return marshalResult(r), nil +} + +// callDirectVoid is callDirect for a handler with nothing to report back. The +// wire reply is always null. +func callDirectVoid[P any](ctx context.Context, req Request, fn func(context.Context, P) error) (json.RawMessage, error) { + if fn == nil { + return nil, unknownMethod(req.Method) + } + var p P + if err := unmarshalParams(req.Params, &p); err != nil { + return nil, err + } + if err := fn(ctx, p); err != nil { + return nil, err + } + return marshalResult(nil), nil +} + +func unknownMethod(m Method) error { + return fmt.Errorf("%w: %s", ErrUnknownMethod, m) +} + func unmarshalParams(raw json.RawMessage, v any) error { if len(raw) == 0 { raw = []byte("null")