Mercurial > hg > env-test-daniele
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 |