1 import threading, time, pickle, random, os
4 __all__ = ["db", "get"]
9 ret += "%02X" % (ord(byte),)
14 for i in xrange(length):
15 nonce += chr(random.randint(0, 255))
18 class session(object):
19 def __init__(self, lock, expire = 86400 * 7):
20 self.id = hexencode(gennonce(16))
23 self.ctime = self.atime = self.mtime = int(time.time())
39 def __getitem__(self, key):
42 def get(self, key, default = None):
43 return self.dict.get(key, default)
45 def __setitem__(self, key, value):
46 self.dict[key] = value
47 if hasattr(value, "sessdirty"):
52 def __delitem__(self, key):
53 old = self.dict.pop(key)
58 def __contains__(self, key):
59 return key in self.dict
61 def __getstate__(self):
63 for k, v in self.__dict__.items():
64 if k == "lock": continue
68 def __setstate__(self, st):
71 # The proper lock is set by the thawer
74 return "<session %s>" % self.id
77 def __init__(self, backdb = None, cookiename = "wrwsess", path = "/"):
79 self.cookiename = cookiename
81 self.lock = threading.Lock()
83 self.freezetime = 3600
87 now = int(time.time())
89 clist = self.live.keys()
93 entry = self.live[sessid]
98 if entry[1] == "retired":
100 elif entry[1] is None:
104 if sess.atime + self.freezetime < now:
109 if sess.atime + sess.expire < now:
116 del self.live[sessid]
123 if len(self.live) == 0:
129 def _fetch(self, sessid):
131 now = int(time.time())
133 if sessid in self.live:
134 entry = self.live[sessid]
136 entry = self.live[sessid] = [threading.RLock(), None]
138 if isinstance(entry[1], session):
141 elif entry[1] == "retired":
143 elif entry[1] is None:
145 thawed = self.thaw(sessid)
146 if thawed.atime + thawed.expire < now:
148 thawed.lock = entry[0]
156 del self.live[sessid]
158 raise Exception("Illegal session entry: " + repr(entry[1]))
160 def checkclean(self):
162 if self.cthread is None:
163 self.cthread = threading.Thread(target = self.cleanloop)
164 self.cthread.setDaemon(True)
167 def mksession(self, req):
168 return session(threading.RLock())
170 def mkcookie(self, req, sess):
171 cookie.add(req, self.cookiename, sess.id,
173 expires=cookie.cdate(time.time() + sess.expire))
175 def fetch(self, req):
176 now = int(time.time())
177 sessid = cookie.get(req, self.cookiename)
182 sess = self._fetch(sessid)
184 sess = self.mksession(req)
190 self.mkcookie(req, sess)
192 self.live[sess.id] = [sess.lock, sess]
198 req.oncommit(ckfreeze)
201 def thaw(self, sessid):
202 if self.backdb is None:
204 data = self.backdb[sessid]
206 return pickle.loads(data)
210 def freeze(self, sess):
211 if self.backdb is None:
214 data = pickle.dumps(sess, -1)
215 self.backdb[sess.id] = data
219 return req.item(self.fetch)
221 class dirback(object):
222 def __init__(self, path):
225 def __getitem__(self, key):
227 with open(os.path.join(self.path, key)) as inf:
232 def __setitem__(self, key, value):
233 if not os.path.exists(self.path):
234 os.makedirs(self.path)
235 with open(os.path.join(self.path, key), "w") as out:
238 default = env.var(db(backdb = dirback(os.path.join("/tmp", "wrwsess-" + str(os.getuid())))))
241 return default.val.get(req)