github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/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/nats-io/nsc/v2/cmd/store" 25 26 nats "github.com/nats-io/nats.go" 27 28 "github.com/spf13/cobra" 29 ) 30 31 func createToolReqCmd() *cobra.Command { 32 var params ReqParams 33 var cmd = &cobra.Command{ 34 Use: "req", 35 Short: "Send a request to a subject on a NATS account", 36 Example: "ngs tool req <subject> <opt_payload>", 37 Args: cobra.MinimumNArgs(1), 38 RunE: func(cmd *cobra.Command, args []string) error { 39 return RunAction(cmd, args, ¶ms) 40 }, 41 } 42 params.BindFlags(cmd) 43 cmd.Flags().BoolVarP(&encryptFlag, "encrypt", "E", false, "encrypt payload") 44 cmd.Flags().MarkHidden("encrypt") 45 cmd.Flags().MarkHidden("decrypt") 46 47 return cmd 48 } 49 50 func init() { 51 toolCmd.AddCommand(createToolReqCmd()) 52 hidden := createToolReqCmd() 53 hidden.Hidden = true 54 hidden.Example = "ngs tool req <subject> <opt_payload>" 55 GetRootCmd().AddCommand(hidden) 56 } 57 58 type ReqParams struct { 59 AccountUserContextParams 60 credsPath string 61 natsURLs []string 62 } 63 64 func (p *ReqParams) SetDefaults(ctx ActionCtx) error { 65 return p.AccountUserContextParams.SetDefaults(ctx) 66 } 67 68 func (p *ReqParams) PreInteractive(ctx ActionCtx) error { 69 return p.AccountUserContextParams.Edit(ctx) 70 } 71 72 func (p *ReqParams) Load(ctx ActionCtx) error { 73 p.credsPath = ctx.StoreCtx().KeyStore.CalcUserCredsPath(p.AccountContextParams.Name, p.UserContextParams.Name) 74 if natsURLFlag != "" { 75 p.natsURLs = []string{natsURLFlag} 76 return nil 77 } 78 79 oc, err := ctx.StoreCtx().Store.ReadOperatorClaim() 80 if err != nil { 81 return err 82 } 83 p.natsURLs = oc.OperatorServiceURLs 84 return nil 85 } 86 87 func (p *ReqParams) PostInteractive(ctx ActionCtx) error { 88 return nil 89 } 90 91 func (p *ReqParams) Validate(ctx ActionCtx) error { 92 if err := p.AccountUserContextParams.Validate(ctx); err != nil { 93 return err 94 } 95 96 if encryptFlag { 97 _, err := ctx.StoreCtx().KeyStore.GetSeed(ctx.StoreCtx().Account.PublicKey) 98 if err != nil { 99 return fmt.Errorf("unable to get the account private key to encrypt/decrypt the payload: %v", err) 100 } 101 } 102 103 if p.credsPath == "" { 104 return fmt.Errorf("a creds file for account %q/%q was not found", p.AccountContextParams.Name, p.UserContextParams.Name) 105 } 106 _, err := os.Stat(p.credsPath) 107 if os.IsNotExist(err) { 108 return err 109 } 110 if len(p.natsURLs) == 0 { 111 return fmt.Errorf("operator %q doesn't have operator_service_urls set", ctx.StoreCtx().Operator.Name) 112 } 113 return nil 114 } 115 116 func (p *ReqParams) Run(ctx ActionCtx) (store.Status, error) { 117 nc, err := nats.Connect(strings.Join(p.natsURLs, ", "), 118 createDefaultToolOptions("nsc_req", ctx, nats.UserCredentials(p.credsPath))...) 119 if err != nil { 120 return nil, err 121 } 122 defer nc.Close() 123 124 subj := ctx.Args()[0] 125 payload := "" 126 if len(ctx.Args()) > 1 { 127 payload = ctx.Args()[1] 128 } 129 130 var seed string 131 if encryptFlag { 132 // cannot fail if we are here 133 seed, _ = ctx.StoreCtx().KeyStore.GetSeed(ctx.StoreCtx().Account.PublicKey) 134 } 135 136 out := []byte(payload) 137 if encryptFlag { 138 out, err = EncryptKV(seed, out) 139 if err != nil { 140 return nil, err 141 } 142 } 143 144 if encryptFlag { 145 ctx.CurrentCmd().Printf("published encrypted request: [%s] : '%s'\n", subj, payload) 146 } else { 147 ctx.CurrentCmd().Printf("published request: [%s] : '%s'\n", subj, payload) 148 } 149 msg, err := nc.Request(subj, out, 5*time.Second) 150 if err == nats.ErrTimeout { 151 ctx.CurrentCmd().Println("request timed out") 152 return nil, nil 153 } 154 if err != nil { 155 return nil, err 156 } 157 158 if encryptFlag { 159 msg = maybeDecryptMessage(seed, msg) 160 } 161 ctx.CurrentCmd().Printf("received reply: [%v] : '%s'\n", msg.Subject, string(msg.Data)) 162 return nil, nil 163 }