github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/internal/fs/client/action.templ (about) 1 {{ GeneratedWarning }} 2 3 package {{ .Package }} 4 5 import ( 6 "context" 7 "encoding/json" 8 "fmt" 9 "sync" 10 "io" 11 "github.com/choria-io/go-choria/protocol" 12 rpcclient "github.com/choria-io/go-choria/providers/agent/mcorpc/client" 13 "github.com/choria-io/go-choria/providers/agent/mcorpc/replyfmt" 14 "github.com/choria-io/go-choria/providers/agent/mcorpc/ddl/agent" 15 ) 16 17 // {{ .ActionName | SnakeToCamel }}Requester performs a RPC request to {{ .AgentName | ToLower }}#{{ .ActionName | ToLower }} 18 type {{ .ActionName | SnakeToCamel }}Requester struct { 19 r *requester 20 outc chan *{{ .ActionName | SnakeToCamel }}Output 21 } 22 23 // {{ .ActionName | SnakeToCamel }}Output is the output from the {{ .ActionName | ToLower }} action 24 type {{ .ActionName | SnakeToCamel }}Output struct { 25 details *ResultDetails 26 reply map[string]any 27 } 28 29 // {{ .ActionName | SnakeToCamel }}Result is the result from a {{ .ActionName | ToLower }} action 30 type {{ .ActionName | SnakeToCamel }}Result struct { 31 ddl *agent.DDL 32 stats *rpcclient.Stats 33 outputs []*{{ .ActionName | SnakeToCamel }}Output 34 rpcreplies []*replyfmt.RPCReply 35 mu sync.Mutex 36 } 37 38 func (d *{{ .ActionName | SnakeToCamel }}Result) RenderResults(w io.Writer, format RenderFormat, displayMode DisplayMode, verbose bool, silent bool, colorize bool, log Log) error { 39 d.mu.Lock() 40 defer d.mu.Unlock() 41 42 if d.stats == nil { 43 return fmt.Errorf("result stats is not set, result was not completed") 44 } 45 46 results := &replyfmt.RPCResults{ 47 Agent: d.stats.Agent(), 48 Action: d.stats.Action(), 49 Replies: d.rpcreplies, 50 Stats: d.stats, 51 } 52 53 addl, err := d.ddl.ActionInterface(d.stats.Action()) 54 if err != nil { 55 return err 56 } 57 58 switch format { 59 case JSONFormat: 60 return results.RenderJSON(w, addl) 61 case TableFormat: 62 return results.RenderTable(w, addl) 63 case TXTFooter: 64 results.RenderTXTFooter(w, verbose) 65 return nil 66 default: 67 return results.RenderTXT(w, addl, verbose, silent, replyfmt.DisplayMode(displayMode), colorize, log) 68 } 69 } 70 71 // Stats is the rpc request stats 72 func (d *{{ .ActionName | SnakeToCamel }}Result) Stats() Stats { 73 return d.stats 74 } 75 76 // ResultDetails is the details about the request 77 func (d *{{ .ActionName | SnakeToCamel }}Output) ResultDetails() *ResultDetails { 78 return d.details 79 } 80 81 // HashMap is the raw output data 82 func (d *{{ .ActionName | SnakeToCamel }}Output) HashMap() map[string]any { 83 return d.reply 84 } 85 86 // JSON is the JSON representation of the output data 87 func (d *{{ .ActionName | SnakeToCamel }}Output) JSON() ([]byte, error) { 88 return json.Marshal(d.reply) 89 } 90 91 // Parse{{ .ActionName | SnakeToCamel }}Output parses the result value from the {{ .ActionName | SnakeToCamel }} action into target 92 func (d *{{ $.ActionName | SnakeToCamel }}Output) Parse{{ .ActionName | SnakeToCamel }}Output(target any) error { 93 j, err := d.JSON() 94 if err != nil { 95 return fmt.Errorf("could not access payload: %s", err) 96 } 97 98 err = json.Unmarshal(j, target) 99 if err != nil { 100 return fmt.Errorf("could not unmarshal JSON payload: %s", err) 101 } 102 103 return nil 104 } 105 106 // Do performs the request 107 func (d *{{ .ActionName | SnakeToCamel }}Requester) Do(ctx context.Context) (*{{ .ActionName | SnakeToCamel }}Result, error) { 108 dres := &{{ .ActionName | SnakeToCamel }}Result{ddl: d.r.client.ddl} 109 110 addl, err := dres.ddl.ActionInterface(d.r.action) 111 if err != nil { 112 return nil, err 113 } 114 115 handler := func(pr protocol.Reply, r *rpcclient.RPCReply) { 116 // filtered by expr filter 117 if r ==nil { 118 return 119 } 120 121 output := &{{ .ActionName | SnakeToCamel }}Output{ 122 reply: make(map[string]any), 123 details: &ResultDetails{ 124 sender: pr.SenderID(), 125 code: int(r.Statuscode), 126 message: r.Statusmsg, 127 ts: pr.Time(), 128 }, 129 } 130 131 addl.SetOutputDefaults(output.reply) 132 133 err := json.Unmarshal(r.Data, &output.reply) 134 if err != nil { 135 d.r.client.errorf("Could not decode reply from %s: %s", pr.SenderID(), err) 136 } 137 138 // caller wants a channel so we dont return a resultset too (lots of memory etc) 139 // this is unused now, no support for setting a channel 140 if d.outc != nil { 141 d.outc <- output 142 return 143 } 144 145 // else prepare our result set 146 dres.mu.Lock() 147 dres.outputs = append(dres.outputs, output) 148 dres.rpcreplies = append(dres.rpcreplies, &replyfmt.RPCReply{ 149 Sender: pr.SenderID(), 150 RPCReply: r, 151 }) 152 dres.mu.Unlock() 153 } 154 155 res, err := d.r.do(ctx, handler) 156 if err != nil { 157 return nil, err 158 } 159 160 dres.stats = res 161 162 return dres, nil 163 } 164 165 // AllOutputs provide access to all outputs 166 func (d *{{ .ActionName | SnakeToCamel }}Result) AllOutputs() []*{{ .ActionName | SnakeToCamel }}Output { 167 return d.outputs 168 } 169 170 // EachOutput iterates over all results received 171 func (d *{{ .ActionName | SnakeToCamel }}Result) EachOutput(h func(r *{{ .ActionName | SnakeToCamel }}Output)) { 172 for _, resp := range d.outputs { 173 h(resp) 174 } 175 } 176 177 {{ range $name, $input := .OptionalInputs }} 178 // {{ $name | SnakeToCamel }} is an optional input to the {{ $.ActionName | ToLower }} action 179 // 180 // Description: {{ $input.Description }} 181 func (d *{{ $.ActionName | SnakeToCamel }}Requester) {{ $name | SnakeToCamel }}(v {{ ChoriaTypeToGoType $input.Type }}) *{{ $.ActionName | SnakeToCamel }}Requester { 182 d.r.args["{{ $name | ToLower }}"] = v 183 184 return d 185 } 186 {{ end }} 187 {{ range $name, $output := .Outputs }} 188 {{- $return_type := $output.Type | ChoriaTypeToGoType -}} 189 // {{ $name | SnakeToCamel }} is the value of the {{ $name }} output 190 // 191 // Description: {{ $output.Description }} 192 func (d *{{ $.ActionName | SnakeToCamel }}Output) {{ $name | SnakeToCamel }}() {{ $return_type }} { 193 {{- if eq "any" $return_type -}} 194 val, ok := d.reply["{{ $name }}"] 195 if !ok || val == nil { 196 // we have to avoid returning nil.(any) 197 return nil 198 } 199 {{- else -}} 200 val := d.reply["{{ $name }}"] 201 {{ end }} 202 203 {{ if eq "any" $return_type -}} 204 return val 205 {{ else -}} 206 return {{ ChoriaTypeToValOfType $output.Type }} 207 {{ end }} 208 } 209 {{ end }}