comparison DirectorySession.py @ 0:032bc65ebafc

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