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  }