diff --git a/go.mod b/go.mod index 96e8e9c..1357e37 100644 --- a/go.mod +++ b/go.mod @@ -4,3 +4,5 @@ require ( github.com/ipfs/go-block-format v0.0.2 github.com/ipfs/go-cid v0.0.3 ) + +go 1.13 diff --git a/interface.go b/interface.go index c3032b2..e271793 100644 --- a/interface.go +++ b/interface.go @@ -31,7 +31,54 @@ type Fetcher interface { // SessionExchange is an exchange.Interface which supports // sessions. +// +// Deprecated: Use the free-function NewSession(ctx) to associate a session with +// a context. type SessionExchange interface { Interface + + // Deprecated: Use the free-function NewSession(ctx) to associate a new session + // with a context and call functions on the normal exchange interface. NewSession(context.Context) Fetcher } + +// SessionKey is an opaque type uniquely identifying a session. Each SessionKey +// should be allocated with new(SessionKey). +type SessionKey struct{} + +type sessionContextKey struct{} +type sessionContextValue struct { + sesKey *SessionKey + sesCtx context.Context +} + +// NewSession registers a new session with the context. The session will be +// closed when the passed-in context is canceled. +// +// If there's already a session associated with the context, the existing +// session will be used. +// +// This function does not initialize any state, it just creates a new +// *SessionKey and associates it with the context. +func NewSession(ctx context.Context) context.Context { + if _, ok := ctx.Value(sessionContextKey{}).(*sessionContextValue); ok { + // Leave the session alone. + return ctx + } + return context.WithValue(ctx, sessionContextKey{}, &sessionContextValue{ + sesKey: new(SessionKey), + sesCtx: ctx, // save this so we can construct the session with the _session_ context. + }) +} + +// GetSession loads the fetcher from the context. The returned context is the +// context associated with the session itself. +// +// If there is no session associated with this context, this function returns +// a new session key and the passed-in context. +func GetSession(ctx context.Context) (*SessionKey, context.Context) { + if s, ok := ctx.Value(sessionContextKey{}).(*sessionContextValue); ok { + return s.sesKey, s.sesCtx + } + return new(SessionKey), ctx +}