Skip to content

Commit 00ee2d9

Browse files
committed
Memcache based Hitokoto
1 parent 84ed12a commit 00ee2d9

File tree

4 files changed

+99
-35
lines changed

4 files changed

+99
-35
lines changed

src/controllers/hitokoto.js

+51-34
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,73 @@ const iconv = require('iconv-lite')
33
const path = require('path')
44
const SrcDir = path.join('../../', './src/')
55
const db = require(SrcDir + 'db')
6-
7-
async function hitokoto (ctx, next) {
8-
// Connect Database
6+
let Hitokoto
7+
async function syncHitokotoList () {
8+
const result = {}
99
const hitokoto = await db.registerModel('hitokoto')
10+
// Fetch All Data
11+
result.all = await hitokoto.find({
12+
attributes: {
13+
exclude: ['from_who', 'creator_uid', 'assessor', 'owner']
14+
}
15+
})
16+
// Generate Categroy List
17+
result.categroy = {}
18+
for (let sentence of result.all) {
19+
if (!result.categroy[sentence.type]) {
20+
// Init Categroy List
21+
result.categroy[sentence.type] = []
22+
}
23+
result.categroy[sentence.type].push(sentence)
24+
}
25+
// fill TS
26+
result.lastUpdate = Date.now()
27+
// Update Data
28+
Hitokoto = result
29+
}
30+
async function hitokoto (ctx, next) {
31+
// judge whether data is exist
32+
if (!Hitokoto) {
33+
// Sync Data
34+
await syncHitokotoList()
35+
} else if ((Date.now() - Hitokoto.lastUpdate) > 1000 * 60 * 60 * 2) {
36+
// Data is outdate. async update.
37+
syncHitokotoList()
38+
}
1039
if (ctx.query && ctx.query.c) {
1140
// exist params c
12-
const ret = await hitokoto.findOne({
13-
where: {
14-
type: ctx.query.c
15-
},
16-
attributes: {
17-
exclude: ['from_who', 'creator_uid', 'assessor', 'owner']
18-
},
19-
order: db.sequelize.random()
20-
})
21-
if (!ret) {
41+
if (!Hitokoto.categroy[ctx.query.c]) {
2242
ctx.status = 404
2343
ctx.body = {
2444
status: 404,
2545
message: '很抱歉,该分类下尚无条目'
2646
}
2747
return
2848
}
49+
// Random Sentence
50+
const sentence = Hitokoto.categroy[ctx.query.c][Math.floor(Math.random() * Hitokoto.categroy[ctx.query.c].length)]
2951
// CheckEncoding
3052
const encode = ctx.query.encode
3153
const gbk = (ctx.query && ctx.query.charset && ctx.query.charset.toLocaleLowerCase() === 'gbk') ? !!'gbk' : false
3254
switch (encode) {
3355
case 'json':
3456
if (gbk) {
3557
ctx.set('Content-Type', 'application/json; charset=gbk')
36-
ctx.body = iconv.encode(JSON.stringify(ret), 'GBK')
58+
ctx.body = iconv.encode(JSON.stringify(sentence), 'GBK')
3759
} else {
38-
ctx.body = ret
60+
ctx.body = sentence
3961
}
4062
break
4163
case 'text':
4264
if (gbk) {
4365
ctx.set('Content-Type', 'text/plain; charset=gbk')
44-
ctx.body = iconv.encode(ret.hitokoto, 'GBK')
66+
ctx.body = iconv.encode(sentence.hitokoto, 'GBK')
4567
}
46-
ctx.body = ret.hitokoto
68+
ctx.body = sentence.hitokoto
4769
break
4870
case 'js':
4971
const select = ctx.query.select ? ctx.query.select : '.hitokoto'
50-
const response = `(function hitokoto(){var hitokoto="${ret.hitokoto}";var dom=document.querySelector('${select}');Array.isArray(dom)?dom[0].innerText=hitokoto:dom.innerText=hitokoto;})()`
72+
const response = `(function hitokoto(){var hitokoto="${sentence.hitokoto}";var dom=document.querySelector('${select}');Array.isArray(dom)?dom[0].innerText=hitokoto:dom.innerText=hitokoto;})()`
5173
if (gbk) {
5274
ctx.set('Content-Type', 'text/javascript; charset=gbk')
5375
ctx.body = iconv.encode(response, 'GBK')
@@ -59,43 +81,38 @@ async function hitokoto (ctx, next) {
5981
default:
6082
if (gbk) {
6183
ctx.set('Content-Type', 'application/json; charset=gbk')
62-
ctx.body = iconv.encode(JSON.stringify(ret), 'GBK')
84+
ctx.body = iconv.encode(JSON.stringify(sentence), 'GBK')
6385
} else {
64-
ctx.body = ret
86+
ctx.body = sentence
6587
}
6688
break
6789
}
6890
} else {
6991
// Not Params or just has callback
70-
const ret = await hitokoto.findOne({
71-
attributes: {
72-
exclude: ['from_who', 'creator_uid', 'assessor', 'owner']
73-
},
74-
order: db.sequelize.random()
75-
})
76-
92+
// Random Sentence
93+
const sentence = Hitokoto.all[Math.floor(Math.random() * Hitokoto.all.length)]
7794
// CheckEncoding
7895
const encode = ctx.query.encode
7996
const gbk = (ctx.query && ctx.query.charset && ctx.query.charset.toLocaleLowerCase() === 'gbk') ? !!'gbk' : false
8097
switch (encode) {
8198
case 'json':
8299
if (gbk) {
83100
ctx.set('Content-Type', 'application/json; charset=gbk')
84-
ctx.body = iconv.encode(JSON.stringify(ret), 'GBK')
101+
ctx.body = iconv.encode(JSON.stringify(sentence), 'GBK')
85102
} else {
86-
ctx.body = ret
103+
ctx.body = sentence
87104
}
88105
break
89106
case 'text':
90107
if (gbk) {
91108
ctx.set('Content-Type', 'text/plain; charset=gbk')
92-
ctx.body = iconv.encode(ret.hitokoto, 'GBK')
109+
ctx.body = iconv.encode(sentence.hitokoto, 'GBK')
93110
}
94-
ctx.body = ret.hitokoto
111+
ctx.body = sentence.hitokoto
95112
break
96113
case 'js':
97114
const select = ctx.query.select ? ctx.query.select : '.hitokoto'
98-
const response = `(function hitokoto(){var hitokoto="${ret.hitokoto}";var dom=document.querySelector('${select}');Array.isArray(dom)?dom[0].innerText=hitokoto:dom.innerText=hitokoto;})()`
115+
const response = `(function hitokoto(){var hitokoto="${sentence.hitokoto}";var dom=document.querySelector('${select}');Array.isArray(dom)?dom[0].innerText=hitokoto:dom.innerText=hitokoto;})()`
99116
if (gbk) {
100117
ctx.set('Content-Type', 'text/javascript; charset=gbk')
101118
ctx.body = iconv.encode(response, 'GBK')
@@ -107,9 +124,9 @@ async function hitokoto (ctx, next) {
107124
default:
108125
if (gbk) {
109126
ctx.set('Content-Type', 'application/json; charset=gbk')
110-
ctx.body = iconv.encode(JSON.stringify(ret), 'GBK')
127+
ctx.body = iconv.encode(JSON.stringify(sentence), 'GBK')
111128
} else {
112-
ctx.body = ret
129+
ctx.body = sentence
113130
}
114131
break
115132
}

src/controllers/status.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,14 @@ module.exports = async (ctx, next) => {
127127
const limitHost = [
128128
'v1.hitokoto.cn',
129129
'api.hitokoto.cn',
130-
'sslapi.hitokoto.cn'
130+
'sslapi.hitokoto.cn',
131+
'api.a632079.me'
131132
]
132133
for (let i of limitHost) {
134+
if (!fetchData[4][i]) {
135+
// if not exist, continue
136+
continue
137+
}
133138
hosts[i] = {}
134139
hosts[i].total = fetchData[4][i]
135140
hosts[i].pastMinute = fetchData[5] ? parseInt(fetchData[4][i]) - parseInt(fetchData[5][i]) : null

src/crons/dumpOriginStatistics.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict'
2+
// Import Packages
3+
const winston = require('winston')
4+
const path = require('path')
5+
const cache = require(path.join(__dirname, '../cache'))
6+
7+
module.exports = [
8+
'* * * * * *', // Cron Config
9+
() => {
10+
// Do something
11+
if (global.originStatistics) {
12+
cache.set(`statistics:orgin:${new Date(new Date().toDateString()).getTime()}`, global.originStatistics, 60 * 60 * 25)
13+
}
14+
},
15+
() => {
16+
// This function is executed when the job stops
17+
winston.error('Count Requests job is stopped. Kill process.')
18+
process.exit(1)
19+
},
20+
true, // Start the job right now,
21+
'Asia/Shanghai' // Timezone
22+
]

src/crons/resetOriginStatistics.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict'
2+
// Import Packages
3+
const winston = require('winston')
4+
// const path = require('path')
5+
// const cache = require(path.join(__dirname, '../cache'))
6+
7+
module.exports = [
8+
'* * * * * *', // Cron Config
9+
() => {
10+
// Do something
11+
global.originStatistics = {}
12+
},
13+
(job) => {
14+
// This function is executed when the job stops
15+
winston.error('Count Requests job is stopped. Kill process.')
16+
process.exit(1)
17+
},
18+
true, // Start the job right now,
19+
'Asia/Shanghai' // Timezone
20+
]

0 commit comments

Comments
 (0)