Skip to content

Commit

Permalink
refactor(core): re-add handlers (#21575)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Sep 9, 2024
1 parent b1bf488 commit eeeb5b8
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 22 deletions.
134 changes: 120 additions & 14 deletions core/appmodule/v2/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package appmodulev2

import (
"context"
"fmt"

transaction "cosmossdk.io/core/transaction"
)
Expand All @@ -16,47 +17,152 @@ type (
PostMsgHandler = func(ctx context.Context, msg, msgResp transaction.Msg) error
)

// msg handler

// PreMsgRouter is a router that allows you to register PreMsgHandlers for specific message types.
type PreMsgRouter interface {
// RegisterPreHandler will register a specific message handler hooking into the message with
// the provided name.
RegisterPreHandler(msgName string, handler PreMsgHandler)
RegisterPreMsgHandler(msgName string, handler PreMsgHandler)
// RegisterGlobalPreHandler will register a global message handler hooking into any message
// being executed.
RegisterGlobalPreHandler(handler PreMsgHandler)
RegisterGlobalPreMsgHandler(handler PreMsgHandler)
}

// HasPreMsgHandlers is an interface that modules must implement if they want to register PreMsgHandlers.
type HasPreMsgHandlers interface {
RegisterPreMsgHandlers(router PreMsgRouter)
}

type MsgRouter interface {
Register(msgName string, handler Handler)
}
// RegisterMsgPreHandler is a helper function that modules can use to not lose type safety when registering PreMsgHandler to the
// PreMsgRouter. Example usage:
// ```go
//
// func (h Handlers) BeforeSend(ctx context.Context, req *types.MsgSend) error {
// ... before send logic ...
// }
//
// func (m Module) RegisterPreMsgHandlers(router appmodule.PreMsgRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// appmodule.RegisterMsgPreHandler(router, gogoproto.MessageName(types.MsgSend{}), handlers.BeforeSend)
// }
//
// ```
func RegisterMsgPreHandler[Req transaction.Msg](
router PreMsgRouter,
msgName string,
handler func(ctx context.Context, msg Req) error,
) {
untypedHandler := func(ctx context.Context, m transaction.Msg) error {
typed, ok := m.(Req)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
return handler(ctx, typed)
}

type HasMsgHandlers interface {
RegisterMsgHandlers(router MsgRouter)
router.RegisterPreMsgHandler(msgName, untypedHandler)
}

// PostMsgRouter is a router that allows you to register PostMsgHandlers for specific message types.
type PostMsgRouter interface {
// RegisterPostHandler will register a specific message handler hooking after the execution of message with
// the provided name.
RegisterPostHandler(msgName string, handler PostMsgHandler)
RegisterPostMsgHandler(msgName string, handler PostMsgHandler)
// RegisterGlobalPostHandler will register a global message handler hooking after the execution of any message.
RegisterGlobalPostHandler(handler PostMsgHandler)
RegisterGlobalPostMsgHandler(handler PostMsgHandler)
}

// HasPostMsgHandlers is an interface that modules must implement if they want to register PostMsgHandlers.
type HasPostMsgHandlers interface {
RegisterPostMsgHandlers(router PostMsgRouter)
}

// query handler
// RegisterPostHandler is a helper function that modules can use to not lose type safety when registering handlers to the
// PostMsgRouter. Example usage:
// ```go
//
// func (h Handlers) AfterSend(ctx context.Context, req *types.MsgSend, resp *types.MsgSendResponse) error {
// ... query logic ...
// }
//
// func (m Module) RegisterPostMsgHandlers(router appmodule.PostMsgRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// appmodule.RegisterPostMsgHandler(router, gogoproto.MessageName(types.MsgSend{}), handlers.AfterSend)
// }
//
// ```
func RegisterPostMsgHandler[Req, Resp transaction.Msg](
router PostMsgRouter,
msgName string,
handler func(ctx context.Context, msg Req, msgResp Resp) error,
) {
untypedHandler := func(ctx context.Context, m, mResp transaction.Msg) error {
typed, ok := m.(Req)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
typedResp, ok := mResp.(Resp)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Resp))
}
return handler(ctx, typed, typedResp)
}

router.RegisterPostMsgHandler(msgName, untypedHandler)
}

// MsgRouter is a router that allows you to register Handlers for specific message types.
type MsgRouter = interface {
RegisterHandler(msgName string, handler Handler) error
}

type QueryRouter interface {
Register(queryName string, handler Handler)
// HasMsgHandlers is an interface that modules must implement if they want to register Handlers.
type HasMsgHandlers interface {
RegisterMsgHandlers(router MsgRouter)
}

// QueryRouter is a router that allows you to register QueryHandlers for specific query types.
type QueryRouter = MsgRouter

// HasQueryHandlers is an interface that modules must implement if they want to register QueryHandlers.
type HasQueryHandlers interface {
RegisterQueryHandlers(router QueryRouter)
}

// RegisterMsgHandler is a helper function that modules can use to not lose type safety when registering handlers to the MsgRouter and Query Router.
// Example usage:
// ```go
//
// func (h Handlers) Mint(ctx context.Context, req *types.MsgMint) (*types.MsgMintResponse, error) {
// ... msg logic ...
// }
//
// func (h Handlers) QueryBalance(ctx context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
// ... query logic ...
// }
//
// func (m Module) RegisterMsgHandlers(router appmodule.MsgRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// err := appmodule.RegisterHandler(router, gogoproto.MessageName(types.MsgMint{}), handlers.MsgMint)
// }
//
// func (m Module) RegisterQueryHandlers(router appmodule.QueryRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// err := appmodule.RegisterHandler(router, gogoproto.MessageName(types.QueryBalanceRequest{}), handlers.QueryBalance)
// }
//
// ```
func RegisterHandler[Req, Resp transaction.Msg](
router MsgRouter,
msgName string,
handler func(ctx context.Context, msg Req) (msgResp Resp, err error),
) error {
untypedHandler := func(ctx context.Context, m transaction.Msg) (transaction.Msg, error) {
typed, ok := m.(Req)
if !ok {
return nil, fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
return handler(ctx, typed)
}

return router.RegisterHandler(msgName, untypedHandler)
}
13 changes: 9 additions & 4 deletions runtime/v2/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,14 +604,19 @@ func registerServices[T transaction.Tx](s hasServicesV1, app *App[T], registry *
err: nil,
}

err := s.RegisterServices(c)
if err != nil {
if err := s.RegisterServices(c); err != nil {
return fmt.Errorf("unable to register services: %w", err)
}

if c.err != nil {
app.logger.Warn("error registering services", "error", c.err)
}

// merge maps
for path, decoder := range c.grpcQueryDecoders {
app.GRPCMethodsToMessageMap[path] = decoder
}

return nil
}

Expand Down Expand Up @@ -654,7 +659,7 @@ func (c *configurator) registerQueryHandlers(sd *grpc.ServiceDesc, ss interface{
// TODO(tip): what if a query is not deterministic?
requestFullName, err := registerMethod(c.stfQueryRouter, sd, md, ss)
if err != nil {
return fmt.Errorf("unable to register query handler %s: %w", md.MethodName, err)
return fmt.Errorf("unable to register query handler %s.%s: %w", sd.ServiceName, md.MethodName, err)
}

// register gRPC query method.
Expand All @@ -675,7 +680,7 @@ func (c *configurator) registerMsgHandlers(sd *grpc.ServiceDesc, ss interface{})
for _, md := range sd.Methods {
_, err := registerMethod(c.stfMsgRouter, sd, md, ss)
if err != nil {
return fmt.Errorf("unable to register msg handler %s: %w", md.MethodName, err)
return fmt.Errorf("unable to register msg handler %s.%s: %w", sd.ServiceName, md.MethodName, err)
}
}
return nil
Expand Down
8 changes: 4 additions & 4 deletions server/v2/stf/stf_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ func (b *MsgRouterBuilder) RegisterHandler(msgType string, handler appmodulev2.H
return nil
}

func (b *MsgRouterBuilder) RegisterGlobalPreHandler(handler appmodulev2.PreMsgHandler) {
func (b *MsgRouterBuilder) RegisterGlobalPreMsgHandler(handler appmodulev2.PreMsgHandler) {
b.globalPreHandlers = append(b.globalPreHandlers, handler)
}

func (b *MsgRouterBuilder) RegisterPreHandler(msgType string, handler appmodulev2.PreMsgHandler) {
func (b *MsgRouterBuilder) RegisterPreMsgHandler(msgType string, handler appmodulev2.PreMsgHandler) {
b.preHandlers[msgType] = append(b.preHandlers[msgType], handler)
}

func (b *MsgRouterBuilder) RegisterPostHandler(msgType string, handler appmodulev2.PostMsgHandler) {
func (b *MsgRouterBuilder) RegisterPostMsgHandler(msgType string, handler appmodulev2.PostMsgHandler) {
b.postHandlers[msgType] = append(b.postHandlers[msgType], handler)
}

func (b *MsgRouterBuilder) RegisterGlobalPostHandler(handler appmodulev2.PostMsgHandler) {
func (b *MsgRouterBuilder) RegisterGlobalPostMsgHandler(handler appmodulev2.PostMsgHandler) {
b.globalPostHandlers = append(b.globalPostHandlers, handler)
}

Expand Down

0 comments on commit eeeb5b8

Please sign in to comment.