Table-drive the IPC dispatcher instead of a 42-arm switch
dispatch() replaces the hand-written switch with a package-level map[Method]handlerFunc built once at init. Each entry is one withParams/withParamsVoid/withoutParams call closing only over the CoreAPI method it invokes — adding a method is now one table line instead of a new arm. Check still runs once at the top before any unmarshal, unchanged. The three non-CoreAPI methods (assert_stepup, store_encryption_key, unlock) are special-cased before the table lookup since they drive Server fields (StepUp/WrapKeyFn/UnlockFn), not store state. The current CoreAPI is loaded once per dispatch and passed into the handler as an argument, so SetAPI's runtime swap (the unlock transition) still takes effect on the next request — the table itself never captures an api value. No wire-format change; existing round-trip and unknown-method tests in ipc_test.go pass unmodified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
This commit is contained in:
+241
-306
@@ -501,6 +501,239 @@ func (s *Server) safeDispatch(ctx context.Context, req Request) (result json.Raw
|
||||
return s.dispatch(ctx, req)
|
||||
}
|
||||
|
||||
// handlerFunc — one table entry's shape: unmarshal req.Params (if it wants
|
||||
// any), call the matching CoreAPI method against the api passed in, marshal
|
||||
// the result. api is a parameter, not a closed-over field, precisely so a
|
||||
// table built once at package init never pins a stale CoreAPI — see the note
|
||||
// on methodTable below about SetAPI.
|
||||
type handlerFunc func(ctx context.Context, api CoreAPI, raw json.RawMessage) (json.RawMessage, error)
|
||||
|
||||
// withParams adapts a (typed params, typed result) CoreAPI call into a
|
||||
// handlerFunc: unmarshal into P, call fn, marshal R. On error the result is
|
||||
// dropped (marshalResult's output is never read when err != nil — see
|
||||
// serveConn) so every entry can uniformly return early on error without
|
||||
// re-deriving what the pre-table per-arm code used to return in that case.
|
||||
func withParams[P any, R any](fn func(ctx context.Context, api CoreAPI, p P) (R, error)) handlerFunc {
|
||||
return func(ctx context.Context, api CoreAPI, raw json.RawMessage) (json.RawMessage, error) {
|
||||
var p P
|
||||
if err := unmarshalParams(raw, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := fn(ctx, api, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(r), nil
|
||||
}
|
||||
}
|
||||
|
||||
// withParamsVoid is withParams for the error-only methods (mark/resolve/
|
||||
// enable/disable/...): params in, no result out, wire reply is always null.
|
||||
func withParamsVoid[P any](fn func(ctx context.Context, api CoreAPI, p P) error) handlerFunc {
|
||||
return func(ctx context.Context, api CoreAPI, raw json.RawMessage) (json.RawMessage, error) {
|
||||
var p P
|
||||
if err := unmarshalParams(raw, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), fn(ctx, api, p)
|
||||
}
|
||||
}
|
||||
|
||||
// withoutParams is withParams for the handful of methods that take no
|
||||
// params at all (Presence, TickTrace, MorningStatus, ListProposedRoutines).
|
||||
// It does NOT call unmarshalParams — matching the pre-table arms, which
|
||||
// never touched req.Params for these four methods.
|
||||
func withoutParams[R any](fn func(ctx context.Context, api CoreAPI) (R, error)) handlerFunc {
|
||||
return func(ctx context.Context, api CoreAPI, _ json.RawMessage) (json.RawMessage, error) {
|
||||
r, err := fn(ctx, api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(r), nil
|
||||
}
|
||||
}
|
||||
|
||||
// methodTable — one entry per CoreAPI-backed method. Built once at package
|
||||
// init, not per-Server and not per-dispatch: entries close over nothing but
|
||||
// the CoreAPI method being called, and dispatch passes in the *current*
|
||||
// api (loaded fresh via s.api.Load() every call, same as before the table
|
||||
// existed) as an argument — so SetAPI's runtime swap (the unlock transition)
|
||||
// is still honored on the very next request with no extra plumbing here.
|
||||
//
|
||||
// MethodAssertStepUp, MethodStoreEncryptionKey and MethodUnlock are NOT in
|
||||
// this table: they bypass CoreAPI entirely (s.StepUp / s.WrapKeyFn /
|
||||
// s.UnlockFn), so dispatch special-cases them before consulting the table.
|
||||
var methodTable = map[Method]handlerFunc{
|
||||
MethodWriteFact: withParams(func(ctx context.Context, api CoreAPI, p WriteFactReq) (idResp, error) {
|
||||
id, err := api.WriteFact(ctx, p)
|
||||
return idResp{ID: id}, err
|
||||
}),
|
||||
MethodLatestFact: withParams(func(ctx context.Context, api CoreAPI, p keyReq) (Fact, error) {
|
||||
return api.LatestFact(ctx, p.Key)
|
||||
}),
|
||||
MethodLatestFactBySource: withParams(func(ctx context.Context, api CoreAPI, p keySourceReq) (Fact, error) {
|
||||
return api.LatestFactBySource(ctx, p.Key, p.Source)
|
||||
}),
|
||||
MethodSince: withParams(func(ctx context.Context, api CoreAPI, p sinceReq) (sinceResp, error) {
|
||||
d, err := api.Since(ctx, p.Key, p.Now)
|
||||
return sinceResp{Dur: d}, err
|
||||
}),
|
||||
MethodPresence: withoutParams(func(ctx context.Context, api CoreAPI) (Presence, error) {
|
||||
return api.Presence(ctx)
|
||||
}),
|
||||
MethodCreateReminder: withParams(func(ctx context.Context, api CoreAPI, p createReminderReq) (idResp, error) {
|
||||
id, err := api.CreateReminder(ctx, p.Fire, p.Payload, p.Cron)
|
||||
return idResp{ID: id}, err
|
||||
}),
|
||||
MethodMarkReminder: withParamsVoid(func(ctx context.Context, api CoreAPI, p markReminderReq) error {
|
||||
return api.MarkReminder(ctx, p.ID, p.Status)
|
||||
}),
|
||||
MethodListReminders: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]Reminder, error) {
|
||||
out, err := api.ListReminders(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Reminder{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecordNudge: withParams(func(ctx context.Context, api CoreAPI, p recordNudgeReq) (idResp, error) {
|
||||
id, err := api.RecordNudge(ctx, p.Rule, p.Channel, p.Message, p.Ts)
|
||||
return idResp{ID: id}, err
|
||||
}),
|
||||
MethodResolveNudge: withParamsVoid(func(ctx context.Context, api CoreAPI, p resolveNudgeReq) error {
|
||||
return api.ResolveNudge(ctx, p.ID, p.Outcome, p.Ts)
|
||||
}),
|
||||
MethodRecentOutcomes: withParams(func(ctx context.Context, api CoreAPI, p outcomesReq) ([]string, error) {
|
||||
out, err := api.RecentOutcomes(ctx, p.Rule, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []string{} // stable non-null on the wire
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecentFacts: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]Fact, error) {
|
||||
out, err := api.RecentFacts(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Fact{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodCalendarEvents: withParams(func(ctx context.Context, api CoreAPI, p calendarEventsReq) ([]Fact, error) {
|
||||
out, err := api.CalendarEvents(ctx, p.From, p.To)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Fact{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecentNudges: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]Nudge, error) {
|
||||
out, err := api.RecentNudges(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Nudge{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodWriteNote: withParams(func(ctx context.Context, api CoreAPI, p writeNoteReq) (idResp, error) {
|
||||
id, err := api.WriteNote(ctx, p.Ts, p.Text, p.Embedding, p.Source)
|
||||
return idResp{ID: id}, err
|
||||
}),
|
||||
MethodQueryNotes: withParams(func(ctx context.Context, api CoreAPI, p queryNotesReq) ([]Note, error) {
|
||||
out, err := api.QueryNotes(ctx, p.Embedding, p.K)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Note{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecentNotes: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]Note, error) {
|
||||
out, err := api.RecentNotes(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Note{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodProposeTool: withParams(func(ctx context.Context, api CoreAPI, p proposeToolReq) (proposeToolResp, error) {
|
||||
ok, err := api.ProposeTool(ctx, p.Name, p.Utterance, p.Scope, p.Ts)
|
||||
return proposeToolResp{Proposed: ok}, err
|
||||
}),
|
||||
MethodEnableTool: withParamsVoid(func(ctx context.Context, api CoreAPI, p enableToolReq) error {
|
||||
return api.EnableTool(ctx, p.Name, p.Cmd, p.Destructive, p.Scope, p.Ts)
|
||||
}),
|
||||
MethodDisableTool: withParamsVoid(func(ctx context.Context, api CoreAPI, p disableToolReq) error {
|
||||
return api.DisableTool(ctx, p.Name)
|
||||
}),
|
||||
MethodLookupTool: withParams(func(ctx context.Context, api CoreAPI, p lookupToolReq) (Tool, error) {
|
||||
return api.LookupTool(ctx, p.Name)
|
||||
}),
|
||||
MethodListTools: withParams(func(ctx context.Context, api CoreAPI, p listToolsReq) (listToolsResp, error) {
|
||||
out, err := api.ListTools(ctx, p.Status)
|
||||
if err != nil {
|
||||
return listToolsResp{}, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Tool{}
|
||||
}
|
||||
return listToolsResp{Tools: out}, nil
|
||||
}),
|
||||
// MethodDeleteTool shares disableToolReq — both take just a tool name.
|
||||
MethodDeleteTool: withParamsVoid(func(ctx context.Context, api CoreAPI, p disableToolReq) error {
|
||||
return api.DeleteTool(ctx, p.Name)
|
||||
}),
|
||||
MethodListProposedRoutines: withoutParams(func(ctx context.Context, api CoreAPI) (listProposedRoutinesResp, error) {
|
||||
out, err := api.ListProposedRoutines(ctx)
|
||||
if err != nil {
|
||||
return listProposedRoutinesResp{}, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []ProposedRoutine{}
|
||||
}
|
||||
return listProposedRoutinesResp{Routines: out}, nil
|
||||
}),
|
||||
MethodDismissProposedRoutine: withParamsVoid(func(ctx context.Context, api CoreAPI, p dismissProposedRoutineReq) error {
|
||||
return api.DismissProposedRoutine(ctx, p.ID)
|
||||
}),
|
||||
MethodAcceptProposedRoutine: withParamsVoid(func(ctx context.Context, api CoreAPI, p acceptProposedRoutineReq) error {
|
||||
return api.AcceptProposedRoutine(ctx, p.ID)
|
||||
}),
|
||||
MethodRevertFact: withParams(func(ctx context.Context, api CoreAPI, p revertReq) (map[string]int64, error) {
|
||||
newID, err := api.RevertFact(ctx, p.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]int64{"new_id": newID}, nil
|
||||
}),
|
||||
MethodChat: withParams(func(ctx context.Context, api CoreAPI, p chatReq) (chatResp, error) {
|
||||
reply, err := api.Chat(ctx, p.Text)
|
||||
return chatResp{Reply: reply}, err
|
||||
}),
|
||||
MethodTickTrace: withoutParams(func(ctx context.Context, api CoreAPI) (TickTrace, error) {
|
||||
return api.TickTrace(ctx)
|
||||
}),
|
||||
// MorningStatus intentionally has no nil→[]T{} normalization here — the
|
||||
// pre-table arm marshaled api.MorningStatus's result as-is (a nil slice
|
||||
// serializes as JSON null), and this preserves that exact wire shape.
|
||||
MethodMorningStatus: withoutParams(func(ctx context.Context, api CoreAPI) ([]MorningRoutineStatus, error) {
|
||||
return api.MorningStatus(ctx)
|
||||
}),
|
||||
}
|
||||
|
||||
// dispatch unmarshals params for req.Method and calls the matching CoreAPI
|
||||
// method. Unknown method ⇒ ErrUnknownMethod; a malformed params payload ⇒
|
||||
// ErrBadParams with the underlying text (local, server-side, not shipped to
|
||||
@@ -517,312 +750,11 @@ func (s *Server) dispatch(ctx context.Context, req Request) (json.RawMessage, er
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// These three bypass CoreAPI entirely — they drive Server fields set
|
||||
// directly by the daemon (StepUp / WrapKeyFn / UnlockFn), not store
|
||||
// state, so they can never be table entries keyed on a CoreAPI method.
|
||||
switch req.Method {
|
||||
case MethodWriteFact:
|
||||
var p WriteFactReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := api.WriteFact(ctx, p)
|
||||
return marshalResult(idResp{ID: id}), err
|
||||
|
||||
case MethodLatestFact:
|
||||
var p keyReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := api.LatestFact(ctx, p.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(f), nil
|
||||
|
||||
case MethodLatestFactBySource:
|
||||
var p keySourceReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := api.LatestFactBySource(ctx, p.Key, p.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(f), nil
|
||||
|
||||
case MethodSince:
|
||||
var p sinceReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err := api.Since(ctx, p.Key, p.Now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(sinceResp{Dur: d}), nil
|
||||
|
||||
case MethodPresence:
|
||||
pres, err := api.Presence(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(pres), nil
|
||||
|
||||
case MethodCreateReminder:
|
||||
var p createReminderReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := api.CreateReminder(ctx, p.Fire, p.Payload, p.Cron)
|
||||
return marshalResult(idResp{ID: id}), err
|
||||
|
||||
case MethodMarkReminder:
|
||||
var p markReminderReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := api.MarkReminder(ctx, p.ID, p.Status)
|
||||
return marshalResult(nil), err
|
||||
|
||||
case MethodListReminders:
|
||||
var p nReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.ListReminders(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Reminder{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodRecordNudge:
|
||||
var p recordNudgeReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := api.RecordNudge(ctx, p.Rule, p.Channel, p.Message, p.Ts)
|
||||
return marshalResult(idResp{ID: id}), err
|
||||
|
||||
case MethodResolveNudge:
|
||||
var p resolveNudgeReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := api.ResolveNudge(ctx, p.ID, p.Outcome, p.Ts)
|
||||
return marshalResult(nil), err
|
||||
|
||||
case MethodRecentOutcomes:
|
||||
var p outcomesReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.RecentOutcomes(ctx, p.Rule, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []string{} // stable non-null on the wire
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodRecentFacts:
|
||||
var p nReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.RecentFacts(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Fact{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodCalendarEvents:
|
||||
var p calendarEventsReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.CalendarEvents(ctx, p.From, p.To)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Fact{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodRecentNudges:
|
||||
var p nReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.RecentNudges(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Nudge{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodWriteNote:
|
||||
var p writeNoteReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := api.WriteNote(ctx, p.Ts, p.Text, p.Embedding, p.Source)
|
||||
return marshalResult(idResp{ID: id}), err
|
||||
|
||||
case MethodQueryNotes:
|
||||
var p queryNotesReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.QueryNotes(ctx, p.Embedding, p.K)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Note{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodRecentNotes:
|
||||
var p nReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.RecentNotes(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Note{}
|
||||
}
|
||||
return marshalResult(out), nil
|
||||
|
||||
case MethodProposeTool:
|
||||
var p proposeToolReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok, err := api.ProposeTool(ctx, p.Name, p.Utterance, p.Scope, p.Ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(proposeToolResp{Proposed: ok}), nil
|
||||
|
||||
case MethodEnableTool:
|
||||
var p enableToolReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), api.EnableTool(ctx, p.Name, p.Cmd, p.Destructive, p.Scope, p.Ts)
|
||||
|
||||
case MethodDisableTool:
|
||||
var p disableToolReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), api.DisableTool(ctx, p.Name)
|
||||
|
||||
case MethodLookupTool:
|
||||
var p lookupToolReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t, err := api.LookupTool(ctx, p.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(t), nil
|
||||
|
||||
case MethodListTools:
|
||||
var p listToolsReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := api.ListTools(ctx, p.Status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []Tool{}
|
||||
}
|
||||
return marshalResult(listToolsResp{Tools: out}), nil
|
||||
|
||||
case MethodDeleteTool:
|
||||
var p disableToolReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), api.DeleteTool(ctx, p.Name)
|
||||
|
||||
case MethodListProposedRoutines:
|
||||
out, err := api.ListProposedRoutines(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []ProposedRoutine{}
|
||||
}
|
||||
return marshalResult(listProposedRoutinesResp{Routines: out}), nil
|
||||
|
||||
case MethodDismissProposedRoutine:
|
||||
var p dismissProposedRoutineReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), api.DismissProposedRoutine(ctx, p.ID)
|
||||
|
||||
case MethodAcceptProposedRoutine:
|
||||
var p acceptProposedRoutineReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(nil), api.AcceptProposedRoutine(ctx, p.ID)
|
||||
|
||||
case MethodRevertFact:
|
||||
var p struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newID, err := api.RevertFact(ctx, p.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(map[string]int64{"new_id": newID}), nil
|
||||
|
||||
case MethodChat:
|
||||
var p chatReq
|
||||
if err := unmarshalParams(req.Params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reply, err := api.Chat(ctx, p.Text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(chatResp{Reply: reply}), nil
|
||||
|
||||
case MethodTickTrace:
|
||||
t, err := api.TickTrace(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(t), nil
|
||||
|
||||
case MethodMorningStatus:
|
||||
s, err := api.MorningStatus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return marshalResult(s), nil
|
||||
|
||||
case MethodAssertStepUp:
|
||||
if s.StepUp != nil {
|
||||
return marshalResult(nil), s.StepUp(ctx)
|
||||
@@ -848,10 +780,13 @@ func (s *Server) dispatch(ctx context.Context, req Request) (json.RawMessage, er
|
||||
return marshalResult(nil), s.UnlockFn(ctx, p.PublicKey)
|
||||
}
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method)
|
||||
}
|
||||
|
||||
default:
|
||||
h, ok := methodTable[req.Method]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnknownMethod, req.Method)
|
||||
}
|
||||
return h(ctx, api, req.Params)
|
||||
}
|
||||
|
||||
func unmarshalParams(raw json.RawMessage, v any) error {
|
||||
|
||||
Reference in New Issue
Block a user