-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperatoin.go
73 lines (62 loc) · 1.79 KB
/
operatoin.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
package op
import (
"context"
)
// Func describes an operation function.
type Func func(ctx context.Context) error
// Operation manages the runtime of a go-routine, and is intended to be run
// exactly once. Once started, it can be either waited for or canceled.
type Operation struct {
f Func
cancel func()
done chan struct{}
err error
}
// New returns a new operation for f.
func New(f Func) *Operation {
return &Operation{
f: f,
}
}
// Use applies a middleware to the operation. This must be done before the
// operation is started. It can be called multiple times to add multiple
// middleware functions. Middleware are applied in the oreder they are added,
// meaning the last middleware to be added will be the "outer" middleware.
func (op *Operation) Use(m MiddlewareFunc) {
op.f = m(op.f)
}
// Start the operation in the background using the passed in context. This
// method must be called before you can wait for or cancel the operation.
// Concurrent calls to Start are invalid, and will result in unspecified
// behavior.
func (op *Operation) Start(ctx context.Context) {
if op.done != nil {
return
}
op.done = make(chan struct{})
ctx, cancel := context.WithCancel(ctx)
op.cancel = cancel
go func() {
op.err = op.f(ctx)
cancel()
close(op.done)
}()
}
// Wait waits for the operation to be complete, and return an error when the
// operation returned an error. It is invalid to call this method before the
// operation is started.
func (op *Operation) Wait() error {
if op.done == nil {
panic("operation not started")
}
<-op.done
return op.err
}
// Cancel cancels the context passed to the operation. It is invalid to call
// this method before the operation is started.
func (op *Operation) Cancel() {
if op.done == nil {
panic("operation not started")
}
op.cancel()
}