8944a3f57968d017e57e18886d700afc9b037bca
[ndcode_site.git] / _config / site.jst
1 let assert = require('assert')
2 let logjson = (await import('@ndcode/logjson')).default
3 let EmailJSCache = require('@ndcode/emailjs_cache')
4 let XDate = require('xdate')
5 let ZettairCache = require('@ndcode/zettair_cache')
6
7 return async (resources, root, prev_site) => {
8   class CustomSite extends _jst_server.Site {
9     constructor(resources, root, options, prev_site) {
10       super(resources, root, options, prev_site)
11       this.database = undefined
12       this.database_date = new XDate().toUTCString('yyyyMMdd')
13       this.emailjs_cache = undefined
14       this.zettair_cache = undefined
15     }
16
17     // called when the server starts or the site.jst file is modified
18     // in latter case it will carry over the previously created resource objects
19     async start() {
20       await _jst_server.Site.prototype.start.call(this)
21
22       assert(this.database === undefined)
23       this.database = await this.resources.ref(
24         'database',
25         async () => {
26           let database = new logjson.Database()
27           await database.open(this.root + '/database.logjson')
28           return database
29         }
30       )
31
32       assert(this.emailjs_cache === undefined)
33       this.emailjs_cache = await this.resources.ref(
34         'emailjs_cache',
35         async () => new EmailJSCache(true)
36       )
37
38       assert(this.zettair_cache === undefined)
39       this.zettair_cache = await this.resources.ref(
40         'zettair_cache',
41         async () => new ZettairCache(true)
42       )
43     }
44
45     // called when the server starts or the site.jst file is modified
46     // in latter case the start() method of the new CustomSite object is called
47     // first and then the stop() method of the old CustomSite object, so that the
48     // reference counting can keep the resource objects alive during changeover
49     async stop() {
50       await _jst_server.Site.prototype.stop.call(this)
51
52       assert(this.database !== undefined)
53       await this.resources.unref('database')
54
55       assert(this.emailjs_cache !== undefined)
56       await this.resources.unref('emailjs_cache')
57
58       assert(this.zettair_cache !== undefined)
59       await this.resources.unref('zettair_cache')
60     }
61
62     // called once per second, responsible for cache cleaning and flushing
63     async kick() {
64       await _jst_server.Site.prototype.kick.call(this)
65
66       assert(this.database !== undefined)
67       await this.database.kick()
68
69       let new_database_date = new XDate().toUTCString('yyyyMMdd')
70       if (new_database_date !== this.database_date) {
71         console.log(
72           'rotate database',
73           this.database_date,
74           '->',
75           new_database_date
76         )
77         await this.database.rotate('database.logjson.' + this.database_date)
78         this.database_date = new_database_date
79       }
80
81       assert(this.emailjs_cache !== undefined)
82       this.emailjs_cache.kick()
83
84       assert(this.zettair_cache !== undefined)
85       this.zettair_cache.kick()
86     }
87
88     // retrieves a particular email account (loaded into an emailjs object)
89     get_emailjs(pathname) {
90       return /*await*/ this.emailjs_cache.get(this.root + pathname)
91     }
92
93     // retrieves a particular search index (node.js wrapper of a zettair object)
94     get_zettair(pathname) {
95       return /*await*/ this.zettair_cache.get(this.root + pathname)
96     }
97
98     // customize the file search/serving algorithm for this particular website
99     async respond(env) {
100       if (
101         env.parsed_url.pathname === '/node_modules' ||
102         env.parsed_url.pathname.slice(0, 14) === '/node_modules/' ||
103         env.parsed_url.pathname === '/package.json' ||
104         env.parsed_url.pathname === '/package-lock.json'
105       ) {
106         this.die(env, `banned file ${env.parsed_url.pathname}`)
107         return
108       }
109       return /*await*/ _jst_server.Site.prototype.respond.call(this, env)
110     }
111   }
112
113   return new CustomSite(
114     resources,
115     root,
116     {},
117     prev_site
118   )
119 }