mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
369 lines
11 KiB
Python
369 lines
11 KiB
Python
##################################################
|
|
# SPYCE - Python-based HTML Scripting
|
|
# Copyright (c) 2002 Rimon Barr.
|
|
#
|
|
# Refer to spyce.py
|
|
# CVS: $Id: session.py 31144 2012-07-15 15:38:56Z buzz $
|
|
##################################################
|
|
|
|
from spyceModule import spyceModule
|
|
import re, time, string, random
|
|
import spyceLock
|
|
try:
|
|
import cPickle
|
|
pickle = cPickle
|
|
except:
|
|
import pickle
|
|
|
|
__doc__ = '''Session module provides support for session management - the
|
|
storage of variables on the server between requests under some short
|
|
identifier.
|
|
|
|
A user must call setHandler() to determine how the sessions are stored, before
|
|
using the other session methods. The get(), set() and delete() methods provide
|
|
access to the session information.
|
|
|
|
The autoSession() method will turn on the automatic session management
|
|
(loading and saving the session). When automatic session management is turned
|
|
on the session information, identifier, parameter name and browser method are
|
|
stored in the variables called auto, autoID, autoName and autoMethod,
|
|
respectively.'''
|
|
|
|
class session(spyceModule):
|
|
def start(self):
|
|
"Initialise the session module variables."
|
|
self._serverobject = self._api.getServerObject()
|
|
if 'session' not in dir(self._serverobject):
|
|
self._serverobject.session = sessionHandlerRegistry()
|
|
self._handler = None
|
|
self._clearAutoSession()
|
|
def finish(self, theError=None):
|
|
"Save the session, if automatic session management is turned on."
|
|
if self.autoID:
|
|
self.set(self.auto, self.autoExpire, self.autoID)
|
|
if self.autoMethod=='cookie':
|
|
self._api.getModule('cookie').set(self.autoName, self.autoID)
|
|
sessionCleanup(self._serverobject.session)
|
|
def init(self, handler=None, *args, **kwargs):
|
|
if handler:
|
|
session = apply(self.setHandler, (handler,)+args)
|
|
if kwargs.has_key('auto') and kwargs['auto']:
|
|
auto = kwargs['auto']
|
|
if type(auto) != type(()):
|
|
auto = (auto,)
|
|
apply(session.autoSession, auto)
|
|
def setHandler(self, file_name, *params):
|
|
"Select a session handler."
|
|
file_name = string.split(file_name, ':')
|
|
if len(file_name)==1: file, name = None, file_name[0]
|
|
else: file, name = file_name[:2]
|
|
if file: handler = self._api.loadModule(name, file, self._api.getFilename())
|
|
else: handler = eval(name)
|
|
self._handler = apply(handler, (self,)+params)
|
|
self._serverobject.session.add(self._handler)
|
|
return self
|
|
def get(self, id): # method deletes session, if stale
|
|
"Retrieve session information."
|
|
if not self._handler: raise 'call setHandler to initialise'
|
|
return self._handler.get(id)
|
|
def delete(self, id=None):
|
|
"Delete session information."
|
|
if not self._handler: raise 'call setHandler to initialise'
|
|
if not id:
|
|
id = self.autoID
|
|
self._clearAutoSession()
|
|
return self._handler.delete(id)
|
|
def set(self, state, expire, id=None):
|
|
"Set session information."
|
|
if not self._handler: raise 'call setHandler to initialise'
|
|
return self._handler.set(state, expire, id)
|
|
def clear(self):
|
|
"Clear all session information in current handler."
|
|
if not self._handler: raise 'call setHandler to initialise'
|
|
return self._handler.clear()
|
|
def autoSession(self, expire, method='cookie', name='spyceSession'):
|
|
"Turn on automatic session management."
|
|
if not self._handler: raise 'call setHandler to initialise'
|
|
method = string.lower(method)
|
|
if method=='cookie': self.autoID = self._api.getModule('cookie').get(name)
|
|
elif method=='post': self.autoID = self._api.getModule('request').post1(name)
|
|
elif method=='get': self.autoID = self._api.getModule('request').get1(name)
|
|
else: raise 'runtime error: invalid autosession method'
|
|
self.autoMethod = method
|
|
self.autoName = name
|
|
self.autoExpire = expire
|
|
self.auto = None
|
|
if self.autoID:
|
|
self.auto = self.get(self.autoID)
|
|
if not self.auto: self.autoID = None
|
|
if not self.autoID: # generate a sessionid
|
|
self.autoID = self.set(None, self.autoExpire)
|
|
def _clearAutoSession(self):
|
|
self.auto = None
|
|
self.autoID = None
|
|
self.autoMethod = None
|
|
self.autoName = None
|
|
self.autoExpire = None
|
|
|
|
##################################################
|
|
# Cleanup
|
|
#
|
|
|
|
# expire sessions every n requests in expectation
|
|
SESSION_EXPIRE_CHECK = 50
|
|
|
|
class sessionHandlerRegistry:
|
|
"Registry of all used session handlers."
|
|
def __init__(self):
|
|
self.handlers = {}
|
|
def add(self, handler):
|
|
self.handlers[handler.getHandlerID()] = handler
|
|
def list(self):
|
|
return self.handlers.values()
|
|
def remove(self, handler):
|
|
del self.handlers[handler.getHandlerID()]
|
|
|
|
def sessionCleanup(registry):
|
|
"""Iterates through all session handlers and sessions to perform session
|
|
cleanup"""
|
|
if random.randrange(SESSION_EXPIRE_CHECK): return
|
|
for handler in registry.list():
|
|
try:
|
|
sessions = handler.keys()
|
|
for s in sessions:
|
|
handler.get(s) # will delete stale sessions
|
|
except:
|
|
registry.remove(handler)
|
|
|
|
|
|
##################################################
|
|
# Session handlers
|
|
#
|
|
|
|
class sessionHandler:
|
|
'''All session handlers should subclass this, and implement the methods
|
|
marked: 'not implemented'.'''
|
|
def __init__(self, sessionModule):
|
|
self.childnum = sessionModule._api.getServerID()
|
|
def getHandlerID(self):
|
|
raise 'not implemented'
|
|
def get(self, id): # method should delete, if session is stale
|
|
raise 'not implemented'
|
|
def delete(self, id):
|
|
raise 'not implemented'
|
|
def clear(self):
|
|
raise 'not implemented'
|
|
def set(self, state, expire, id=None):
|
|
raise 'not implemented'
|
|
def keys(self):
|
|
raise 'not implemented'
|
|
def __getitem__(self, key):
|
|
return self.get(key)
|
|
def __delitem__(self, key):
|
|
return self.delete(key)
|
|
|
|
##################################################
|
|
# File-based session handler
|
|
#
|
|
|
|
class session_dir(sessionHandler):
|
|
def __init__(self, sessionModule, dir):
|
|
sessionHandler.__init__(self, sessionModule)
|
|
if not os.path.exists(dir):
|
|
raise "session directory '%s' does not exist" % dir
|
|
self.dir = dir
|
|
self.prefix = 'spy'
|
|
self.BINARY_MODE = 1
|
|
def getHandlerID(self):
|
|
return 'session_dir', self.childnum, self.dir
|
|
def get(self, id):
|
|
if not id: return None
|
|
filename = os.path.join(self.dir, self.prefix+id)
|
|
f=None
|
|
sessionInfo = None
|
|
try:
|
|
f=open(filename, 'r')
|
|
sessionInfo = pickle.load(f)
|
|
f.close()
|
|
except:
|
|
try:
|
|
if f: f.close()
|
|
os.unlink(filename)
|
|
except: pass
|
|
if sessionInfo:
|
|
if time.time() > sessionInfo['expire']:
|
|
self.delete(id)
|
|
return None
|
|
else: return sessionInfo['state']
|
|
else: return None
|
|
def delete(self, id):
|
|
try:
|
|
filename = os.path.join(self.dir, self.prefix+id)
|
|
os.remove(filename)
|
|
except: pass
|
|
def clear(self):
|
|
for id in self.keys():
|
|
self.delete(id)
|
|
def set(self, state, expire, id=None):
|
|
f=None
|
|
try:
|
|
if id:
|
|
filename = os.path.join(self.dir, self.prefix+id)
|
|
f=open(filename, 'w')
|
|
else:
|
|
filename, f, id = openUniqueFile(self.dir, self.prefix, ('%d_' % self.childnum))
|
|
sessionInfo = {}
|
|
sessionInfo['expire'] = int(time.time())+expire
|
|
sessionInfo['state'] = state
|
|
pickle.dump(sessionInfo, f, self.BINARY_MODE)
|
|
f.close()
|
|
except:
|
|
try:
|
|
if f: f.close()
|
|
except: pass
|
|
raise
|
|
return id
|
|
def keys(self):
|
|
sessions = os.listdir(self.dir)
|
|
sessions = filter(lambda s, p=self.prefix: s[:len(p)]==p, sessions)
|
|
sessions = map(lambda s, self=self: s[len(self.prefix):], sessions)
|
|
return sessions
|
|
|
|
# requires unique (dir, prefix)
|
|
def openUniqueFile(dir, prefix, unique, mode='w', max=1000000):
|
|
filelock = spyceLock.fileLock(os.path.join(dir, prefix))
|
|
filelock.lock(1)
|
|
try:
|
|
id = "%06d"%random.randrange(max)
|
|
filename = os.path.join(dir, prefix+unique+id)
|
|
while os.path.exists(filename):
|
|
id = str(random.randrange(max))
|
|
filename = os.path.join(dir, prefix+unique+id)
|
|
f = None
|
|
f = open(filename, mode)
|
|
return filename, f, unique+id
|
|
finally:
|
|
filelock.unlock()
|
|
|
|
##################################################
|
|
# Hash file session handlers
|
|
#
|
|
|
|
class sessionHandlerDBM(sessionHandler):
|
|
def __init__(self, sessionModule, filename):
|
|
sessionHandler.__init__(self, sessionModule)
|
|
self.filename = filename
|
|
self.dbm = None
|
|
self.BINARY_MODE = 1
|
|
self.dbm_type = None # redefine in subclass
|
|
def getHandlerID(self):
|
|
return 'session_'+self.dbm_type, self.childnum, self.filename
|
|
def _open(self):
|
|
raise 'need to implement'
|
|
def _close(self):
|
|
if self.dbm:
|
|
self.dbm.close()
|
|
self.dbm = None
|
|
def get(self, id):
|
|
if not id: return None
|
|
self._open()
|
|
try:
|
|
expire, state = None, None
|
|
if self.dbm.has_key(id):
|
|
expire, state = pickle.loads(self.dbm[id])
|
|
if expire!=None and time.time() > expire:
|
|
self.delete(id)
|
|
state = None
|
|
return state
|
|
finally:
|
|
self._close()
|
|
def delete(self, id):
|
|
self._open()
|
|
try:
|
|
if self.dbm.has_key(id):
|
|
del self.dbm[id]
|
|
finally:
|
|
self._close()
|
|
def clear(self):
|
|
if os.path.exists(self.filename):
|
|
os.unlink(self.filename)
|
|
def set(self, state, expire, id=None):
|
|
self._open()
|
|
try:
|
|
if not id:
|
|
id = generateKey(self.dbm, self.childnum)
|
|
value = pickle.dumps( (int(time.time())+expire, state), self.BINARY_MODE)
|
|
self.dbm[id] = value
|
|
return id
|
|
finally:
|
|
self._close()
|
|
def keys(self):
|
|
self._open()
|
|
try:
|
|
return self.dbm.keys()
|
|
finally:
|
|
self._close()
|
|
|
|
def opendb(dbm_session_handler, module, filename, flags):
|
|
mod = __import__(module)
|
|
if not dbm_session_handler.dbm:
|
|
dbm_session_handler.dbm = mod.open(filename, flags)
|
|
|
|
class session_gdbm(sessionHandlerDBM):
|
|
def __init__(self, sessionModule, filename):
|
|
sessionHandlerDBM.__init__(self, sessionModule, filename)
|
|
self.dbm_type = 'gdbm'
|
|
def _open(self):
|
|
opendb(self, self.dbm_type, self.filename, 'cu')
|
|
|
|
class session_bsddb(sessionHandlerDBM):
|
|
def __init__(self, sessionModule, filename):
|
|
sessionHandlerDBM.__init__(self, sessionModule, filename)
|
|
self.dbm_type = 'bsddb'
|
|
def _open(self):
|
|
opendb(self, 'dbhash', self.filename, 'c')
|
|
|
|
def generateKey(hash, prefix, max = 1000000):
|
|
prefix = str(prefix)+'_'
|
|
key = random.randrange(max)
|
|
while hash.has_key(prefix+str(key)):
|
|
key = random.randrange(max)
|
|
key = prefix+str(key)
|
|
hash[key] = pickle.dumps(None, 1)
|
|
return key
|
|
|
|
|
|
##################################################
|
|
# User callback session handlers
|
|
#
|
|
|
|
class session_user(sessionHandler):
|
|
'''User-callback session handler'''
|
|
def __init__(self, sessionModule, getf, setf, delf, idsf, info=None):
|
|
self.serverID = sessionModule._api.getServerID()
|
|
self.info = info
|
|
self.getf = getf
|
|
self.setf = setf
|
|
self.delf = delf
|
|
self.idsf = idsf
|
|
def getHandlerID(self):
|
|
return 'session_user', self.serverID, self.info
|
|
def get(self, id): # method should delete, if session is stale
|
|
return self.getf(self.info, id)
|
|
def set(self, state, expire, id):
|
|
return self.setf(self.info, state, expire, self.serverID, id)
|
|
def delete(self, id):
|
|
return self.delf(self.info, id)
|
|
def keys(self):
|
|
return self.idsf(self.info)
|
|
def clear(self):
|
|
for id in self.keys():
|
|
self.delete(id)
|
|
|
|
##################################################
|
|
# database-based session handlers
|
|
#
|
|
|
|
# rimtodo: database-based session handler
|
|
|