github.com/aavshr/aws-sdk-go@v1.41.3/private/model/api/eventstream.go (about)

     1  //go:build codegen
     2  // +build codegen
     3  
     4  package api
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"text/template"
    10  )
    11  
    12  // EventStreamAPI provides details about the event stream async API and
    13  // associated EventStream shapes.
    14  type EventStreamAPI struct {
    15  	API          *API
    16  	Operation    *Operation
    17  	Name         string
    18  	InputStream  *EventStream
    19  	OutputStream *EventStream
    20  	RequireHTTP2 bool
    21  
    22  	// The eventstream generated code was generated with an older model that
    23  	// does not scale with bi-directional models. This drives the need to
    24  	// expose the output shape's event stream member as an exported member.
    25  	Legacy bool
    26  }
    27  
    28  func (es *EventStreamAPI) StreamInputEventTypeGetterName() string {
    29  	return "eventTypeFor" + es.Name + "InputEvent"
    30  }
    31  func (es *EventStreamAPI) StreamOutputUnmarshalerForEventName() string {
    32  	return "eventTypeFor" + es.Name + "OutputEvent"
    33  }
    34  
    35  // EventStream represents a single eventstream group (input/output) and the
    36  // modeled events that are known for the stream.
    37  type EventStream struct {
    38  	Name       string
    39  	Shape      *Shape
    40  	Events     []*Event
    41  	Exceptions []*Event
    42  }
    43  
    44  func (es *EventStream) EventGroupName() string {
    45  	return es.Name + "Event"
    46  }
    47  
    48  func (es *EventStream) StreamWriterAPIName() string {
    49  	return es.Name + "Writer"
    50  }
    51  
    52  func (es *EventStream) StreamWriterImplName() string {
    53  	return "write" + es.Name
    54  }
    55  
    56  func (es *EventStream) StreamEventTypeGetterName() string {
    57  	return "eventTypeFor" + es.Name + "Event"
    58  }
    59  
    60  func (es *EventStream) StreamReaderAPIName() string {
    61  	return es.Name + "Reader"
    62  }
    63  
    64  func (es *EventStream) StreamReaderImplName() string {
    65  	return "read" + es.Name
    66  }
    67  func (es *EventStream) StreamReaderImplConstructorName() string {
    68  	return "newRead" + es.Name
    69  }
    70  
    71  func (es *EventStream) StreamUnmarshalerForEventName() string {
    72  	return "unmarshalerFor" + es.Name + "Event"
    73  }
    74  
    75  func (es *EventStream) StreamUnknownEventName() string {
    76  	return es.Name + "UnknownEvent"
    77  }
    78  
    79  // Event is a single EventStream event that can be sent or received in an
    80  // EventStream.
    81  type Event struct {
    82  	Name    string
    83  	Shape   *Shape
    84  	For     *EventStream
    85  	Private bool
    86  }
    87  
    88  // ShapeDoc returns the docstring for the EventStream API.
    89  func (esAPI *EventStreamAPI) ShapeDoc() string {
    90  	tmpl := template.Must(template.New("eventStreamShapeDoc").Parse(`
    91  {{- $.Name }} provides handling of EventStreams for
    92  the {{ $.Operation.ExportedName }} API.
    93  
    94  {{- if $.OutputStream }}
    95  
    96  Use this type to receive {{ $.OutputStream.Name }} events. The events
    97  can be read from the stream.
    98  
    99  The events that can be received are:
   100  {{- range $_, $event := $.OutputStream.Events }}
   101      * {{ $event.Shape.ShapeName }}
   102  {{- end }}
   103  
   104  {{- end }}
   105  
   106  {{- if $.InputStream }}
   107  
   108  Use this type to send {{ $.InputStream.Name }} events. The events
   109  can be written to the stream.
   110  
   111  The events that can be sent are:
   112  {{ range $_, $event := $.InputStream.Events -}}
   113      * {{ $event.Shape.ShapeName }}
   114  {{- end }}
   115  
   116  {{- end }}`))
   117  
   118  	var w bytes.Buffer
   119  	if err := tmpl.Execute(&w, esAPI); err != nil {
   120  		panic(fmt.Sprintf("failed to generate eventstream shape template for %v, %v",
   121  			esAPI.Operation.ExportedName, err))
   122  	}
   123  
   124  	return commentify(w.String())
   125  }
   126  
   127  func hasEventStream(topShape *Shape) bool {
   128  	for _, ref := range topShape.MemberRefs {
   129  		if ref.Shape.IsEventStream {
   130  			return true
   131  		}
   132  	}
   133  
   134  	return false
   135  }
   136  
   137  func eventStreamAPIShapeRefDoc(refName string) string {
   138  	return commentify(fmt.Sprintf("Use %s to use the API's stream.", refName))
   139  }
   140  
   141  func (a *API) setupEventStreams() error {
   142  	streams := EventStreams{}
   143  
   144  	for opName, op := range a.Operations {
   145  		inputRef := getEventStreamMember(op.InputRef.Shape)
   146  		outputRef := getEventStreamMember(op.OutputRef.Shape)
   147  
   148  		if inputRef == nil && outputRef == nil {
   149  			continue
   150  		}
   151  		if inputRef != nil && outputRef == nil {
   152  			return fmt.Errorf("event stream input only stream not supported for protocol %s, %s, %v",
   153  				a.NiceName(), opName, a.Metadata.Protocol)
   154  		}
   155  		switch a.Metadata.Protocol {
   156  		case `rest-json`, `rest-xml`, `json`:
   157  		default:
   158  			return UnsupportedAPIModelError{
   159  				Err: fmt.Errorf("EventStream not supported for protocol %s, %s, %v",
   160  					a.NiceName(), opName, a.Metadata.Protocol),
   161  			}
   162  		}
   163  
   164  		var inputStream *EventStream
   165  		if inputRef != nil {
   166  			inputStream = streams.GetStream(op.InputRef.Shape, inputRef.Shape)
   167  			inputStream.Shape.IsInputEventStream = true
   168  		}
   169  
   170  		var outputStream *EventStream
   171  		if outputRef != nil {
   172  			outputStream = streams.GetStream(op.OutputRef.Shape, outputRef.Shape)
   173  			outputStream.Shape.IsOutputEventStream = true
   174  		}
   175  
   176  		requireHTTP2 := op.API.Metadata.ProtocolSettings.HTTP2 == "eventstream" &&
   177  			inputStream != nil && outputStream != nil
   178  
   179  		a.HasEventStream = true
   180  		op.EventStreamAPI = &EventStreamAPI{
   181  			API:          a,
   182  			Operation:    op,
   183  			Name:         op.ExportedName + "EventStream",
   184  			InputStream:  inputStream,
   185  			OutputStream: outputStream,
   186  			Legacy:       isLegacyEventStream(op),
   187  			RequireHTTP2: requireHTTP2,
   188  		}
   189  		op.OutputRef.Shape.OutputEventStreamAPI = op.EventStreamAPI
   190  
   191  		if s, ok := a.Shapes[op.EventStreamAPI.Name]; ok {
   192  			newName := op.EventStreamAPI.Name + "Data"
   193  			if _, ok := a.Shapes[newName]; ok {
   194  				panic(fmt.Sprintf(
   195  					"%s: attempting to rename %s to %s, but shape with that name already exists",
   196  					a.NiceName(), op.EventStreamAPI.Name, newName))
   197  			}
   198  			s.Rename(newName)
   199  		}
   200  	}
   201  
   202  	return nil
   203  }
   204  
   205  // EventStreams is a map of streams for the API shared across all operations.
   206  // Ensurs that no stream is duplicated.
   207  type EventStreams map[*Shape]*EventStream
   208  
   209  // GetStream returns an EventStream for the operations top level shape, and
   210  // member reference to the stream shape.
   211  func (es *EventStreams) GetStream(topShape *Shape, streamShape *Shape) *EventStream {
   212  	var stream *EventStream
   213  	if v, ok := (*es)[streamShape]; ok {
   214  		stream = v
   215  	} else {
   216  		stream = setupEventStream(streamShape)
   217  		(*es)[streamShape] = stream
   218  	}
   219  
   220  	if topShape.API.Metadata.Protocol == "json" {
   221  		if topShape.EventFor == nil {
   222  			topShape.EventFor = map[string]*EventStream{}
   223  		}
   224  		topShape.EventFor[stream.Name] = stream
   225  	}
   226  
   227  	return stream
   228  }
   229  
   230  var legacyEventStream = map[string]map[string]struct{}{
   231  	"s3": {
   232  		"SelectObjectContent": struct{}{},
   233  	},
   234  	"kinesis": {
   235  		"SubscribeToShard": struct{}{},
   236  	},
   237  }
   238  
   239  func isLegacyEventStream(op *Operation) bool {
   240  	if s, ok := legacyEventStream[op.API.PackageName()]; ok {
   241  		if _, ok = s[op.ExportedName]; ok {
   242  			return true
   243  		}
   244  	}
   245  	return false
   246  }
   247  
   248  func (e EventStreamAPI) OutputMemberName() string {
   249  	if e.Legacy {
   250  		return "EventStream"
   251  	}
   252  
   253  	return "eventStream"
   254  }
   255  
   256  func getEventStreamMember(topShape *Shape) *ShapeRef {
   257  	for _, ref := range topShape.MemberRefs {
   258  		if !ref.Shape.IsEventStream {
   259  			continue
   260  		}
   261  		return ref
   262  	}
   263  
   264  	return nil
   265  }
   266  
   267  func setupEventStream(s *Shape) *EventStream {
   268  	eventStream := &EventStream{
   269  		Name:  s.ShapeName,
   270  		Shape: s,
   271  	}
   272  	s.EventStream = eventStream
   273  
   274  	for _, eventRefName := range s.MemberNames() {
   275  		eventRef := s.MemberRefs[eventRefName]
   276  		if !(eventRef.Shape.IsEvent || eventRef.Shape.Exception) {
   277  			panic(fmt.Sprintf("unexpected non-event member reference %s.%s",
   278  				s.ShapeName, eventRefName))
   279  		}
   280  
   281  		updateEventPayloadRef(eventRef.Shape)
   282  
   283  		if eventRef.Shape.EventFor == nil {
   284  			eventRef.Shape.EventFor = map[string]*EventStream{}
   285  		}
   286  		eventRef.Shape.EventFor[eventStream.Name] = eventStream
   287  
   288  		// Exceptions and events are two different lists to allow the SDK
   289  		// to easily generate code with the two handled differently.
   290  		event := &Event{
   291  			Name:  eventRefName,
   292  			Shape: eventRef.Shape,
   293  			For:   eventStream,
   294  		}
   295  		if eventRef.Shape.Exception {
   296  			eventStream.Exceptions = append(eventStream.Exceptions, event)
   297  		} else {
   298  			eventStream.Events = append(eventStream.Events, event)
   299  		}
   300  	}
   301  
   302  	return eventStream
   303  }
   304  
   305  func updateEventPayloadRef(parent *Shape) {
   306  	refName := parent.PayloadRefName()
   307  	if len(refName) == 0 {
   308  		return
   309  	}
   310  
   311  	payloadRef := parent.MemberRefs[refName]
   312  	if payloadRef.Shape.Type == "blob" {
   313  		return
   314  	}
   315  
   316  	if len(payloadRef.LocationName) != 0 {
   317  		return
   318  	}
   319  
   320  	payloadRef.LocationName = refName
   321  }