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
|
// package cookie implements a specialized version of a context
// - It is cancellable
// - It has a channel associated with it to reply to state callbacks
// - It can be marshalled by having a cgo Handle attached to it
package cookie
import (
"context"
"encoding/json"
"runtime/cgo"
"github.com/go-errors/errors"
)
type Cookie struct {
c chan string
ctx context.Context
ctxCancel context.CancelFunc
H cgo.Handle
}
// NewWithContext creates a new cookie with a context
// It stores the cancel and channel inside of the struct
func NewWithContext(ctx context.Context) Cookie {
ctx, cancel := context.WithCancel(ctx)
return Cookie{
c: make(chan string),
ctx: ctx,
ctxCancel: cancel,
}
}
// MarshalJSON marshals the cookie to JSON
func (c *Cookie) MarshalJSON() ([]byte, error) {
if c.H == 0 {
return nil, errors.New("no associated handle found")
}
return json.Marshal(c.H)
}
// Receive receives a value from the cookie up until the context is done or errchan gets an error
// This error chan is used for goroutines to signal errors that we have to exit early
func (c *Cookie) Receive(errchan chan error) (string, error) {
select {
case r := <-c.c:
return r, nil
case e := <-errchan:
return "", e
case <-c.ctx.Done():
return "", errors.WrapPrefix(context.Canceled, "receive cookie", 0)
}
}
// Cancel cancels the cookie by calling the context cancel function
// It returns an error if no such function exists
func (c *Cookie) Cancel() error {
if c.ctxCancel == nil {
return errors.New("no cancel function found")
}
c.ctxCancel()
return nil
}
// Send sends data to the cookie channel if the context is not canceled
func (c *Cookie) Send(data string) error {
select {
case <-c.ctx.Done():
return errors.WrapPrefix(context.Canceled, "send cookie", 0)
default:
if c.c == nil {
return errors.New("channel is nil")
}
c.c <- data
return nil
}
}
// Context gets the underlying context of the cookie
func (c *Cookie) Context() context.Context {
return c.ctx
}
|