package main import ( "context" "fmt" "os" "strconv" "strings" "github.com/fatih/color" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip90" "github.com/urfave/cli/v3" ) var dvm = &cli.Command{ Name: "dvm", Usage: "deal with nip90 data-vending-machine things (experimental)", Description: `example usage: nak dvm 5001 --input "What is the capital of France?" --input-type text --output "text/plain" --bid 1000 wss://relay.example.com`, DisableSliceFlagSeparator: true, Flags: append(defaultKeyFlags, &cli.StringSliceFlag{ Name: "relay", Aliases: []string{"r"}, }, ), Commands: append([]*cli.Command{ { Name: "list", Usage: "find DVMs that have announced themselves for a specific kind", Action: func(ctx context.Context, c *cli.Command) error { return fmt.Errorf("we don't know how to do this yet") }, }, }, (func() []*cli.Command { commands := make([]*cli.Command, len(nip90.Jobs)) for i, job := range nip90.Jobs { flags := make([]cli.Flag, 0, 2+len(job.Params)) if job.InputType != "" { flags = append(flags, &cli.StringSliceFlag{ Name: "input", Category: "INPUT", }) } for _, param := range job.Params { flags = append(flags, &cli.StringSliceFlag{ Name: param, Category: "PARAMETER", }) } commands[i] = &cli.Command{ Name: strconv.Itoa(job.InputKind), Usage: job.Name, Description: job.Description, Flags: flags, Action: func(ctx context.Context, c *cli.Command) error { relayUrls := c.StringSlice("relay") relays := connectToAllRelays(ctx, relayUrls, false) if len(relays) == 0 { log("failed to connect to any of the given relays.\n") os.Exit(3) } defer func() { for _, relay := range relays { relay.Close() } }() evt := nostr.Event{ Kind: job.InputKind, Tags: make(nostr.Tags, 0, 2+len(job.Params)), CreatedAt: nostr.Now(), } for _, input := range c.StringSlice("input") { evt.Tags = append(evt.Tags, nostr.Tag{"i", input, job.InputType}) } for _, paramN := range job.Params { for _, paramV := range c.StringSlice(paramN) { tag := nostr.Tag{"param", paramN, "", ""}[0:2] for _, v := range strings.Split(paramV, ";") { tag = append(tag, v) } evt.Tags = append(evt.Tags, tag) } } kr, _, err := gatherKeyerFromArguments(ctx, c) if err != nil { return err } if err := kr.SignEvent(ctx, &evt); err != nil { return err } log("- publishing job request... ") first := true for res := range sys.Pool.PublishMany(ctx, relayUrls, evt) { cleanUrl, ok := strings.CutPrefix(res.RelayURL, "wss://") if !ok { cleanUrl = res.RelayURL } if !first { log(", ") } first = false if res.Error != nil { log("%s: %s", color.RedString(cleanUrl), res.Error) } else { log("%s: ok", color.GreenString(cleanUrl)) } } log("\n- waiting for response...") for ie := range sys.Pool.SubscribeMany(ctx, relayUrls, nostr.Filter{ Kinds: []int{7000, job.OutputKind}, Tags: nostr.TagMap{"e": []string{evt.ID}}, }) { stdout(ie.Event) } return nil }, } } return commands })()...), }