2021-06-11 16:30:05 +03:00
package tcp
import (
2024-02-07 19:14:07 +03:00
"errors"
2021-06-11 16:30:05 +03:00
)
// Constructor A constructor for a piece of TCP middleware.
// Some TCP middleware use this constructor out of the box,
// so in most cases you can just pass somepackage.New.
type Constructor func ( Handler ) ( Handler , error )
// Chain is a chain for TCP handlers.
// Chain acts as a list of tcp.Handler constructors.
// Chain is effectively immutable:
// once created, it will always hold
// the same set of constructors in the same order.
type Chain struct {
constructors [ ] Constructor
}
// NewChain creates a new TCP chain,
// memorizing the given list of TCP middleware constructors.
// New serves no other function,
// constructors are only called upon a call to Then().
func NewChain ( constructors ... Constructor ) Chain {
return Chain { constructors : constructors }
}
// Then adds an handler at the end of the chain.
func ( c Chain ) Then ( h Handler ) ( Handler , error ) {
if h == nil {
2024-02-07 19:14:07 +03:00
return nil , errors . New ( "cannot add a nil handler to the chain" )
2021-06-11 16:30:05 +03:00
}
for i := range c . constructors {
handler , err := c . constructors [ len ( c . constructors ) - 1 - i ] ( h )
if err != nil {
return nil , err
}
h = handler
}
return h , nil
}
// Append extends a chain, adding the specified constructors
// as the last ones in the request flow.
//
// Append returns a new chain, leaving the original one untouched.
//
2022-07-19 19:38:09 +03:00
// stdChain := tcp.NewChain(m1, m2)
// extChain := stdChain.Append(m3, m4)
// // requests in stdChain go m1 -> m2
// // requests in extChain go m1 -> m2 -> m3 -> m4
2021-06-11 16:30:05 +03:00
func ( c Chain ) Append ( constructors ... Constructor ) Chain {
newCons := make ( [ ] Constructor , 0 , len ( c . constructors ) + len ( constructors ) )
newCons = append ( newCons , c . constructors ... )
newCons = append ( newCons , constructors ... )
return Chain { newCons }
}
// Extend extends a chain by adding the specified chain
// as the last one in the request flow.
//
// Extend returns a new chain, leaving the original one untouched.
//
2022-07-19 19:38:09 +03:00
// stdChain := tcp.NewChain(m1, m2)
// ext1Chain := tcp.NewChain(m3, m4)
// ext2Chain := stdChain.Extend(ext1Chain)
// // requests in stdChain go m1 -> m2
// // requests in ext1Chain go m3 -> m4
// // requests in ext2Chain go m1 -> m2 -> m3 -> m4
2021-06-11 16:30:05 +03:00
//
// Another example:
2022-07-19 19:38:09 +03:00
//
// aHtmlAfterNosurf := tcp.NewChain(m2)
// aHtml := tcp.NewChain(m1, func(h tcp.Handler) tcp.Handler {
// csrf := nosurf.New(h)
// csrf.SetFailureHandler(aHtmlAfterNosurf.ThenFunc(csrfFail))
// return csrf
// }).Extend(aHtmlAfterNosurf)
// // requests to aHtml hitting nosurfs success handler go m1 -> nosurf -> m2 -> target-handler
// // requests to aHtml hitting nosurfs failure handler go m1 -> nosurf -> m2 -> csrfFail
2021-06-11 16:30:05 +03:00
func ( c Chain ) Extend ( chain Chain ) Chain {
return c . Append ( chain . constructors ... )
}