annotate DirectorySession.py @ 25:4a4bd554b4c1 tip

Closing this sub branch.
author Daniele Barchiesi <daniele.barchiesi@eecs.qmul.ac.uk>
date Mon, 25 Mar 2013 14:02:54 +0000
parents 032bc65ebafc
children 89978106f0bb
rev   line source
gyorgy@0 1 """
gyorgy@0 2 DiractorySession.py
gyorgy@0 3
gyorgy@0 4 Created by George Fazekas, QMUL on 2009-06-03.
gyorgy@0 5 Copyright (c) 2009 QMUL. All rights reserved.
gyorgy@0 6
gyorgy@0 7 This Cherrypy extension implements a hybrid session type,
gyorgy@0 8 where data is held in memory, while files are written to
gyorgy@0 9 a directory created for each session.
gyorgy@0 10
gyorgy@0 11 To use it as a builtin session type, we use:
gyorgy@0 12 cherrypy.lib.sessions.DirectorySession = DirectorySession
gyorgy@0 13 """
gyorgy@0 14 from __future__ import with_statement
gyorgy@0 15 import os,sys,time,shutil,datetime,logging,threading,cherrypy
gyorgy@0 16 from cherrypy.lib.sessions import Session
gyorgy@0 17 from cherrypy.lib import static
gyorgy@0 18
gyorgy@0 19 from sawautil import convertFilename
gyorgy@0 20
gyorgy@0 21 class DirectorySession(Session):
gyorgy@0 22
gyorgy@0 23 cache = {}
gyorgy@0 24 locks = {}
gyorgy@0 25 instanceList = []
gyorgy@0 26
gyorgy@0 27 def __init__(self, id=None, **kwargs):
gyorgy@0 28 # for i in self.instanceList :
gyorgy@0 29 # print 'previous-sessions: ', i.id
gyorgy@0 30 # if (i.id == id) :
gyorgy@0 31 # print 'got instance already!'
gyorgy@0 32 # self.instanceList.append(self)
gyorgy@0 33 # print 'instance initialised:' + str(len(self.instanceList))
gyorgy@0 34 # kwargs['SESSIONS_PATH'] = os.path.abspath(kwargs['SESSIONS_PATH'])
gyorgy@0 35
gyorgy@0 36 if not id in self.cache:
gyorgy@0 37 new_session_signal = True
gyorgy@0 38 else :
gyorgy@0 39 new_session_signal = False
gyorgy@0 40
gyorgy@0 41 Session.__init__(self, id=id, **kwargs)
gyorgy@0 42
gyorgy@0 43 if new_session_signal or not self.has_key('name'):
gyorgy@0 44 active_sessions = str(self.__len__())
gyorgy@0 45 self.name = "Session %s.%s: " %(active_sessions, str(self.id)[-2:])
gyorgy@0 46 self['name'] = self.name
gyorgy@0 47 self['log_count'] = 0
gyorgy@0 48 try :
gyorgy@0 49 # try to write initial session data into the log file
gyorgy@0 50 log_msg = "%sCherrypy::DirectorySession:New Session Created: ID = %s active sessions: %s \n" %(self.name,str(self.id),active_sessions)
gyorgy@0 51 log_msg += '\n'.join(map ( lambda x: " %s: %s " %x , cherrypy.request.headers.items() ))
gyorgy@0 52 cherrypy.log(log_msg)
gyorgy@0 53 except :
gyorgy@0 54 print "An error has occured while writing initial session data to the log file."
gyorgy@0 55
gyorgy@0 56 def setup(cls,**kwargs):
gyorgy@0 57 print 'Setting up storage class... Nothing to do here yet.'
gyorgy@0 58 for k, v in kwargs.iteritems():
gyorgy@0 59 setattr(cls, k, v)
gyorgy@0 60 print k,v
gyorgy@0 61 # cls.SESSIONS_PATH = kwargs['SESSIONS_PATH'] we could setup a cleanup thread here for the dirs too. kwargs['sessions_path'] = os.path.abspath(kwargs['sessions_path'])
gyorgy@0 62
gyorgy@0 63 # NOTE: This is now passed in via tools.config:
gyorgy@0 64 # tools.sessions.SESSIONS_PATH
gyorgy@0 65
gyorgy@0 66 # DELETION COMMENTED OUT
gyorgy@0 67 #if (os.path.exists(cls.SESSIONS_PATH)) :
gyorgy@0 68 # shutil.rmtree (cls.SESSIONS_PATH, ignore_errors=True, onerror=None)
gyorgy@0 69 # cherrypy.log('Cherrypy::DirectorySession:setup (classmethod) Existing session directory removed.')
gyorgy@0 70 if not (os.path.exists(cls.SESSIONS_PATH)) :
gyorgy@0 71 os.mkdir(cls.SESSIONS_PATH)
gyorgy@0 72 cherrypy.log('Cherrypy::DirectorySession:setup (classmethod) New sessions path created: %s' %str(cls.SESSIONS_PATH))
gyorgy@0 73
gyorgy@0 74
gyorgy@0 75 setup = classmethod(setup)
gyorgy@0 76
gyorgy@0 77 def get_session_name(self):
gyorgy@0 78 """ Return the human readable name of the session. """
gyorgy@0 79 if self.has_key('name') :
gyorgy@0 80 return self['name']
gyorgy@0 81 else :
gyorgy@0 82 return 'Session None: '
gyorgy@0 83
gyorgy@0 84 def log(self,msg,context='',severity=logging.DEBUG,traceback=True):
gyorgy@0 85 """ Write into cherrypy.log using the session prefix."""
gyorgy@0 86 if not self.has_key('log_count') : self['log_count'] = 0
gyorgy@0 87 log_msg = self.get_session_name() + "m%03i. %s" %(self['log_count'],msg)
gyorgy@0 88 self['log_count'] += 1
gyorgy@0 89 cherrypy.log(log_msg,context,severity,traceback)
gyorgy@0 90
gyorgy@0 91 def get_session_path(self):
gyorgy@0 92 """ Return a valid path for this session """
gyorgy@0 93 if self.has_key('session_path') :
gyorgy@0 94 return self.get('session_path',None)
gyorgy@0 95 else :
gyorgy@0 96 if not self.id :
gyorgy@0 97 raise AssertionError("Can not create directory for uninitialised session.")
gyorgy@0 98 return None
gyorgy@0 99 sessionPath = os.path.join(self.SESSIONS_PATH,str(self.id))
gyorgy@0 100 if os.path.exists(sessionPath) :
gyorgy@0 101 # clash of session IDs (unprobable), flush data
gyorgy@0 102 shutil.rmtree (sessionPath, ignore_errors=True, onerror=None)
gyorgy@0 103 print "flushed data in %s" % sessionPath
gyorgy@0 104 try :
gyorgy@0 105 os.makedirs(sessionPath)
gyorgy@0 106 except:
gyorgy@0 107 raise IOError("Session directory for id %r not created." % self.id)
gyorgy@0 108 return None
gyorgy@0 109 if os.path.exists(sessionPath) :
gyorgy@0 110 # create an entry in self so that the clean_up thread knows about this session
gyorgy@0 111 # setattr(self._data,'session_path',sessionPath)
gyorgy@0 112 self['session_path'] = sessionPath
gyorgy@0 113 return sessionPath
gyorgy@0 114
gyorgy@0 115
gyorgy@0 116 # TODO: the other use case: write the output of a pipe
gyorgy@0 117 def write_file(self,fileObj,fileName,filetype = None):
gyorgy@0 118 pass
gyorgy@0 119
gyorgy@0 120 def write_data(self,data,filename,filetype = None):
gyorgy@0 121 data = str(data)
gyorgy@0 122 sessionPath = self.get_session_path()
gyorgy@0 123 filePath = os.path.join(sessionPath,filename)
gyorgy@0 124 # print 'writing file to: ',filePath
gyorgy@0 125 with open(filePath,'wb') as f:
gyorgy@0 126 f.writelines(data)
gyorgy@0 127
gyorgy@0 128 # check file and save filetype key if given
gyorgy@0 129 if not os.path.exists(filePath) \
gyorgy@0 130 or not os.stat(filePath).st_size > 0 :
gyorgy@0 131 cherrypy.log("Session x.xx: mxxx. Cherrypy::DirectorySession:write_data: Warning: Could not verify file: %s " %filePath)
gyorgy@0 132 return False
gyorgy@0 133 elif not filetype :
gyorgy@0 134 return True
gyorgy@0 135 elif self.has_key(filetype) :
gyorgy@0 136 ol = self.get(filetype,None)
gyorgy@0 137 ol.append(os.path.basename(filePath))
gyorgy@0 138 self[filetype] = list(ol)
gyorgy@0 139 else :
gyorgy@0 140 self[filetype]= list([os.path.basename(filePath)])
gyorgy@0 141 self.save()
gyorgy@0 142 return True
gyorgy@0 143
gyorgy@0 144
gyorgy@0 145 def write_fsfile(self,fsFile,filetype = None):
gyorgy@0 146 '''Write file to session given as CGI field-storage object.'''
gyorgy@0 147 #fsFile is a cgi.FieldStorage object : cherrypy._cpcgifs.FieldStorage()
gyorgy@0 148 if hasattr (fsFile,'filename') and hasattr(fsFile,'file'):
gyorgy@0 149 return self._write_file(fsFile.file,fsFile.filename,filetype)
gyorgy@0 150
gyorgy@0 151 def write_fsfile_as(self,fsFile,filename,filetype = None):
gyorgy@0 152 '''Write file to session given as CGI field-storage object.'''
gyorgy@0 153 #fsFile is a cgi.FieldStorage object : cherrypy._cpcgifs.FieldStorage()
gyorgy@0 154 if hasattr (fsFile,'filename') and hasattr(fsFile,'file'):
gyorgy@0 155 return self._write_file(fsFile.file,filename,filetype)
gyorgy@0 156
gyorgy@0 157 def _write_file(self,file,filename,filetype):
gyorgy@0 158 '''Write file to session given as python file object.'''
gyorgy@0 159 filename = convertFilename(filename)
gyorgy@0 160 sessionPath = self.get_session_path()
gyorgy@0 161 filePath = os.path.join(sessionPath,filename)
gyorgy@0 162 # print 'writing file to: ',filePath
gyorgy@0 163
gyorgy@0 164 file.seek(0)
gyorgy@0 165 newFile = open(filePath,'wb')
gyorgy@0 166 try :
gyorgy@0 167 shutil.copyfileobj(file,newFile)
gyorgy@0 168 except :
gyorgy@0 169 try :
gyorgy@0 170 while True:
gyorgy@0 171 data = file.read(8192)
gyorgy@0 172 if not data: break
gyorgy@0 173 newFile.write(data)
gyorgy@0 174 except:
gyorgy@0 175 # newFile.close()
gyorgy@0 176 cherrypy.log("Session x.xx: mxxx. Cherrypy::DirectorySession: Could not write file to session: %i " %self.id)
gyorgy@0 177 raise IOError("Cherrypy::DirectorySession: Could not write file to session %r " %self.id)
gyorgy@0 178 finally:
gyorgy@0 179 newFile.close()
gyorgy@0 180
gyorgy@0 181 if not os.path.exists(filePath) \
gyorgy@0 182 or not os.stat(filePath).st_size > 0 :
gyorgy@0 183 cherrypy.log("Session x.xx: mxxx. Cherrypy::DirectorySession:_write_file: Warning: Failed to verify file at: %s " %filePath)
gyorgy@0 184 return False
gyorgy@0 185 elif not filetype :
gyorgy@0 186 return True
gyorgy@0 187 elif self.has_key(filetype) :
gyorgy@0 188 ol = self.get(filetype,None)
gyorgy@0 189 ol.append(os.path.basename(filePath))
gyorgy@0 190 self[filetype] = list(ol)
gyorgy@0 191 else :
gyorgy@0 192 self[filetype]= list([os.path.basename(filePath)])
gyorgy@0 193 self.save()
gyorgy@0 194 return True
gyorgy@0 195
gyorgy@0 196 def getFiles(self,filelist):
gyorgy@0 197 pass
gyorgy@0 198
gyorgy@0 199 def clean_up(self):
gyorgy@0 200 """Clean up expired sessions."""
gyorgy@0 201 now = datetime.datetime.now()
gyorgy@0 202 log_msg = "Session x.xx: mxxx. Cherrypy::DirectorySession: Cleaning up session data at: %s Length of cache = %i " %(str(now), len(self.cache))
gyorgy@0 203 print '\nCeaning up session data at %s: \n===========================' % now
gyorgy@0 204 print 'Length of cache = ', len(self.cache)
gyorgy@0 205 print 'cache members: ', self.cache.keys()
gyorgy@0 206 cherrypy.log(log_msg)
gyorgy@0 207
gyorgy@0 208 #clean up temp if server not in use
gyorgy@0 209 temp_path='/Users/Shared/george/sawa/sonic-annotator-webapp/static/temp/'
gyorgy@0 210 if len(self.cache.keys()) == 0 and os.path.exists(temp_path):
gyorgy@0 211 try :
gyorgy@0 212 for fname in os.listdir(temp_path):
gyorgy@0 213 os.remove(os.path.join(temp_path,fname))
gyorgy@0 214 print "Note: Cleaned temp directory."
gyorgy@0 215 except:
gyorgy@0 216 print "Warning: could not clear temp directory."
gyorgy@0 217 pass
gyorgy@0 218
gyorgy@0 219 for id, (data, expiration_time) in self.cache.items():
gyorgy@0 220 print 'Id: ', id
gyorgy@0 221 print 'expiration time: ', expiration_time
gyorgy@0 222 print 'Length of data: ', len(data)
gyorgy@0 223 print 'data members: ', data.keys()
gyorgy@0 224 print 'SESSIONS_PATH: ', self.SESSIONS_PATH
gyorgy@0 225
gyorgy@0 226 if expiration_time < now:
gyorgy@0 227
gyorgy@0 228 path = os.path.join(self.SESSIONS_PATH,str(id))
gyorgy@0 229 if os.path.exists(path) :
gyorgy@0 230 for fname in os.listdir(path):
gyorgy@0 231 os.remove(os.path.join(path,fname))
gyorgy@0 232 # os.removedirs(path) -> removes sessions too
gyorgy@0 233 os.rmdir(path)
gyorgy@0 234 try:
gyorgy@0 235 del self.cache[id]
gyorgy@0 236 except KeyError:
gyorgy@0 237 pass
gyorgy@0 238 try:
gyorgy@0 239 del self.locks[id]
gyorgy@0 240 except KeyError:
gyorgy@0 241 pass
gyorgy@0 242
gyorgy@0 243 def _exists(self):
gyorgy@0 244 return self.id in self.cache
gyorgy@0 245
gyorgy@0 246 def _load(self):
gyorgy@0 247 return self.cache.get(self.id)
gyorgy@0 248
gyorgy@0 249 #this is always called on an on_end_request hook (by cherrypy.session.save)
gyorgy@0 250 def _save(self, expiration_time):
gyorgy@0 251 print 'Saving Session ', self.id
gyorgy@0 252 self.cache[self.id] = (self._data, expiration_time)
gyorgy@0 253
gyorgy@0 254 def _delete(self):
gyorgy@0 255 del self.cache[self.id]
gyorgy@0 256
gyorgy@0 257 def acquire_lock(self):
gyorgy@0 258 """Acquire an exclusive lock on the currently-loaded session data."""
gyorgy@0 259 self.locked = True
gyorgy@0 260 self.locks.setdefault(self.id, threading.RLock()).acquire()
gyorgy@0 261
gyorgy@0 262 def release_lock(self):
gyorgy@0 263 """Release the lock on the currently-loaded session data."""
gyorgy@0 264 self.locks[self.id].release()
gyorgy@0 265 self.locked = False
gyorgy@0 266
gyorgy@0 267 def __len__(self):
gyorgy@0 268 """Return the number of active sessions."""
gyorgy@0 269 return len(self.cache)
gyorgy@0 270
gyorgy@0 271 cherrypy.lib.sessions.DirectorySession = DirectorySession