forked from secondbit/wendy
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwendy.go
90 lines (76 loc) · 3.59 KB
/
wendy.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
90
package wendy
import (
"errors"
"fmt"
)
const (
LogLevelDebug = iota
LogLevelWarn
LogLevelError
)
// Application is an interface that other packages can fulfill to hook into Wendy.
//
// OnError is called on errors that are even remotely recoverable, passing the error that was raised.
//
// OnDeliver is called when the current Node is determined to be the final destination of a Message. It passes the Message that was received.
//
// OnForward is called immediately before a Message is forwarded to the next Node in its route through the Cluster. The function receives a pointer to the Message, which can be modified before it is sent, and the ID of the next step in the Message's route. The function must return a boolean; true if the Message should continue its way through the Cluster, false if the Message should be prematurely terminated instead of forwarded.
//
// OnNewLeaves is called when the current Node's leafSet is updated. The function receives a dump of the leafSet.
//
// OnNodeJoin is called when the current Node learns of a new Node in the Cluster. It receives the Node that just joined.
//
// OnNodeExit is called when a Node is discovered to no longer be participating in the Cluster. It is passed the Node that just left the Cluster. Note that by the time this method is called, the Node is no longer reachable.
//
// OnHeartbeat is called when the current Node receives a heartbeat from another Node. Heartbeats are sent at a configurable interval, if no messages have been sent between the Nodes, and serve the purpose of a health check.
type Application interface {
OnError(err error)
OnDeliver(msg Message)
OnForward(msg *Message, nextId NodeID) bool // return False if Wendy should not forward
OnNewLeaves(leafset []*Node)
OnNodeJoin(node Node)
OnNodeExit(node Node)
OnHeartbeat(node Node)
}
// Credentials is an interface that can be fulfilled to limit access to the Cluster.
type Credentials interface {
Valid([]byte) bool
Marshal() []byte
}
// Passphrase is an implementation of Credentials that grants access to the Cluster if the Node has the same Passphrase set
type Passphrase string
func (p Passphrase) Valid(supplied []byte) bool {
return string(supplied) == string(p)
}
func (p Passphrase) Marshal() []byte {
return []byte(p)
}
// Errors!
var deadNodeError = errors.New("Node did not respond to heartbeat.")
var nodeNotFoundError = errors.New("Node not found.")
var impossibleError = errors.New("This error should never be reached. It's logically impossible.")
// IdentityError represents an error that was raised when a Node attempted to perform actions on its state tables using its own ID, which is problematic. It is its own type for the purposes of handling the error.
type IdentityError struct {
Action string
Preposition string
Container string
}
// Error returns the IdentityError as a string and fulfills the error interface.
func (e IdentityError) Error() string {
return fmt.Sprintf("IdentityError: Tried to %s myself %s the %s.", e.Action, e.Preposition, e.Container)
}
func throwIdentityError(action, prep, container string) IdentityError {
return IdentityError{
Action: action,
Preposition: prep,
Container: container,
}
}
// InvalidArgumentError represents an error that is raised when arguments that are invalid are passed to a function that depends on those arguments. It is its own type for the purposes of handling the error.
type InvalidArgumentError string
func (e InvalidArgumentError) Error() string {
return fmt.Sprintf("InvalidArgumentError: %s", e)
}
func throwInvalidArgumentError(msg string) InvalidArgumentError {
return InvalidArgumentError(msg)
}