From 337d45e896c0ef3c6d4a0103c9d1f75af81eda05 Mon Sep 17 00:00:00 2001 From: Mengyi Date: Tue, 19 Oct 2021 10:48:39 +0200 Subject: [PATCH] feat: add support for core-command list This commit adds support for the `list` command of the `command` endpoint. ``` edgex-cli command list ``` Adds support for the `-j`, `-v` flags, which generate raw JSON output. Adds support for the `-l` flag, which limits the number of items to return. Adds support for the `-o` flag, which indicates the number of items to skip. Signed-off-by: Mengyi --- internal/cmd/command.go | 97 ++++++++++++++++++++++++++ internal/service/corecommandservice.go | 22 ++++++ 2 files changed, 119 insertions(+) diff --git a/internal/cmd/command.go b/internal/cmd/command.go index f30589f..cb3d668 100644 --- a/internal/cmd/command.go +++ b/internal/cmd/command.go @@ -20,6 +20,7 @@ import ( jsonpkg "encoding/json" "errors" "fmt" + "github.com/edgexfoundry/go-mod-core-contracts/v2/dtos" "github.com/spf13/cobra" "io/ioutil" "os" @@ -29,11 +30,13 @@ import ( var deviceName, commandName string var pushEvent, noReturnEvent bool var requestBody, requestFile string +var limit, offset int func init() { commandCmd := initCommandCommand() initReadCommand(commandCmd) initWriteCommand(commandCmd) + initListCommand(commandCmd) } func initCommandCommand() *cobra.Command { @@ -84,6 +87,21 @@ func initWriteCommand(cmd *cobra.Command) { addFormatFlags(writeCmd) } +func initListCommand(cmd *cobra.Command) { + listCmd := &cobra.Command{ + Use: "list", + Short: "A list of device supported commands", + Long: "Returns a paginated list contains all of the commands in the system associated with their respective device, optionally filtering by device name", + RunE: handleListCommand, + SilenceUsage: true, + } + listCmd.Flags().StringVarP(&deviceName, "device", "d", "", "List commands specified by device name") + listCmd.Flags().IntVarP(&limit, "limit", "l", 50, "The number of items to return. Specifying -1 will return all remaining items") + listCmd.Flags().IntVarP(&offset, "offset", "o", 0, "The number of items to skip") + cmd.AddCommand(listCmd) + addFormatFlags(listCmd) +} + func handleReadCommand(cmd *cobra.Command, args []string) error { dsPushEvent := boolToString(pushEvent) dsReturnEvent := boolToString(!noReturnEvent) @@ -168,6 +186,85 @@ func handleWriteCommand(cmd *cobra.Command, args []string) error { return nil } +func handleListCommand(cmd *cobra.Command, args []string) error { + //LIST commands with specified device name + if deviceName != "" { + response, err := getCoreCommandService().ListCommandsByDeviceName(deviceName) + if err != nil { + return err + } + + //print LIST commands with one of these formats: JSON, verbose or table + if json || verbose { + stringified, err := jsonpkg.Marshal(response) + if err != nil { + return err + } + + if verbose { + url := getCoreCommandService().GetListByDeviceEndpoint(deviceName) + fmt.Printf("Result:%s\nURL: %s\n", string(stringified), url) + } else { + fmt.Printf(string(stringified)) + } + } else { + w := tabwriter.NewWriter(os.Stdout, 1, 1, 2, ' ', 0) + fmt.Fprintln(w, "Name\tDevice Name\tProfile Name\tMethods\tURL") + for _, command := range response.DeviceCoreCommand.CoreCommands { + methods := methodsToString(command) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", + command.Name, response.DeviceCoreCommand.DeviceName, response.DeviceCoreCommand.ProfileName, methods, command.Url+command.Path) + } + w.Flush() + } + //LIST all commands, optionally specifying a limit and offset + } else { + response, err := getCoreCommandService().ListAllCommands(offset, limit) + if err != nil { + return err + } + + //print LIST command's output with one of these formats: JSON, verbose or table + if json || verbose { + stringified, err := jsonpkg.Marshal(response) + if err != nil { + return err + } + + if verbose { + url := getCoreCommandService().GetListAllEndpoint() + fmt.Printf("Result:%s\nURL: %s\n", string(stringified), url) + } else { + fmt.Printf(string(stringified)) + } + } else { + w := tabwriter.NewWriter(os.Stdout, 1, 1, 2, ' ', 0) + fmt.Fprintln(w, "Name\tDevice Name\tProfile Name\tMethods\tURL") + for _, device := range response.DeviceCoreCommands { + for _, command := range device.CoreCommands { + methods := methodsToString(command) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", + command.Name, device.DeviceName, device.ProfileName, methods, command.Url+command.Path) + } + } + w.Flush() + } + } + + return nil +} + +//using by LIST when it shows in table format +func methodsToString(command dtos.CoreCommand) string { + if command.Get && command.Set { + return "Get, Put" + } else if command.Get { + return "Get" + } else { + return "Put" + } +} + //using by READ when it specified dsPushEvent or dsReturnEvent func boolToString(b bool) string { if b { diff --git a/internal/service/corecommandservice.go b/internal/service/corecommandservice.go index d722244..1639594 100644 --- a/internal/service/corecommandservice.go +++ b/internal/service/corecommandservice.go @@ -39,6 +39,18 @@ func (c Service) IssueWriteCommand(deviceName string, commandName string, settin return } +func (c Service) ListAllCommands(offset int, limit int) (response responses.MultiDeviceCoreCommandsResponse, err error) { + client := c.getCommandClient() + response, err = client.AllDeviceCoreCommands(context.Background(), offset, limit) + return +} + +func (c Service) ListCommandsByDeviceName(deviceName string) (response responses.DeviceCoreCommandResponse, err error) { + client := c.getCommandClient() + response, err = client.DeviceCoreCommandsByDeviceName(context.Background(), deviceName) + return +} + func (c Service) GetReadEndpoint(deviceName string, commandName string, dsPushEvent string, dsReturnEvent string) string { url := c.getEndpointUrl(common.ApiDeviceNameCommandNameRoute) replacer := strings.NewReplacer("{name}", deviceName, "{command}", commandName) @@ -51,6 +63,16 @@ func (c Service) GetWriteEndpoint(deviceName string, commandName string, request return replacer.Replace(url) + " -d '" + requestBody + "'" } +func (c Service) GetListAllEndpoint() string { + return c.getEndpointUrl(common.ApiAllDeviceRoute) +} + +func (c Service) GetListByDeviceEndpoint(deviceName string) string { + url := c.getEndpointUrl(common.ApiDeviceByNameRoute) + replacer := strings.NewReplacer("{name}", deviceName) + return replacer.Replace(url) +} + func (c Service) getEndpointUrl(endpoint string) string { return fmt.Sprintf("http://%s:%v%s", c.Host, c.Port, endpoint) }