github.com/aavshr/aws-sdk-go@v1.41.3/private/model/api/waiters.go (about) 1 //go:build codegen 2 // +build codegen 3 4 package api 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "os" 11 "sort" 12 "strings" 13 "text/template" 14 ) 15 16 // WaiterAcceptor is the acceptors defined in the model the SDK will use 17 // to wait on resource states with. 18 type WaiterAcceptor struct { 19 State string 20 Matcher string 21 Argument string 22 Expected interface{} 23 } 24 25 // ExpectedString returns the string that was expected by the WaiterAcceptor 26 func (a *WaiterAcceptor) ExpectedString() string { 27 switch a.Expected.(type) { 28 case string: 29 return fmt.Sprintf("%q", a.Expected) 30 default: 31 return fmt.Sprintf("%v", a.Expected) 32 } 33 } 34 35 // A Waiter is an individual waiter definition. 36 type Waiter struct { 37 Name string 38 Delay int 39 MaxAttempts int 40 OperationName string `json:"operation"` 41 Operation *Operation 42 Acceptors []WaiterAcceptor 43 } 44 45 // WaitersGoCode generates and returns Go code for each of the waiters of 46 // this API. 47 func (a *API) WaitersGoCode() string { 48 var buf bytes.Buffer 49 fmt.Fprintf(&buf, "import (\n%q\n\n%q\n%q\n)", 50 "time", 51 SDKImportRoot+"/aws", 52 SDKImportRoot+"/aws/request", 53 ) 54 55 for _, w := range a.Waiters { 56 buf.WriteString(w.GoCode()) 57 } 58 return buf.String() 59 } 60 61 // used for unmarshaling from the waiter JSON file 62 type waiterDefinitions struct { 63 *API 64 Waiters map[string]Waiter 65 } 66 67 // AttachWaiters reads a file of waiter definitions, and adds those to the API. 68 // Will panic if an error occurs. 69 func (a *API) AttachWaiters(filename string) error { 70 p := waiterDefinitions{API: a} 71 72 f, err := os.Open(filename) 73 defer f.Close() 74 if err != nil { 75 return err 76 } 77 err = json.NewDecoder(f).Decode(&p) 78 if err != nil { 79 return err 80 } 81 82 return p.setup() 83 } 84 85 func (p *waiterDefinitions) setup() error { 86 p.API.Waiters = []Waiter{} 87 i, keys := 0, make([]string, len(p.Waiters)) 88 for k := range p.Waiters { 89 keys[i] = k 90 i++ 91 } 92 sort.Strings(keys) 93 94 for _, n := range keys { 95 e := p.Waiters[n] 96 n = p.ExportableName(n) 97 e.Name = n 98 e.OperationName = p.ExportableName(e.OperationName) 99 e.Operation = p.API.Operations[e.OperationName] 100 if e.Operation == nil { 101 return fmt.Errorf("unknown operation %s for waiter %s", 102 e.OperationName, n) 103 } 104 p.API.Waiters = append(p.API.Waiters, e) 105 } 106 107 return nil 108 } 109 110 var waiterTmpls = template.Must(template.New("waiterTmpls").Funcs( 111 template.FuncMap{ 112 "titleCase": func(v string) string { 113 return strings.Title(v) 114 }, 115 }, 116 ).Parse(` 117 {{ define "waiter"}} 118 // WaitUntil{{ .Name }} uses the {{ .Operation.API.NiceName }} API operation 119 // {{ .OperationName }} to wait for a condition to be met before returning. 120 // If the condition is not met within the max attempt window, an error will 121 // be returned. 122 func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}(input {{ .Operation.InputRef.GoType }}) error { 123 return c.WaitUntil{{ .Name }}WithContext(aws.BackgroundContext(), input) 124 } 125 126 // WaitUntil{{ .Name }}WithContext is an extended version of WaitUntil{{ .Name }}. 127 // With the support for passing in a context and options to configure the 128 // Waiter and the underlying request options. 129 // 130 // The context must be non-nil and will be used for request cancellation. If 131 // the context is nil a panic will occur. In the future the SDK may create 132 // sub-contexts for http.Requests. See https://golang.org/pkg/context/ 133 // for more information on using Contexts. 134 func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}WithContext(` + 135 `ctx aws.Context, input {{ .Operation.InputRef.GoType }}, opts ...request.WaiterOption) error { 136 w := request.Waiter{ 137 Name: "WaitUntil{{ .Name }}", 138 MaxAttempts: {{ .MaxAttempts }}, 139 Delay: request.ConstantWaiterDelay({{ .Delay }} * time.Second), 140 Acceptors: []request.WaiterAcceptor{ 141 {{ range $_, $a := .Acceptors }}{ 142 State: request.{{ titleCase .State }}WaiterState, 143 Matcher: request.{{ titleCase .Matcher }}WaiterMatch, 144 {{- if .Argument }}Argument: "{{ .Argument }}",{{ end }} 145 Expected: {{ .ExpectedString }}, 146 }, 147 {{ end }} 148 }, 149 Logger: c.Config.Logger, 150 NewRequest: func(opts []request.Option) (*request.Request, error) { 151 var inCpy {{ .Operation.InputRef.GoType }} 152 if input != nil { 153 tmp := *input 154 inCpy = &tmp 155 } 156 req, _ := c.{{ .OperationName }}Request(inCpy) 157 req.SetContext(ctx) 158 req.ApplyOptions(opts...) 159 return req, nil 160 }, 161 } 162 w.ApplyOptions(opts...) 163 164 return w.WaitWithContext(ctx) 165 } 166 {{- end }} 167 168 {{ define "waiter interface" }} 169 WaitUntil{{ .Name }}({{ .Operation.InputRef.GoTypeWithPkgName }}) error 170 WaitUntil{{ .Name }}WithContext(aws.Context, {{ .Operation.InputRef.GoTypeWithPkgName }}, ...request.WaiterOption) error 171 {{- end }} 172 `)) 173 174 // InterfaceSignature returns a string representing the Waiter's interface 175 // function signature. 176 func (w *Waiter) InterfaceSignature() string { 177 var buf bytes.Buffer 178 if err := waiterTmpls.ExecuteTemplate(&buf, "waiter interface", w); err != nil { 179 panic(err) 180 } 181 182 return strings.TrimSpace(buf.String()) 183 } 184 185 // GoCode returns the generated Go code for an individual waiter. 186 func (w *Waiter) GoCode() string { 187 var buf bytes.Buffer 188 if err := waiterTmpls.ExecuteTemplate(&buf, "waiter", w); err != nil { 189 panic(err) 190 } 191 192 return buf.String() 193 }