From 055ceaa633db839da2dd2058c0d7895cd48a20e8 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Fri, 7 Jan 2022 17:39:57 +1100 Subject: [PATCH] Change page.jst to use /database.logjson instead of /_analytics/*.json files --- .gitignore | 2 +- _config/site.jst | 149 ++++++++++++++++++++++++++++------------------- link.sh | 2 +- package.json | 1 + page.jst | 72 ++++++++++------------- 5 files changed, 123 insertions(+), 103 deletions(-) diff --git a/.gitignore b/.gitignore index 0e2151c..dff39c0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,8 @@ .*.less .*.min .*.svg -/_analytics /_logs /_zet/site.* +/database.logjson /node_modules /package-lock.json diff --git a/_config/site.jst b/_config/site.jst index d11c5c1..0298224 100644 --- a/_config/site.jst +++ b/_config/site.jst @@ -1,78 +1,109 @@ +let assert = require('assert') let EmailJSCache = require('@ndcode/emailjs_cache') let ZettairCache = require('@ndcode/zettair_cache') -let assert = require('assert') -let CustomSite = function(resources, root, options, prev_site) { - if (!this instanceof CustomSite) - throw Error('CustomSite is a constructor') - _jst_server.Site.call(this, resources, root, options, prev_site) +return async (resources, root, prev_site) => { + let logjson = (await import('@ndcode/logjson')).default - this.emailjs_cache = undefined - this.zettair_cache = undefined -} + let CustomSite = function(resources, root, options, prev_site) { + if (!this instanceof CustomSite) + throw Error('CustomSite is a constructor') + _jst_server.Site.call(this, resources, root, options, prev_site) -CustomSite.prototype = Object.create(_jst_server.Site.prototype) + this.database = undefined + this.emailjs_cache = undefined + this.zettair_cache = undefined + } -CustomSite.prototype.start = async function() { - await _jst_server.Site.prototype.start.call(this) + CustomSite.prototype = Object.create(_jst_server.Site.prototype) + + // called when the server starts or the site.jst file is modified + // in latter case it will carry over the previously created resource objects + CustomSite.prototype.start = async function() { + await _jst_server.Site.prototype.start.call(this) + + assert(this.database === undefined) + this.database = await this.resources.ref( + 'database', + async () => { + let database = new logjson.Database() + await database.open(this.root + '/database.logjson') + return database + } + ) + + assert(this.emailjs_cache === undefined) + this.emailjs_cache = await this.resources.ref( + 'emailjs_cache', + async () => new EmailJSCache(true) + ) + + assert(this.zettair_cache === undefined) + this.zettair_cache = await this.resources.ref( + 'zettair_cache', + async () => new ZettairCache(true) + ) + } - assert(this.emailjs_cache === undefined) - this.emailjs_cache = await this.resources.ref( - 'emailjs_cache', - async () => new EmailJSCache(true) - ) + // called when the server starts or the site.jst file is modified + // in latter case the start() method of the new CustomSite object is called + // first and then the stop() method of the old CustomSite object, so that the + // reference counting can keep the resource objects alive during changeover + CustomSite.prototype.stop = async function() { + await _jst_server.Site.prototype.stop.call(this) - assert(this.zettair_cache === undefined) - this.zettair_cache = await this.resources.ref( - 'zettair_cache', - async () => new ZettairCache(true) - ) -} + assert(this.database !== undefined) + await this.resources.unref('database') -CustomSite.prototype.stop = async function() { - await _jst_server.Site.prototype.stop.call(this) + assert(this.emailjs_cache !== undefined) + await this.resources.unref('emailjs_cache') - assert(this.emailjs_cache !== undefined) - await this.resources.unref('emailjs_cache') + assert(this.zettair_cache !== undefined) + await this.resources.unref('zettair_cache') + } - assert(this.zettair_cache !== undefined) - await this.resources.unref('zettair_cache') -} + // called once per second, responsible for cache cleaning and flushing + CustomSite.prototype.kick = async function() { + await _jst_server.Site.prototype.kick.call(this) -CustomSite.prototype.kick = async function() { - await _jst_server.Site.prototype.kick.call(this) + assert(this.database !== undefined) + this.database.kick() - assert(this.emailjs_cache !== undefined) - this.emailjs_cache.kick() + assert(this.emailjs_cache !== undefined) + this.emailjs_cache.kick() - assert(this.zettair_cache !== undefined) - this.zettair_cache.kick() -} + assert(this.zettair_cache !== undefined) + this.zettair_cache.kick() + } -CustomSite.prototype.get_emailjs = function(pathname) { - return /*await*/ this.emailjs_cache.get(this.root + pathname) -} + // retrieves a particular email account (loaded into an emailjs object) + CustomSite.prototype.get_emailjs = function(pathname) { + return /*await*/ this.emailjs_cache.get(this.root + pathname) + } -CustomSite.prototype.get_zettair = function(pathname) { - return /*await*/ this.zettair_cache.get(this.root + pathname) -} + // retrieves a particular search index (node.js wrapper of a zettair object) + CustomSite.prototype.get_zettair = function(pathname) { + return /*await*/ this.zettair_cache.get(this.root + pathname) + } -CustomSite.prototype.respond = async function(env) { - if ( - env.parsed_url.pathname === '/node_modules' || - env.parsed_url.pathname.slice(0, 14) === '/node_modules/' || - env.parsed_url.pathname === '/package.json' || - env.parsed_url.pathname === '/package-lock.json' - ) { - this.die(env, `banned file ${env.parsed_url.pathname}`) - return + // customize the file search/serving algorithm for this particular website + CustomSite.prototype.respond = async function(env) { + if ( + env.parsed_url.pathname === '/node_modules' || + env.parsed_url.pathname.slice(0, 14) === '/node_modules/' || + env.parsed_url.pathname === '/package.json' || + env.parsed_url.pathname === '/package-lock.json' + ) { + this.die(env, `banned file ${env.parsed_url.pathname}`) + return + } + return /*await*/ _jst_server.Site.prototype.respond.call(this, env) } - return /*await*/ _jst_server.Site.prototype.respond.call(this, env) -} -return async (resources, root, prev_site) => new CustomSite( - resources, - root, - {}, - prev_site -) + return new CustomSite( + resources, + root, + {}, + prev_site + ) +} diff --git a/link.sh b/link.sh index 0894a32..09936fd 100755 --- a/link.sh +++ b/link.sh @@ -1,5 +1,5 @@ #!/bin/sh rm -rf node_modules package-lock.json -npm link @ndcode/emailjs_cache @ndcode/zettair_cache +npm link @ndcode/emailjs_cache @ndcode/logjson @ndcode/zettair_cache npm install npm link diff --git a/package.json b/package.json index 3b52d86..52a4ddc 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "directories": {}, "dependencies": { "@ndcode/emailjs_cache": "^0.1.0", + "@ndcode/logjson": "^0.1.0", "@ndcode/zettair_cache": "^0.1.0", "cookie": "^0.3.1", "querystring": "^0.2.0", diff --git a/page.jst b/page.jst index caef8d3..106b253 100644 --- a/page.jst +++ b/page.jst @@ -6,28 +6,21 @@ return async (env, head, body, scripts) => { let favicons = await env.site.get_min_html('/_favicon/favicons.html') let globals = await env.site.get_json('/_config/globals.json') - await env.site.ensure_dir('/_analytics') - let sessions = await env.site.read_json('/_analytics/sessions.json', {}) - let pageviews = await env.site.read_json('/_analytics/pageviews.json', {}) + let transaction = env.site.database.Transaction() + let root = await transaction.get(transaction.LazyObject()) + let sessions = await root.get('sessions', transaction.LazyObject()) + let pageviews = await root.get('pageviews', transaction.LazyObject()) let cookies = cookie.parse(env.request.headers.cookie || '') - let session_key - if ( - !Object.prototype.hasOwnProperty.call(cookies, 'session_key') || - !Object.prototype.hasOwnProperty.call( - sessions, - session_key = cookies.session_key - ) - ) { - session_key = crypto.randomBytes(16).toString('hex') - console.log('new session', session_key) - sessions[session_key] = {pageviews: {}} - } - let session = sessions[session_key] + let session_key = + Object.prototype.hasOwnProperty.call(cookies, 'session_key') ? + cookies.session_key : + crypto.randomBytes(16).toString('hex') + let session = await sessions.get(session_key, transaction.LazyObject()) let expires = new XDate() expires.addMonths(1) - session.expires = expires.toUTCString() + session.set('expires', expires.toUTCString()) env.response.setHeader( 'Set-Cookie', 'session_key=' + @@ -37,35 +30,30 @@ return async (env, head, body, scripts) => { '; path=/;' ) - if ( - !Object.prototype.hasOwnProperty.call( - pageviews, - env.parsed_url.pathname - ) - ) { - console.log('new pageview', env.parsed_url.pathname) - pageviews[env.parsed_url.pathname] = {visits: 0, unique_visits: 0} - } - let pageview = pageviews[env.parsed_url.pathname] - ++pageview.visits; + let pageview = await pageviews.get( + env.parsed_url.pathname, + transaction.LazyObject() + ) + pageview.set( + 'visits', + (await pageview.get('visits') || 0) + 1 + ) - //if (!Object.prototype.hasOwnProperty.call(session, 'pageviews')) - // session.pageviews = {} - let session_pageviews = session.pageviews - if ( - !Object.prototype.hasOwnProperty.call( - session_pageviews, - env.parsed_url.pathname + let session_pageviews = await session.get( + 'pageviews', + transaction.LazyObject() + ) + let i = await session_pageviews.get(env.parsed_url.pathname) + if (i === undefined) { + pageview.set( + 'unique_visits', + (await pageview.get('unique_visits') || 0) + 1 ) - ) { - console.log('new session_pageview', env.parsed_url.pathname) - session_pageviews[env.parsed_url.pathname] = 0 - ++pageview.unique_visits + i = 0 } - ++session_pageviews[env.parsed_url.pathname] + session_pageviews.set(env.parsed_url.pathname, i + 1) - env.site.write_json('/_analytics/sessions.json', sessions) - env.site.write_json('/_analytics/pageviews.json', pageviews) + await transaction.commit() let _out = [] _out.push('') -- 2.34.1