// Save implements wcg.SessionStore#Save func (s *SessionStore) Save(sess *wcg.Session) error { encoded, err := sess.Encode() if err != nil { return err } item := &EncodedSession{ []byte(encoded), } key := datastore.NewKey(s.ctx, "EncodedSession", string(sess.ID), 0, nil) _, err = datastore.Put(s.ctx, key, item) return err }
// SessionSupportWithConfig returns two middleware functions for session support, which need to be registered // on route.Before and route.After. // // Example: // // sprepare, scomplete := SessionSupport() // // route.Before(sprepare) // route.After(scomplete) // func SessionSupportWithConfig(cfg *SessionConfig) (wcg.Handler, wcg.Handler) { if cfg.StoreFactory == nil { memorystore := wcg.NewMemorySessionStore() cfg.StoreFactory = func(req *wcg.Request) wcg.SessionStore { req.Logger.Warnf("Memory SessionStore is used so that the session data would lost suddenly.") req.Logger.Warnf("If you are in GAE environment (including devserver), you must use GAESessionStoreFactory") return memorystore } } // load handler loads the session data from backend storage. load := func(res *wcg.Response, req *wcg.Request) { if res.IsClosed() { return } var sess *wcg.Session var err error store := cfg.StoreFactory(req) c, err := req.SignedCookie(cfg.CookieName, cfg.Key) if err != nil { req.Logger.Debugf("Could not decode the signed cookie on %s: %v", cfg.Key, err) } if c != nil { if wcg.IsUUID(c.Value) { sess, err = store.Load(wcg.UUID(c.Value)) } if err != nil { req.Logger.Warnf( "Could not load the session (id: %q) from the store (%v), use a new session.", err, c.Value) sess = nil c = nil } else { if sess == nil { req.Logger.Debugf("Session data for %q was not found on backend.", c.Value) } else { req.Logger.Debugf("Session data for %q found.", c.Value) expiredAt := sess.Timestamp.Add(time.Duration(cfg.MaxAge) * time.Second) if expiredAt.Before(time.Now()) { // expired req.Logger.Infof("Session data for %q is found but expired.", c.Value) if _, err := store.Delete(sess.ID); err != nil { req.Logger.Errorf("An error occurred while deleting the expired session (%q): %v", sess.ID, err) } sess = nil } } } } if c == nil { // no cookie found c = &http.Cookie{} c.Name = cfg.CookieName c.HttpOnly = cfg.HTTPOnly c.MaxAge = cfg.MaxAge if cfg.Domain != "" { c.Domain = cfg.Domain } } c.Path = cfg.Path // No session found if sess == nil { sess = wcg.NewSession(req) sess.Timestamp = time.Now() req.Logger.Debugf("Creating the new session.") store := cfg.StoreFactory(req) err := store.Save(sess) if err != nil { res.RenderInternalError("New Session could not be created: %v", err) return } } else { // Update the timestamp. sess.Timestamp = time.Now() } // Set the cookie data c.Value = string(sess.ID) c.Expires = sess.Timestamp.Add(time.Duration(cfg.MaxAge) * time.Second) c.MaxAge = cfg.MaxAge req.Session = sess encoded, _ := sess.Encode() req.SetLocal("__session_support", encoded) res.SetSignedCookie(c, cfg.Key) } // save handler store the cookie data into backend storage. save := func(res *wcg.Response, req *wcg.Request) { if encoded, ok := req.Local("__session_support").(string); ok { nencoded, _ := req.Session.Encode() // Store session if it is changed. if encoded != nencoded { store := cfg.StoreFactory(req) err := store.Save(req.Session) if err != nil { // TODO: log session error req.Logger.Errorf("Could not save the session data on backend: %v", err) } else { req.Logger.Debugf("Successfully stored the session data on backend.") } } else { req.Logger.Debugf("Session is not changed, skipped to be stored.") } } } return wcg.NewNamedHandler("Session.Load", load), wcg.NewNamedHandler("Session.Save", save) }