-
Notifications
You must be signed in to change notification settings - Fork 46
/
router.go
89 lines (76 loc) · 2.63 KB
/
router.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package app
import (
"fmt"
"regexp"
"github.com/iov-one/weave"
"github.com/iov-one/weave/errors"
)
// isPath is the RegExp to ensure the routes make sense
var isPath = regexp.MustCompile(`^[a-zA-Z0-9_/]+$`).MatchString
// Router allows us to register many handlers with different
// paths and then direct each message to the proper handler.
//
// Minimal interface modeled after net/http.ServeMux
//
// TODO: look for better trie routers that handle patterns...
// maybe take code from here?
// https://github.com/julienschmidt/httprouter
// https://github.com/julienschmidt/httprouter/blob/master/tree.go
type Router struct {
routes map[string]weave.Handler
}
var _ weave.Registry = (*Router)(nil)
var _ weave.Handler = (*Router)(nil)
// NewRouter returns a new empty router instance.
func NewRouter() *Router {
return &Router{
routes: make(map[string]weave.Handler),
}
}
// Handle implements weave.Registry interface.
func (r *Router) Handle(m weave.Msg, h weave.Handler) {
path := m.Path()
if !isPath(path) {
panic(fmt.Sprintf("invalid path: %T: %s", m, path))
}
if _, ok := r.routes[path]; ok {
panic(fmt.Sprintf("re-registering route: %T: %s", m, path))
}
r.routes[path] = h
}
// handler returns the registered Handler for this path. If no path is found,
// returns a noSuchPath Handler. This method always returns a non-nil Handler.
func (r *Router) handler(m weave.Msg) weave.Handler {
path := m.Path()
if h, ok := r.routes[path]; ok {
return h
}
return notFoundHandler(path)
}
// Check dispatches to the proper handler based on path
func (r *Router) Check(ctx weave.Context, store weave.KVStore, tx weave.Tx) (*weave.CheckResult, error) {
msg, err := tx.GetMsg()
if err != nil {
return nil, errors.Wrap(err, "cannot load msg")
}
h := r.handler(msg)
return h.Check(ctx, store, tx)
}
// Deliver dispatches to the proper handler based on path
func (r *Router) Deliver(ctx weave.Context, store weave.KVStore, tx weave.Tx) (*weave.DeliverResult, error) {
msg, err := tx.GetMsg()
if err != nil {
return nil, errors.Wrap(err, "cannot load msg")
}
h := r.handler(msg)
return h.Deliver(ctx, store, tx)
}
// notFoundHandler always returns ErrNotFound error regardless of the arguments
// provided.
type notFoundHandler string
func (path notFoundHandler) Check(ctx weave.Context, store weave.KVStore, tx weave.Tx) (*weave.CheckResult, error) {
return nil, errors.Wrapf(errors.ErrNotFound, "no handler for message path %q", path)
}
func (path notFoundHandler) Deliver(ctx weave.Context, store weave.KVStore, tx weave.Tx) (*weave.DeliverResult, error) {
return nil, errors.Wrapf(errors.ErrNotFound, "no handler for message path %q", path)
}