stack.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package middleware
  2. import (
  3. "context"
  4. "io"
  5. "strings"
  6. )
  7. // Stack provides protocol and transport agnostic set of middleware split into
  8. // distinct steps. Steps have specific transitions between them, that are
  9. // managed by the individual step.
  10. //
  11. // Steps are composed as middleware around the underlying handler in the
  12. // following order:
  13. //
  14. // Initialize -> Serialize -> Build -> Finalize -> Deserialize -> Handler
  15. //
  16. // Any middleware within the chain may choose to stop and return an error or
  17. // response. Since the middleware decorate the handler like a call stack, each
  18. // middleware will receive the result of the next middleware in the chain.
  19. // Middleware that does not need to react to an input, or result must forward
  20. // along the input down the chain, or return the result back up the chain.
  21. //
  22. // Initialize <- Serialize -> Build -> Finalize <- Deserialize <- Handler
  23. type Stack struct {
  24. // Initialize prepares the input, and sets any default parameters as
  25. // needed, (e.g. idempotency token, and presigned URLs).
  26. //
  27. // Takes Input Parameters, and returns result or error.
  28. //
  29. // Receives result or error from Serialize step.
  30. Initialize *InitializeStep
  31. // Serialize serializes the prepared input into a data structure that can be consumed
  32. // by the target transport's message, (e.g. REST-JSON serialization)
  33. //
  34. // Converts Input Parameters into a Request, and returns the result or error.
  35. //
  36. // Receives result or error from Build step.
  37. Serialize *SerializeStep
  38. // Build adds additional metadata to the serialized transport message
  39. // (e.g. HTTP's Content-Length header, or body checksum). Decorations and
  40. // modifications to the message should be copied to all message attempts.
  41. //
  42. // Takes Request, and returns result or error.
  43. //
  44. // Receives result or error from Finalize step.
  45. Build *BuildStep
  46. // Finalize performs final preparations needed before sending the message. The
  47. // message should already be complete by this stage, and is only alternated
  48. // to meet the expectations of the recipient (e.g. Retry and AWS SigV4
  49. // request signing)
  50. //
  51. // Takes Request, and returns result or error.
  52. //
  53. // Receives result or error from Deserialize step.
  54. Finalize *FinalizeStep
  55. // Deserialize reacts to the handler's response returned by the recipient of the request
  56. // message. Deserializes the response into a structured type or error above
  57. // stacks can react to.
  58. //
  59. // Should only forward Request to underlying handler.
  60. //
  61. // Takes Request, and returns result or error.
  62. //
  63. // Receives raw response, or error from underlying handler.
  64. Deserialize *DeserializeStep
  65. id string
  66. }
  67. // NewStack returns an initialize empty stack.
  68. func NewStack(id string, newRequestFn func() interface{}) *Stack {
  69. return &Stack{
  70. id: id,
  71. Initialize: NewInitializeStep(),
  72. Serialize: NewSerializeStep(newRequestFn),
  73. Build: NewBuildStep(),
  74. Finalize: NewFinalizeStep(),
  75. Deserialize: NewDeserializeStep(),
  76. }
  77. }
  78. // ID returns the unique ID for the stack as a middleware.
  79. func (s *Stack) ID() string { return s.id }
  80. // HandleMiddleware invokes the middleware stack decorating the next handler.
  81. // Each step of stack will be invoked in order before calling the next step.
  82. // With the next handler call last.
  83. //
  84. // The input value must be the input parameters of the operation being
  85. // performed.
  86. //
  87. // Will return the result of the operation, or error.
  88. func (s *Stack) HandleMiddleware(ctx context.Context, input interface{}, next Handler) (
  89. output interface{}, metadata Metadata, err error,
  90. ) {
  91. h := DecorateHandler(next,
  92. s.Initialize,
  93. s.Serialize,
  94. s.Build,
  95. s.Finalize,
  96. s.Deserialize,
  97. )
  98. return h.Handle(ctx, input)
  99. }
  100. // List returns a list of all middleware in the stack by step.
  101. func (s *Stack) List() []string {
  102. var l []string
  103. l = append(l, s.id)
  104. l = append(l, s.Initialize.ID())
  105. l = append(l, s.Initialize.List()...)
  106. l = append(l, s.Serialize.ID())
  107. l = append(l, s.Serialize.List()...)
  108. l = append(l, s.Build.ID())
  109. l = append(l, s.Build.List()...)
  110. l = append(l, s.Finalize.ID())
  111. l = append(l, s.Finalize.List()...)
  112. l = append(l, s.Deserialize.ID())
  113. l = append(l, s.Deserialize.List()...)
  114. return l
  115. }
  116. func (s *Stack) String() string {
  117. var b strings.Builder
  118. w := &indentWriter{w: &b}
  119. w.WriteLine(s.id)
  120. w.Push()
  121. writeStepItems(w, s.Initialize)
  122. writeStepItems(w, s.Serialize)
  123. writeStepItems(w, s.Build)
  124. writeStepItems(w, s.Finalize)
  125. writeStepItems(w, s.Deserialize)
  126. return b.String()
  127. }
  128. type stackStepper interface {
  129. ID() string
  130. List() []string
  131. }
  132. func writeStepItems(w *indentWriter, s stackStepper) {
  133. type lister interface {
  134. List() []string
  135. }
  136. w.WriteLine(s.ID())
  137. w.Push()
  138. defer w.Pop()
  139. // ignore stack to prevent circular iterations
  140. if _, ok := s.(*Stack); ok {
  141. return
  142. }
  143. for _, id := range s.List() {
  144. w.WriteLine(id)
  145. }
  146. }
  147. type stringWriter interface {
  148. io.Writer
  149. WriteString(string) (int, error)
  150. WriteRune(rune) (int, error)
  151. }
  152. type indentWriter struct {
  153. w stringWriter
  154. depth int
  155. }
  156. const indentDepth = "\t\t\t\t\t\t\t\t\t\t"
  157. func (w *indentWriter) Push() {
  158. w.depth++
  159. }
  160. func (w *indentWriter) Pop() {
  161. w.depth--
  162. if w.depth < 0 {
  163. w.depth = 0
  164. }
  165. }
  166. func (w *indentWriter) WriteLine(v string) {
  167. w.w.WriteString(indentDepth[:w.depth])
  168. v = strings.ReplaceAll(v, "\n", "\\n")
  169. v = strings.ReplaceAll(v, "\r", "\\r")
  170. w.w.WriteString(v)
  171. w.w.WriteRune('\n')
  172. }