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, ¶ms) 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 }