durusmail: quixote-users: SessionPublisher / read_config in SCGI
SessionPublisher / read_config in SCGI
2002-05-07
2002-05-08
2002-05-08
2002-05-08
2002-05-08
SessionPublisher / read_config in SCGI
Jonathan Corbet
2002-05-08
> Would anyone on the list have some example Quixote code showing the use of
> sessions to share?

OK, for what it's worth, here's what I've been using.  It's a quick hack
that wasn't really meant to be released to the world (yet), so it's not the
most polished thing in the world.  I'm sure there's something obviously
stupid in here somewhere...be nice...:)

Beginning boilerplate looks like this:

from quixote.errors import SessionError
from quixote import session, get_publisher
import SessionDB

I'll leave out SessionDB - it just stashes a pickle into the database using
the session ID as a key, simple stuff.

As has been mentioned, the Quixote session directory is process-specific
and nonpersistent.  I run out of mod_python, so there can be many copies of
the application running simultaneously; the session objects need to be
visible to all of them.  So I made a new one that remaps the dictionary
operations into the (postgres) database:

#
# A class to replace the simple session dictionary used by SessionManager.
#
class SessionList:
    def __init__ (self):
        pass
    #
    # Basic dictionary operations
    #
    def has_key (self, id):
        return SessionDB.ss_HasId (id)

    def get (self, id):
        return SessionDB.ss_Get (id)

    def keys (self):
        return SessionDB.ss_IdList ()

    def __getitem__ (self, id):
        return SessionDB.ss_Get (id)

    def __setitem__ (self, id, session):
        if SessionDB.ss_HasId (id):
            SessionDB.ss_Update (id, session)
        else:
            SessionDB.ss_Save (id, session)

    def __delitem__ (self, id):
        SessionDB.ss_Delete (id)


Then I ended up making a new session class that keeps track of whether it
needs to be synced back to persistent store.  When I make the ZODB version,
this won't be necessary...

#
# Our session class.  Just like the stock one, except that we keep track of
# a "dirty" state which says we need to be written back to persistent store.
#
class LWNSession (session.Session):
    def __init__ (self, request, id):
        session.Session.__init__ (self, request, id)
        self._dirty = 0

    def dirty (self):
        self._dirty = 1

    def clean (self):
        self._dirty = 0

    def is_dirty (self):
        return self._dirty


Finally, the session manager looks like this.  I put in the session
directory defined above, and have new_session create my own session
object.  maintain_session has been overridden to force the session object
to be rewritten to persistent store if something has changed it.

class LWNSessionManager (session.SessionManager):
    #
    # The key to the whole thing: substitute in our own session listing
    # class.  With this in place, things work.
    #
    def __init__ (self):
        self.sessions = SessionList ()

    #
    # Create a new session.
    #
    def new_session (self, request, id):
        return LWNSession (request, id)

    #
    # Our version of maintain_session, which rewrites the session object
    # to persistent store if need be.
    #
    def maintain_session (self, request, session):
        #
        # See if we've stored this session already.
        #
        if self.sessions.has_key(session.id):
            #
            # Just discard sessions that don't hold any useful info.
            #
            if session.is_empty():
                del self.sessions[session.id]
                self.revoke_session_cookie(request)
            #
            # Save dirty sessions back to the database.
            #
            elif session.is_dirty ():
                session.clean ()
                self.sessions[session.id] = session
        #
        # If the session is not currently in persistent store, put it there,
        # but only if it's worth saving.
        #
        else:
            if not session.is_empty():
                self.sessions[session.id] = session
                self.set_session_cookie(request, session.id)


I also use a couple of application state-derived objects for actually
keeping the useful information in the session object - user preferences,
privileges, etc.  But that's about it, it's pretty simple, really.

Hope that helps,

jon

Jonathan Corbet
Executive editor, LWN.net
corbet@lwn.net


reply