diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2023-04-12 22:54:30 +0200 |
|---|---|---|
| committer | Jeroen Wijenbergh <46386452+jwijenbergh@users.noreply.github.com> | 2023-09-25 09:43:37 +0200 |
| commit | d9c775f710508f9dc29139cc8714122114893531 (patch) | |
| tree | 6225e32e449b27780338e96cb6ffa63639ad76b8 | |
| parent | 97308a5b0f1f930220be889be5c486328af104d0 (diff) | |
Types: Add a new cookie type
Used as a specialized context in state callbacks and for cancellation
| -rw-r--r-- | types/cookie/cookie.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/types/cookie/cookie.go b/types/cookie/cookie.go new file mode 100644 index 0000000..e1cffca --- /dev/null +++ b/types/cookie/cookie.go @@ -0,0 +1,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 +} |
