153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
package stack
|
|
|
|
import (
|
|
abci "github.com/tendermint/abci/types"
|
|
"github.com/tendermint/tmlibs/log"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk"
|
|
"github.com/cosmos/cosmos-sdk/state"
|
|
)
|
|
|
|
// middleware lets us wrap a whole stack up into one Handler
|
|
//
|
|
// heavily inspired by negroni's design
|
|
type middleware struct {
|
|
middleware Middleware
|
|
space string
|
|
allowIBC bool
|
|
next sdk.Handler
|
|
}
|
|
|
|
var _ sdk.Handler = &middleware{}
|
|
|
|
func (m *middleware) Name() string {
|
|
return m.middleware.Name()
|
|
}
|
|
|
|
func (m *middleware) wrapCtx(ctx sdk.Context) sdk.Context {
|
|
if m.allowIBC {
|
|
return withIBC(ctx)
|
|
}
|
|
return withApp(ctx, m.space)
|
|
}
|
|
|
|
// CheckTx always returns an empty success tx
|
|
func (m *middleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (sdk.CheckResult, error) {
|
|
// make sure we pass in proper context to child
|
|
next := secureCheck(m.next, ctx)
|
|
// set the permissions for this app
|
|
ctx = m.wrapCtx(ctx)
|
|
store = stateSpace(store, m.space)
|
|
|
|
return m.middleware.CheckTx(ctx, store, tx, next)
|
|
}
|
|
|
|
// DeliverTx always returns an empty success tx
|
|
func (m *middleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) {
|
|
// make sure we pass in proper context to child
|
|
next := secureDeliver(m.next, ctx)
|
|
// set the permissions for this app
|
|
ctx = m.wrapCtx(ctx)
|
|
store = stateSpace(store, m.space)
|
|
|
|
return m.middleware.DeliverTx(ctx, store, tx, next)
|
|
}
|
|
|
|
func (m *middleware) InitState(l log.Logger, store state.SimpleDB, module, key, value string) (string, error) {
|
|
// set the namespace for the app
|
|
store = stateSpace(store, m.space)
|
|
|
|
return m.middleware.InitState(l, store, module, key, value, m.next)
|
|
}
|
|
|
|
func (m *middleware) InitValidate(l log.Logger, store state.SimpleDB, vals []*abci.Validator) {
|
|
// set the namespace for the app
|
|
store = stateSpace(store, m.space)
|
|
m.middleware.InitValidate(l, store, vals, m.next)
|
|
}
|
|
|
|
// builder is used to associate info with the middleware, so we can build
|
|
// it properly
|
|
type builder struct {
|
|
middleware Middleware
|
|
stateSpace string
|
|
allowIBC bool
|
|
}
|
|
|
|
func prep(m Middleware, ibc bool) builder {
|
|
return builder{
|
|
middleware: m,
|
|
stateSpace: m.Name(),
|
|
allowIBC: ibc,
|
|
}
|
|
}
|
|
|
|
// wrap sets up the middleware with the proper options
|
|
func (b builder) wrap(next sdk.Handler) sdk.Handler {
|
|
return &middleware{
|
|
middleware: b.middleware,
|
|
space: b.stateSpace,
|
|
allowIBC: b.allowIBC,
|
|
next: next,
|
|
}
|
|
}
|
|
|
|
// Stack is the entire application stack
|
|
type Stack struct {
|
|
middles []builder
|
|
handler sdk.Handler
|
|
sdk.Handler // the compiled version, which we expose
|
|
}
|
|
|
|
var _ sdk.Handler = &Stack{}
|
|
|
|
// New prepares a middleware stack, you must `.Use()` a Handler
|
|
// before you can execute it.
|
|
func New(middlewares ...Middleware) *Stack {
|
|
stack := new(Stack)
|
|
return stack.Apps(middlewares...)
|
|
}
|
|
|
|
// Apps adds the following Middlewares as typical application
|
|
// middleware to the stack (limit permission to one app)
|
|
func (s *Stack) Apps(middlewares ...Middleware) *Stack {
|
|
// TODO: some wrapper...
|
|
for _, m := range middlewares {
|
|
s.middles = append(s.middles, prep(m, false))
|
|
}
|
|
return s
|
|
}
|
|
|
|
// IBC add the following middleware with permission to add cross-chain
|
|
// permissions
|
|
func (s *Stack) IBC(m Middleware) *Stack {
|
|
// TODO: some wrapper...
|
|
s.middles = append(s.middles, prep(m, true))
|
|
return s
|
|
}
|
|
|
|
// Use sets the final handler for the stack and prepares it for use
|
|
func (s *Stack) Use(handler sdk.Handler) *Stack {
|
|
if handler == nil {
|
|
panic("Cannot have a Stack without an end handler")
|
|
}
|
|
s.handler = handler
|
|
s.Handler = build(s.middles, s.handler)
|
|
return s
|
|
}
|
|
|
|
// Dispatch is like Use, but a convenience method to construct a
|
|
// dispatcher with a set of modules to route.
|
|
func (s *Stack) Dispatch(routes ...Dispatchable) *Stack {
|
|
d := NewDispatcher(routes...)
|
|
return s.Use(d)
|
|
}
|
|
|
|
func build(mid []builder, end sdk.Handler) sdk.Handler {
|
|
if len(mid) == 0 {
|
|
return end
|
|
}
|
|
next := build(mid[1:], end)
|
|
return mid[0].wrap(next)
|
|
}
|