-
Notifications
You must be signed in to change notification settings - Fork 469
/
listener.go
72 lines (64 loc) · 2.48 KB
/
listener.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
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
package agreement
// A listener is a state machine which can handle events, returning new events.
type listener interface {
// T returns the stateMachineTag describing the listener.
T() stateMachineTag
// underlying returns a listener of the underlying type.
//
// This is used to get to the underlying type when it is wrapped by another type.
// For instance, if
// c = checkedListener{listener: voteAggregator{}, listenerContract: voteAggregatorContract{}}
// then
// c.underlying() == c.listener
underlying() listener
// handle an event, updating the state of the listener.
handle(routerHandle, player, event) event
}
// A listenerContract describes the list of allowed preconditions and postconditions
// for events entering and exiting the listener.
type listenerContract interface {
// pre returns an error for each precondition that is violated for each
// event sent to some listener.
pre(p player, in event) []error
// post returns an error for each postcondition that is violated for
// each event emitted by a listener.
post(p player, in event, out event) []error
}
// A checkedListener wraps a listener, checking its contract on each call.
type checkedListener struct {
listener
listenerContract
}
func (l checkedListener) handle(r routerHandle, p player, in event) event {
errs := l.pre(p, in)
if len(errs) != 0 {
for _, err := range errs {
r.t.log.Errorf("%v: precondition violated: %v", l.T(), err)
}
r.t.log.Panicf("%v: precondition violated: %v", l.T(), errs[0])
}
out := l.listener.handle(r, p, in)
errs = l.post(p, in, out)
if len(errs) != 0 {
for _, err := range errs {
r.t.log.Errorf("%v: postcondition violated: %v", l.T(), err)
}
r.t.log.Panicf("%v: postcondition violated: %v", l.T(), errs[0])
}
return out
}