summaryrefslogtreecommitdiff
path: root/types/cookie/cookie.go
diff options
context:
space:
mode:
authorjwijenbergh <jeroenwijenbergh@protonmail.com>2023-04-12 22:54:30 +0200
committerJeroen Wijenbergh <46386452+jwijenbergh@users.noreply.github.com>2023-09-25 09:43:37 +0200
commitd9c775f710508f9dc29139cc8714122114893531 (patch)
tree6225e32e449b27780338e96cb6ffa63639ad76b8 /types/cookie/cookie.go
parent97308a5b0f1f930220be889be5c486328af104d0 (diff)
Types: Add a new cookie type
Used as a specialized context in state callbacks and for cancellation
Diffstat (limited to 'types/cookie/cookie.go')
-rw-r--r--types/cookie/cookie.go81
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
+}