+ // customize template serving to initialize env.now, env.session_key first
+ async serve_jst(env, pathname, ...args) {
+ let template
+ try {
+ template = await this.jst_cache.get(pathname)
+ }
+ catch (err) {
+ if (!(err instanceof Error) || err.code !== 'ENOENT')
+ throw err
+ return false
+ }
+ env.site = this
+
+ // added part
+ env.now = XDate.now()
+ let transaction = await this.database.Transaction()
+ try {
+ let sessions = await (
+ await transaction.get({})
+ ).get('sessions', {})
+
+ let cookies = cookie.parse(env.request.headers.cookie || '')
+ let session, expires = new XDate(env.now)
+ if (
+ Object.prototype.hasOwnProperty.call(cookies, 'session_key') &&
+ (
+ session = await sessions.get(
+ env.session_key = cookies.session_key
+ )
+ ) !== undefined &&
+ env.now < await session.get('expires', 0)
+ )
+ // if session key is already in database, the requester supports
+ // cookies, and each access extends the session expiry by 1 month
+ expires.addMonths(1)
+ else {
+ // first request for session, maybe a bot, retain for only 1 day
+ expires.addDays(1)
+
+ do {
+ env.session_key = crypto.randomBytes(16).toString('hex')
+ } while (sessions.has(env.session_key))
+ session = transaction.LazyObject()
+ sessions.set(env.session_key, session)
+ }
+
+ await session.set('expires', expires.getTime())
+ env.response.setHeader(
+ 'Set-Cookie',
+ `session_key=${env.session_key}; expires=${expires.toUTCString()}; path=/;`
+ )
+
+ await transaction.commit()
+ }
+ catch (error) {
+ transaction.rollback()
+ throw error
+ }
+
+ await template(env, ...args)
+ return true
+ }
+