Skip to content

Commit d3e58a5

Browse files
committed
init
1 parent b76816d commit d3e58a5

16 files changed

+218
-60
lines changed

Readme.md

-45
This file was deleted.

config.example.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
},
2323
"redis": {
2424
"host": "127.0.0.1",
25-
"port": 3306,
25+
"port": 6379,
2626
"password": "",
2727
"database": 0
2828
},

core.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ const app = new Koa()
1414
const preStart = require('./src/prestart')
1515
preStart.load()
1616

17+
// Load CronJob
18+
const cron = require('./src/cron')
19+
cron.load()
20+
1721
// Register Middlewares (Plugins)
1822
async function registerMiddlewares () {
1923
try {
2024
const middlewares = require('./plugins')
2125
await middlewares.map((middleware, index, input) => {
2226
app.use(middleware)
2327
})
24-
winston.debug('All Plugins Loads done.')
28+
winston.verbose('All Plugins Load done.')
2529
} catch (e) {
2630
winston.error(e)
2731
// mail.error(e)
@@ -43,7 +47,7 @@ async function registerRoutes (routes) {
4347
// mail.error(err)
4448
process.exit(1)
4549
})
46-
winston.debug('All Routes Loads done.')
50+
winston.verbose('All Routes Load done.')
4751
} catch (e) {
4852
winston.error(e)
4953
// mail.error(e)

crons.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Register Cron Event
2+
module.exports = (cron) => {
3+
// return true
4+
return [
5+
// Register cron
6+
cron.countRequests
7+
]
8+
}

img/screenshot.png

-138 KB
Loading

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "teng-koa",
3-
"version": "0.0.1",
4-
"description": "Simple & fast REST API Framework.",
2+
"name": "Hitokoto-api",
3+
"version": "1.0.0",
4+
"description": "Fast & Powerful Hitokoto API Framework.",
55
"main": "core.js",
66
"engines": {
77
"node": ">=8"
@@ -34,6 +34,7 @@
3434
"bytes": "^3.0.0",
3535
"chalk": "^2.3.0",
3636
"colors": "^1.1.2",
37+
"cron": "^1.3.0",
3738
"humanize-number": "^0.0.2",
3839
"kcors": "^2.2.1",
3940
"koa": "^2.4.1",

plugins.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module.exports = [
44
// MiddleWares
55
require('./src/middlewares/requestId')(),
66
require('./src/middlewares/responseHandler')(),
7+
require('./src/middlewares/countRequest')(),
78

89
// Basic Plugins
910
require('koa-json')(),
@@ -16,7 +17,7 @@ module.exports = [
1617
require('kcors')({
1718
origin: '*',
1819
allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'],
19-
exposeHeaders: ['X-Request-Id']
20+
exposeHeaders: ['X-Request-Id', 'X-Api-Token'] // Need Api-token
2021
}),
2122
require('koa-favicon')(path.join(__dirname, './public/favicon.ico')),
2223
require('koa-compress')({

readme.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Hitokoto API
2+
目前该项目是针对 Hitokoto V1 的 PHP 框架的重新实现。
3+
同时更新了以下功能:
4+
* API 请求统计
5+
6+
## 开始使用
7+
1. `cp config.example.json config.json` 并配置好相关信息
8+
2. `yarn --production`
9+
3. `yarn start`

routes.js

+1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ module.exports = (router, controller) => {
99
})
1010

1111
router.get('/test', controller.hello.index)
12+
router.get('/status', controller.status.status)
1213
return router
1314
}

src/cache.js

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
'use strict'
2+
// Import Packages
23
const nconf = require('nconf')
34
const bluebrid = require('bluebird')
45
const winston = require('winston')
5-
const redis = require('redis')
66
// Promisify Redis
7-
bluebrid.promisifyAll(redis.RedisClient.prototype)
8-
bluebrid.promisifyAll(redis.Multi.prototype)
7+
const redis = bluebrid.promisifyAll(require('redis'))
98

109
class cache {
1110
static connect () {
12-
if (this.redis) {
11+
if (this.hasOwnProperty('redis')) {
1312
return true
1413
} else {
1514
// Get Config
1615
const config = {
1716
host: nconf.get('redis:host') || '127.0.0.1',
18-
port: nconf.get('redis:port') || 3306,
19-
password: nconf.get('redis:password') || '',
17+
port: nconf.get('redis:port') || 6379,
18+
password: nconf.get('redis:password') && nconf.get('redis:password') !== '' ? nconf.get('redis:password') : false,
2019
db: nconf.get('redis:database') || 0
2120
}
21+
if (!config.password) {
22+
delete config.password
23+
}
2224
// Connect Redis
2325
this.redis = redis.createClient(config)
2426
this.redis.on('error', err => {
2527
winston.error(err)
28+
process.exit(1)
2629
})
2730
return true
2831
}
@@ -36,7 +39,11 @@ class cache {
3639

3740
static set (key, value, time) {
3841
this.connect()
39-
return this.redis.setAsync('cache:' + key, value, 'EX', time)
42+
if (time) {
43+
return this.redis.setAsync('cache:' + key, value, 'EX', time)
44+
} else {
45+
return this.redis.setAsync('cache:' + key, value)
46+
}
4047
}
4148

4249
static get (key) {

src/controllers/status.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict'
2+
const path = require('path')
3+
const cache = require(path.join(__dirname, '../cache'))
4+
const winston = require('winston')
5+
async function getRequests () {
6+
const requests = await cache.get('requests')
7+
return requests
8+
}
9+
10+
async function getPastMinute () {
11+
const ts = parseInt(Date.now().toString().slice(0, 10)) - 60
12+
const requests = await cache.get('requests:count:' + ts.toString())
13+
return requests
14+
}
15+
16+
async function getPastHour () {
17+
const ts = parseInt(Date.now().toString().slice(0, 10)) - 60 * 60
18+
const requests = await cache.get('requests:count:' + ts.toString())
19+
return requests
20+
}
21+
22+
async function getPastDay () {
23+
const ts = parseInt(Date.now().toString().slice(0, 10)) - 60 * 60 * 24
24+
const requests = await cache.get('requests:count:' + ts.toString())
25+
return requests
26+
}
27+
28+
module.exports = {
29+
status: async (ctx, next) => {
30+
const now = await getRequests()
31+
const pastMinute = await getPastMinute()
32+
const pastHour = await getPastHour()
33+
const pastDay = await getPastDay()
34+
ctx.body = {
35+
requests: {
36+
all: parseInt(now),
37+
pastMinute: parseInt(now) - parseInt(pastMinute),
38+
pastHour: parseInt(now) - parseInt(pastHour),
39+
pastDay: parseInt(now) - parseInt(pastDay)
40+
},
41+
now: new Date(Date.now()).toString(),
42+
ts: Date.now()
43+
}
44+
}
45+
}

src/cron.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use strict'
2+
// Import Packages
3+
const winston = require('winston')
4+
const path = require('path')
5+
const fs = require('fs')
6+
const colors = require('colors/safe')
7+
const CronJob = require('cron').CronJob
8+
9+
// Load Cron
10+
class cron {
11+
static async load () {
12+
try {
13+
// load crons
14+
let crons = await this.autoLoad()
15+
const cronMap = require(path.join(__dirname, '../crons.js'))(crons)
16+
if (cronMap === true) {
17+
// AutoLoad All Crons
18+
crons = await this.autoLoad(true)
19+
await crons.map((item, index, input) => {
20+
// Register CronJob
21+
const job = new CronJob(item[0], item[1], item[2], item[3], item[4])
22+
job.start()
23+
})
24+
winston.verbose('All Cron Jobs Load done.')
25+
} else {
26+
await cronMap.map((item, index, input) => {
27+
// Register CronJob
28+
const job = new CronJob(item[0], item[1], item[2], item[3], item[4])
29+
job.start()
30+
})
31+
winston.verbose('All Cron Jobs Load done.')
32+
}
33+
} catch (e) {
34+
winston.error(colors.red(e))
35+
process.exit(1)
36+
}
37+
}
38+
39+
static async autoLoad (isArray) {
40+
try {
41+
// Load Crons
42+
let crons = {}
43+
const dir = fs.readdirSync(path.join(__dirname, '../', './src/crons'))
44+
if (isArray) {
45+
await dir.map((item, index, input) => {
46+
crons[index] = module.parent.require(path.join(__dirname, '../', './src/crons/' + item))
47+
})
48+
} else {
49+
await dir.map((item, index, input) => {
50+
crons[item.substring(0, item.length - 3)] = module.parent.require(path.join(__dirname, '../', './src/crons/' + item))
51+
})
52+
}
53+
return crons
54+
} catch (e) {
55+
winston.error(colors.red(e))
56+
process.exit(1)
57+
}
58+
}
59+
}
60+
module.exports = cron

src/crons/countRequests.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
function saveCount (ts, count) {
8+
cache.set('requests:count:' + ts, count, 60 * 60 * 25)
9+
.catch(err => {
10+
winston.error(err)
11+
saveCount(ts, count)
12+
})
13+
}
14+
15+
module.exports = [
16+
'* * * * * *', // Cron Config
17+
() => {
18+
// Do something
19+
cache.get('requests')
20+
.then(requests => {
21+
const request = requests ? parseInt(requests) : 0
22+
const ts = Date.now().toString().slice(0, 10)
23+
saveCount(ts, request)
24+
winston.debug('Save Count to Cache. Requests: ' + request)
25+
})
26+
.catch(err => {
27+
winston.error(err)
28+
})
29+
},
30+
() => {
31+
// This function is executed when the job stops
32+
winston.error('Count Requests job is stopped. Kill process.')
33+
process.exit(1)
34+
},
35+
true, // Start the job right now,
36+
'Asia/Shanghai' // Timezone
37+
]

src/middlewares/countRequest.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
3+
function countRequest () {
4+
const path = require('path')
5+
const cache = require(path.join(__dirname, '../', 'cache'))
6+
const winston = require('winston')
7+
return async (ctx, next) => {
8+
await next()
9+
// Wait Request Done
10+
await cache.get('requests')
11+
.then(requests => {
12+
requests = requests || '0'
13+
cache.set('requests', parseInt(requests) + 1)
14+
.catch(err => {
15+
winston.error(err)
16+
})
17+
})
18+
.catch(err => {
19+
winston.error(err)
20+
})
21+
}
22+
}
23+
24+
module.exports = countRequest

src/models/databases/hitokoto.js

Whitespace-only changes.

yarn.lock

+7-1
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,12 @@ core-util-is@~1.0.0:
468468
version "1.0.2"
469469
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
470470

471+
cron@^1.3.0:
472+
version "1.3.0"
473+
resolved "https://registry.yarnpkg.com/cron/-/cron-1.3.0.tgz#7e459968eaf94e1a445be796ce402166c234659d"
474+
dependencies:
475+
moment-timezone "^0.5.x"
476+
471477
cross-spawn@^4:
472478
version "4.0.2"
473479
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
@@ -1607,7 +1613,7 @@ mocha@^5.0.0:
16071613
mkdirp "0.5.1"
16081614
supports-color "4.4.0"
16091615

1610-
moment-timezone@^0.5.4:
1616+
moment-timezone@^0.5.4, moment-timezone@^0.5.x:
16111617
version "0.5.14"
16121618
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.14.tgz#4eb38ff9538b80108ba467a458f3ed4268ccfcb1"
16131619
dependencies:

0 commit comments

Comments
 (0)