diff --git a/cmd/ftl/cmd_call.go b/cmd/ftl/cmd_call.go index 2866b613f2..f53c42ca6b 100644 --- a/cmd/ftl/cmd_call.go +++ b/cmd/ftl/cmd_call.go @@ -5,9 +5,7 @@ import ( "encoding/json" "fmt" "net/url" - "strings" "time" - "unicode/utf8" "connectrpc.com/connect" "github.com/alecthomas/errors" @@ -20,7 +18,6 @@ import ( "github.com/block/ftl/common/reflection" "github.com/block/ftl/internal/rpc" "github.com/block/ftl/internal/rpc/headers" - "github.com/block/ftl/internal/schema/schemaeventsource" status "github.com/block/ftl/internal/terminal" ) @@ -35,7 +32,6 @@ type callCmd struct { func (c *callCmd) Run( ctx context.Context, verbClient ftlv1connect.VerbServiceClient, - schemaClient *schemaeventsource.EventSource, ) error { if err := rpc.Wait(ctx, backoff.Backoff{Max: time.Second * 2}, c.Wait, verbClient); err != nil { return errors.WithStack(err) @@ -54,13 +50,12 @@ func (c *callCmd) Run( logger.Debugf("Calling %s", c.Verb) - return errors.WithStack(callVerb(ctx, verbClient, schemaClient, c.Verb, requestJSON, c.Verbose, c)) + return errors.WithStack(callVerb(ctx, verbClient, c.Verb, requestJSON, c.Verbose, c)) } func callVerb( ctx context.Context, verbClient ftlv1connect.VerbServiceClient, - schemaClient *schemaeventsource.EventSource, verb reflection.Ref, requestJSON []byte, verbose bool, @@ -73,14 +68,6 @@ func callVerb( Body: requestJSON, })) - if cerr := new(connect.Error); errors.As(err, &cerr) && cerr.Code() == connect.CodeNotFound { - suggestions, err := findSuggestions(ctx, schemaClient, verb) - - // If we have suggestions, return a helpful error message, otherwise continue to the original error. - if err == nil { - return errors.Errorf("verb not found: %s\n\nDid you mean one of these?\n%s", verb, strings.Join(suggestions, "\n")) - } - } if err != nil { return errors.WithStack(err) } @@ -114,83 +101,3 @@ func callVerb( } return nil } - -// findSuggestions looks up the schema and finds verbs that are similar to the one that was not found -// it uses the levenshtein distance to determine similarity - if the distance is less than 40% of the length of the verb, -// it returns an error if no closely matching suggestions are found -func findSuggestions( - ctx context.Context, - schemaClient *schemaeventsource.EventSource, - verb reflection.Ref, -) ([]string, error) { - logger := log.FromContext(ctx) - - // lookup the verbs - schemaClient.WaitForInitialSync(ctx) - res := schemaClient.CanonicalView() - verbs := []string{} - - // build a list of all the verbs - for _, module := range res.InternalModules() { - for _, v := range module.Verbs() { - verbName := fmt.Sprintf("%s.%s", module.Name, v.Name) - if verbName == fmt.Sprintf("%s.%s", verb.Module, verb.Name) { - break - } - - verbs = append(verbs, module.Name+"."+v.Name) - } - } - - suggestions := []string{} - - logger.Debugf("Found %d verbs", len(verbs)) - needle := fmt.Sprintf("%s.%s", verb.Module, verb.Name) - - // only consider suggesting verbs that are within 40% of the length of the needle - distanceThreshold := int(float64(len(needle))*0.4) + 1 - for _, verb := range verbs { - d := levenshtein(verb, needle) - logger.Debugf("Verb %s distance %d", verb, d) - - if d <= distanceThreshold { - suggestions = append(suggestions, verb) - } - } - - if len(suggestions) > 0 { - return suggestions, nil - } - - return nil, errors.Errorf("no suggestions found") -} - -// Levenshtein computes the Levenshtein distance between two strings. -// -// credit goes to https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Go -func levenshtein(a, b string) int { - f := make([]int, utf8.RuneCountInString(b)+1) - - for j := range f { - f[j] = j - } - - for _, ca := range a { - j := 1 - fj1 := f[0] // fj1 is the value of f[j - 1] in last iteration - f[0]++ - for _, cb := range b { - mn := min(f[j]+1, f[j-1]+1) // delete & insert - if cb != ca { - mn = min(mn, fj1+1) // change - } else { - mn = min(mn, fj1) // matched - } - - fj1, f[j] = f[j], mn // save f[j] to fj1(j is about to increase), update f[j] to mn - j++ - } - } - - return f[len(f)-1] -} diff --git a/cmd/ftl/cmd_replay.go b/cmd/ftl/cmd_replay.go index 5fd82a69ef..67652d1c0a 100644 --- a/cmd/ftl/cmd_replay.go +++ b/cmd/ftl/cmd_replay.go @@ -3,7 +3,6 @@ package main import ( "context" "net/url" - "strings" "time" "connectrpc.com/connect" @@ -62,11 +61,6 @@ func (c *replayCmd) Run( } } if !found { - suggestions, err := findSuggestions(ctx, eventSource, c.Verb) - // if we have suggestions, return a helpful error message. otherwise continue to the original error - if err == nil { - return errors.Errorf("verb not found: %s\n\nDid you mean one of these?\n%s", c.Verb, strings.Join(suggestions, "\n")) - } return errors.Errorf("verb not found: %s", c.Verb) } @@ -109,5 +103,5 @@ func (c *replayCmd) Run( ConsoleEndpoint: c.ConsoleEndpoint, Verbose: c.Verbose, } - return errors.WithStack(callVerb(ctx, verbClient, eventSource, c.Verb, []byte(requestJSON), c.Verbose, cmd)) + return errors.WithStack(callVerb(ctx, verbClient, c.Verb, []byte(requestJSON), c.Verbose, cmd)) }