Write dispatcher, change SetOption arguments

This commit is contained in:
Ethan Frey
2017-07-04 12:22:06 +02:00
parent 9cd303d1fd
commit fcab8ac901
13 changed files with 215 additions and 34 deletions
+94
View File
@@ -0,0 +1,94 @@
package stack
import (
"fmt"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/types"
)
const (
NameDispatcher = "disp"
)
// Dispatcher grabs a bunch of Dispatchables and groups them into one Handler.
//
// It will route tx to the proper locations and also allows them to call each
// other synchronously through the same tx methods.
type Dispatcher struct {
routes map[string]Dispatchable
}
func NewDispatcher(routes ...Dispatchable) *Dispatcher {
d := &Dispatcher{}
d.AddRoutes(routes...)
return d
}
var _ basecoin.Handler = new(Dispatcher)
// AddRoutes registers all these dispatchable choices under their subdomains
//
// Panics on attempt to double-register a route name, as this is a configuration error.
// Should I retrun an error instead?
func (d *Dispatcher) AddRoutes(routes ...Dispatchable) {
for _, r := range routes {
name := r.Name()
if _, ok := d.routes[name]; ok {
panic(fmt.Sprintf("%s already registered with dispatcher", name))
}
d.routes[name] = r
}
}
func (d *Dispatcher) Name() string {
return NameDispatcher
}
func (d *Dispatcher) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
r, err := d.lookupTx(tx)
if err != nil {
return res, err
}
// TODO: callback
return r.CheckTx(ctx, store, tx, nil)
}
func (d *Dispatcher) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
r, err := d.lookupTx(tx)
if err != nil {
return res, err
}
// TODO: callback
return r.DeliverTx(ctx, store, tx, nil)
}
func (d *Dispatcher) SetOption(l log.Logger, store types.KVStore, module, key, value string) (string, error) {
r, err := d.lookupModule(module)
if err != nil {
return "", err
}
// TODO: callback
return r.SetOption(l, store, module, key, value, nil)
}
func (d *Dispatcher) lookupTx(tx basecoin.Tx) (Dispatchable, error) {
// TODO
name := "foo"
r, ok := d.routes[name]
if !ok {
return nil, errors.ErrUnknownTxType(tx)
}
return r, nil
}
func (d *Dispatcher) lookupModule(name string) (Dispatchable, error) {
r, ok := d.routes[name]
if !ok {
return nil, errors.ErrUnknownModule(name)
}
return r, nil
}
+43 -6
View File
@@ -39,13 +39,13 @@ func (d DeliverMiddleFunc) DeliverTx(ctx basecoin.Context, store types.KVStore,
}
type SetOptionMiddle interface {
SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error)
SetOption(l log.Logger, store types.KVStore, module, key, value string, next basecoin.SetOptioner) (string, error)
}
type SetOptionMiddleFunc func(log.Logger, types.KVStore, string, string, basecoin.SetOptioner) (string, error)
type SetOptionMiddleFunc func(log.Logger, types.KVStore, string, string, string, basecoin.SetOptioner) (string, error)
func (c SetOptionMiddleFunc) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
return c(l, store, key, value, next)
func (c SetOptionMiddleFunc) SetOption(l log.Logger, store types.KVStore, module, key, value string, next basecoin.SetOptioner) (string, error) {
return c(l, store, module, key, value, next)
}
// holders
@@ -63,6 +63,43 @@ func (_ PassDeliver) DeliverTx(ctx basecoin.Context, store types.KVStore, tx bas
type PassOption struct{}
func (_ PassOption) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
return next.SetOption(l, store, key, value)
func (_ PassOption) SetOption(l log.Logger, store types.KVStore, module, key, value string, next basecoin.SetOptioner) (string, error) {
return next.SetOption(l, store, module, key, value)
}
// Dispatchable is like middleware, except the meaning of "next" is different.
// Whereas in the middleware, it is the next handler that we should pass the same tx into,
// for dispatchers, it is a dispatcher, which it can use to
type Dispatchable interface {
Middleware
AssertDispatcher()
}
// WrapHandler turns a basecoin.Handler into a Dispatchable interface
func WrapHandler(h basecoin.Handler) Dispatchable {
return wrapped{h}
}
type wrapped struct {
h basecoin.Handler
}
var _ Dispatchable = wrapped{}
func (w wrapped) AssertDispatcher() {}
func (w wrapped) Name() string {
return w.h.Name()
}
func (w wrapped) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, _ basecoin.Checker) (basecoin.Result, error) {
return w.h.CheckTx(ctx, store, tx)
}
func (w wrapped) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, _ basecoin.Deliver) (basecoin.Result, error) {
return w.h.DeliverTx(ctx, store, tx)
}
func (w wrapped) SetOption(l log.Logger, store types.KVStore, module, key, value string, _ basecoin.SetOptioner) (string, error) {
return w.h.SetOption(l, store, module, key, value)
}
+3 -3
View File
@@ -50,12 +50,12 @@ func (_ Logger) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin
return
}
func (_ Logger) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
func (_ Logger) SetOption(l log.Logger, store types.KVStore, module, key, value string, next basecoin.SetOptioner) (string, error) {
start := time.Now()
res, err := next.SetOption(l, store, key, value)
res, err := next.SetOption(l, store, module, key, value)
delta := time.Now().Sub(start)
// TODO: log the value being set also?
l = l.With("duration", micros(delta)).With("key", key)
l = l.With("duration", micros(delta)).With("mod", module).With("key", key)
if err == nil {
l.Info("SetOption", "log", res)
} else {
+2 -2
View File
@@ -39,8 +39,8 @@ func (m *middleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx bas
return m.middleware.DeliverTx(ctx, store, tx, next)
}
func (m *middleware) SetOption(l log.Logger, store types.KVStore, key, value string) (string, error) {
return m.middleware.SetOption(l, store, key, value, m.next)
func (m *middleware) SetOption(l log.Logger, store types.KVStore, module, key, value string) (string, error) {
return m.middleware.SetOption(l, store, module, key, value, m.next)
}
// Stack is the entire application stack
+2 -2
View File
@@ -41,13 +41,13 @@ func (_ Recovery) DeliverTx(ctx basecoin.Context, store types.KVStore, tx baseco
return next.DeliverTx(ctx, store, tx)
}
func (_ Recovery) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (log string, err error) {
func (_ Recovery) SetOption(l log.Logger, store types.KVStore, module, key, value string, next basecoin.SetOptioner) (log string, err error) {
defer func() {
if r := recover(); r != nil {
err = normalizePanic(r)
}
}()
return next.SetOption(l, store, key, value)
return next.SetOption(l, store, module, key, value)
}
// normalizePanic makes sure we can get a nice TMError (with stack) out of it