cascadestore

package module
v0.0.0-...-446e702 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2016 License: LGPL-3.0 Imports: 18 Imported by: 0

README

Overview

This package equips Go with session support under Google AppEngine. It provides a storage implementation that's built on top of gorilla/sessions. Thanks goes to the boj/redistore project for providing an insightful foundation to start from.

Description

The purpose of this storage implementation is to allow you to implement one or more AppEngine-specific backends to store your session data. For example, the recommended mode is to use both Memcache and Datastore. When you do updates, they will be pushed to both. When you do a retrieval, it'll try retrieving the session from Memcache (faster and cheaper) before trying Datastore.

There is also a "request" backend, which will store into the current request so that further retrievals within the same request will not incur the cost of hitting the services. However, use of this backend is not recommended as updates from concurrent requests will not be seen from the current request. If the session has already been stored to the current request context then it'll never hit one of the distributed services and you risk stale data.

Usage

To choose a backend, pass a constant, or a bitwise-OR of more than one, to NewCascadeStore():

  • RequestBackend
  • MemcacheBackend
  • DatastoreBackend

For convenience, constants for commonly OR'd modes are provided:

  • DistributedBackends (MemcacheBackend | DatastoreBackend)
  • AllBackends (RequestBackend | MemcacheBackend | DatastoreBackend)

Example

package handlers

import (
    "net/http"

    "google.golang.org/appengine"
    "google.golang.org/appengine/log"

    "github.com/dsoprea/goappenginesessioncascade"
)

const (
    sessionName = "MainSession"
)

var (
    sessionSecret = []byte("SessionSecret")
    sessionStore = cascadestore.NewCascadeStore(cascadestore.DistributedBackends, sessionSecret)
)

func HandleRequest(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)

    if session, err := sessionStore.Get(r, sessionName); err != nil {
        panic(err)
    } else {
        if vRaw, found := session.Values["ExistingKey"]; found == false {
            log.Debugf(ctx, "Existing value not found.")
        } else {
            v := vRaw.(string)
            log.Debugf(ctx, "Existing value: [%s]", v)
        }

        session.Values["NewKey"] = "NewValue"
        if err := session.Save(r, w); err != nil {
            panic(err)
        }
    }
}

Other Notes

  • There is always the chance that you are going to store things bigger than Memcache can handle. By default, AppEngine has a one-megabyte size-limit for values in Memcache. go-appengine-sessioncascade will, by default, not try to push to Memcache if the serialized value is larger than this. Since you are probably ignoring Memcache errors, we could probably, technically, just ignore this as well. However, you would see error messages in your logging that might catch you off-guard. So, we prefer preventing them. If you want to change the size limit, define the MaxMemcacheSessionSizeBytes environment variable.

  • For general session store usage information, see the gorilla/sessions homepage.

  • This project uses go-appengine-logging for logging and, as a result, provides stacktraces with its errors.

Documentation

Index

Constants

View Source
const (
	CkDoDisplayLogging            = "SessionCascadeDisplayLogging"
	CkMaxMemcacheSessionSizeBytes = "MaxMemcacheSessionSizeBytes"
)

Config keys

View Source
const (
	RequestBackend   = 1 << iota
	MemcacheBackend  = 1 << iota
	DatastoreBackend = 1 << iota
)
View Source
const (
	// In most cases we won't want to use the "request" backend. Though it's
	// nice to prevent hitting Memcache or Datastore if the information is
	// requested multiple times during a single request, it won't be updated by
	// concurrent requests from the same user/browser. The distributed backends
	// will receive the updates but the "Request" backend will preempt it with
	// potentially old information. We'd have to implement a secondary channel,
	// like the Channel API, to receive fault notifications from other requests
	// that do an update so that we can know to update the information in the
	// request.
	DistributedBackends = MemcacheBackend | DatastoreBackend
	AllBackends         = RequestBackend | MemcacheBackend | DatastoreBackend

	// Amount of time for cookies/redis keys to expire.
	DefaultExpireSeconds = 86400 * 30
	MaxValueLength       = 4096
	DefaultMaxAgeSeconds = 60 * 20
	DefaultKeyPrefix     = "session."
)

Variables

View Source
var (
	ErrValueTooBig = e.New("the value to store for the session is too big")
)

Errors

Functions

This section is empty.

Types

type CascadeStore

type CascadeStore struct {
	Codecs        []securecookie.Codec
	Options       *sessions.Options // default configuration
	DefaultMaxAge int               // default Redis TTL for a MaxAge == 0 session
	// contains filtered or unexported fields
}

func NewCascadeStore

func NewCascadeStore(backendTypes int, keyPairs ...[]byte) *CascadeStore

func (*CascadeStore) Get

func (cs *CascadeStore) Get(r *http.Request, name string) (*sessions.Session, error)

Get returns a session for the given name after adding it to the registry.

See gorilla/sessions FilesystemStore.Get().

func (*CascadeStore) New

func (cs *CascadeStore) New(r *http.Request, name string) (session *sessions.Session, err error)

New returns a session for the given name without adding it to the registry.

See gorilla/sessions FilesystemStore.New().

func (*CascadeStore) Save

func (cs *CascadeStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) (err error)

Save adds a single session to the response.

func (*CascadeStore) SetKeyPrefix

func (cs *CascadeStore) SetKeyPrefix(p string)

SetKeyPrefix set the prefix

func (*CascadeStore) SetMaxAge

func (cs *CascadeStore) SetMaxAge(v int)

SetMaxAge restricts the maximum age, in seconds, of the session record both in database and a browser. This is to change session storage configuration. If you want just to remove session use your session `s` object and change it's `Options.MaxAge` to -1, as specified in

http://godoc.org/github.com/gorilla/sessions#Options

Default is the one provided by this package value - `DefaultExpireSeconds`. Set it to 0 for no restriction. Because we use `MaxAge` also in SecureCookie crypting algorithm you should use this function to change `MaxAge` value.

func (*CascadeStore) SetMaxLength

func (cs *CascadeStore) SetMaxLength(l int)

SetMaxLength sets RediStore.maxLength if the `l` argument is greater or equal 0 maxLength restricts the maximum length of new sessions to l. If l is 0 there is no limit to the size of a session, use with caution. The default for a new RediStore is 4096. Redis allows for max. value sizes of up to 512MB (http://redis.io/topics/data-types) Default: 4096,

func (*CascadeStore) SetSerializer

func (cs *CascadeStore) SetSerializer(ss SessionSerializer)

SetSerializer sets the serializer

type GobSerializer

type GobSerializer struct{}

GobSerializer uses gob package to encode the session map

func (GobSerializer) Deserialize

func (s GobSerializer) Deserialize(d []byte, ss *sessions.Session) error

Deserialize back to map[interface{}]interface{}

func (GobSerializer) Serialize

func (s GobSerializer) Serialize(ss *sessions.Session) ([]byte, error)

Serialize using gob

type JSONSerializer

type JSONSerializer struct{}

JSONSerializer encode the session map to JSON.

func (JSONSerializer) Deserialize

func (s JSONSerializer) Deserialize(d []byte, ss *sessions.Session) error

Deserialize back to map[string]interface{}

func (JSONSerializer) Serialize

func (s JSONSerializer) Serialize(ss *sessions.Session) ([]byte, error)

Serialize to JSON. Will err if there are unmarshalable key values

type SessionSerializer

type SessionSerializer interface {
	Deserialize(d []byte, ss *sessions.Session) error
	Serialize(ss *sessions.Session) ([]byte, error)
}

SessionSerializer provides an interface hook for alternative serializers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL