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 }