github.com/kbehouse/nsc@v0.0.6/cmd/reqtool.go (about)

     1  /*
     2   * Copyright 2018-2019 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  	"os"
    21  	"strings"
    22  	"time"
    23  
    24  	"github.com/kbehouse/nsc/cmd/store"
    25  
    26  	nats "github.com/nats-io/nats.go"
    27  	"github.com/spf13/cobra"
    28  )
    29  
    30  func createToolReqCmd() *cobra.Command {
    31  	var params ReqParams
    32  	var cmd = &cobra.Command{
    33  		Use:     "req",
    34  		Short:   "Send a request to a subject on a NATS account",
    35  		Example: "ngs tool req <subject> <opt_payload>",
    36  		Args:    cobra.MinimumNArgs(1),
    37  		RunE: func(cmd *cobra.Command, args []string) error {
    38  			return RunAction(cmd, args, &params)
    39  		},
    40  	}
    41  	params.BindFlags(cmd)
    42  	cmd.Flags().BoolVarP(&encryptFlag, "encrypt", "E", false, "encrypt payload")
    43  	cmd.Flags().MarkHidden("encrypt")
    44  	cmd.Flags().MarkHidden("decrypt")
    45  
    46  	return cmd
    47  }
    48  
    49  func init() {
    50  	toolCmd.AddCommand(createToolReqCmd())
    51  	hidden := createToolReqCmd()
    52  	hidden.Hidden = true
    53  	hidden.Example = "ngs tool req <subject> <opt_payload>"
    54  	GetRootCmd().AddCommand(hidden)
    55  }
    56  
    57  type ReqParams struct {
    58  	AccountUserContextParams
    59  	credsPath string
    60  	natsURLs  []string
    61  }
    62  
    63  func (p *ReqParams) SetDefaults(ctx ActionCtx) error {
    64  	return p.AccountUserContextParams.SetDefaults(ctx)
    65  }
    66  
    67  func (p *ReqParams) PreInteractive(ctx ActionCtx) error {
    68  	return p.AccountUserContextParams.Edit(ctx)
    69  }
    70  
    71  func (p *ReqParams) Load(ctx ActionCtx) error {
    72  	p.credsPath = ctx.StoreCtx().KeyStore.CalcUserCredsPath(p.AccountContextParams.Name, p.UserContextParams.Name)
    73  	if natsURLFlag != "" {
    74  		p.natsURLs = []string{natsURLFlag}
    75  		return nil
    76  	}
    77  
    78  	oc, err := ctx.StoreCtx().Store.ReadOperatorClaim()
    79  	if err != nil {
    80  		return err
    81  	}
    82  	p.natsURLs = oc.OperatorServiceURLs
    83  	return nil
    84  }
    85  
    86  func (p *ReqParams) PostInteractive(ctx ActionCtx) error {
    87  	return nil
    88  }
    89  
    90  func (p *ReqParams) Validate(ctx ActionCtx) error {
    91  	if err := p.AccountUserContextParams.Validate(ctx); err != nil {
    92  		return err
    93  	}
    94  
    95  	if encryptFlag {
    96  		_, err := ctx.StoreCtx().KeyStore.GetSeed(ctx.StoreCtx().Account.PublicKey)
    97  		if err != nil {
    98  			return fmt.Errorf("unable to get the account private key to encrypt/decrypt the payload: %v", err)
    99  		}
   100  	}
   101  
   102  	if p.credsPath == "" {
   103  		return fmt.Errorf("a creds file for account %q/%q was not found", p.AccountContextParams.Name, p.UserContextParams.Name)
   104  	}
   105  	_, err := os.Stat(p.credsPath)
   106  	if os.IsNotExist(err) {
   107  		return err
   108  	}
   109  	if len(p.natsURLs) == 0 {
   110  		return fmt.Errorf("operator %q doesn't have operator_service_urls set", ctx.StoreCtx().Operator.Name)
   111  	}
   112  	return nil
   113  }
   114  
   115  func (p *ReqParams) Run(ctx ActionCtx) (store.Status, error) {
   116  	nc, err := nats.Connect(strings.Join(p.natsURLs, ", "),
   117  		createDefaultToolOptions("nsc_req", ctx, nats.UserCredentials(p.credsPath))...)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	defer nc.Close()
   122  
   123  	subj := ctx.Args()[0]
   124  	payload := ""
   125  	if len(ctx.Args()) > 1 {
   126  		payload = ctx.Args()[1]
   127  	}
   128  
   129  	var seed string
   130  	if encryptFlag {
   131  		// cannot fail if we are here
   132  		seed, _ = ctx.StoreCtx().KeyStore.GetSeed(ctx.StoreCtx().Account.PublicKey)
   133  	}
   134  
   135  	out := []byte(payload)
   136  	if encryptFlag {
   137  		out, err = EncryptKV(seed, out)
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  	}
   142  
   143  	if encryptFlag {
   144  		ctx.CurrentCmd().Printf("published encrypted request: [%s] : '%s'\n", subj, payload)
   145  	} else {
   146  		ctx.CurrentCmd().Printf("published request: [%s] : '%s'\n", subj, payload)
   147  	}
   148  	msg, err := nc.Request(subj, out, 5*time.Second)
   149  	if err == nats.ErrTimeout {
   150  		ctx.CurrentCmd().Println("request timed out")
   151  		return nil, nil
   152  	}
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	if encryptFlag {
   158  		msg = maybeDecryptMessage(seed, msg)
   159  	}
   160  	ctx.CurrentCmd().Printf("received reply: [%v] : '%s'\n", msg.Subject, string(msg.Data))
   161  	return nil, nil
   162  }