tkserver 1.7.9 → 1.7.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,7 @@ tkserver
19
19
  | `MONGODB_URI` | MongoDB 数据库连接字符串,不传则使用 lokijs | `null` |
20
20
  | `MONGO_URL` | MongoDB 数据库连接字符串,不传则使用 lokijs | `null` |
21
21
  | `TWIKOO_DATA` | lokijs 数据库存储路径 | `./data` |
22
+ | `TWIKOO_HOST` | 自定义监听的主机名或IP地址(例如 0.0.0.0 或 127.0.0.1),设置该值则会忽略 TWIKOO_LOCALHOST_ONLY,默认值为 null 但实际行为会回退到 `::` | `null` |
22
23
  | `TWIKOO_PORT` | 端口号 | `8080` |
23
24
  | `TWIKOO_THROTTLE` | IP 请求限流,当同一 IP 短时间内请求次数超过阈值将对该 IP 返回错误 | `250` |
24
25
  | `TWIKOO_LOCALHOST_ONLY` | 为`true`时只监听本地请求,使得 nginx 等服务器反代之后不暴露原始端口 | `null` |
package/index.js CHANGED
@@ -69,6 +69,7 @@ const TWIKOO_REQ_TIMES_CLEAR_TIME = parseInt(process.env.TWIKOO_REQ_TIMES_CLEAR_
69
69
  let db = null
70
70
  let config
71
71
  let requestTimes = {}
72
+ let requestTimesTimer = null
72
73
 
73
74
  connectToDatabase()
74
75
 
@@ -1065,8 +1066,36 @@ function getIp (request) {
1065
1066
  return getUserIP(request)
1066
1067
  }
1067
1068
 
1069
+ async function closeDatabase () {
1070
+ if (!db) return
1071
+ try {
1072
+ await new Promise((resolve, reject) => {
1073
+ db.saveDatabase((err) => {
1074
+ if (err) {
1075
+ reject(err)
1076
+ } else {
1077
+ resolve()
1078
+ }
1079
+ })
1080
+ })
1081
+ } finally {
1082
+ db.close()
1083
+ db = null
1084
+ }
1085
+ }
1086
+
1087
+ async function shutdown () {
1088
+ if (requestTimesTimer) {
1089
+ clearInterval(requestTimesTimer)
1090
+ requestTimesTimer = null
1091
+ }
1092
+ await closeDatabase()
1093
+ }
1094
+
1068
1095
  function clearRequestTimes () {
1069
1096
  requestTimes = {}
1070
1097
  }
1071
1098
 
1072
- setInterval(clearRequestTimes, TWIKOO_REQ_TIMES_CLEAR_TIME)
1099
+ requestTimesTimer = setInterval(clearRequestTimes, TWIKOO_REQ_TIMES_CLEAR_TIME)
1100
+
1101
+ module.exports.shutdown = shutdown
package/mongo.js CHANGED
@@ -66,6 +66,8 @@ const TWIKOO_REQ_TIMES_CLEAR_TIME = parseInt(process.env.TWIKOO_REQ_TIMES_CLEAR_
66
66
  let db = null
67
67
  let config
68
68
  let requestTimes = {}
69
+ let client = null
70
+ let requestTimesTimer = null
69
71
 
70
72
  module.exports = async (request, response) => {
71
73
  let accessToken
@@ -225,7 +227,7 @@ async function connectToDatabase (uri) {
225
227
  if (!uri) throw new Error('未设置环境变量 MONGODB_URI | MONGO_URL')
226
228
  // If no connection is cached, create a new one
227
229
  logger.info('Connecting to database...')
228
- const client = await MongoClient.connect(uri, {})
230
+ client = await MongoClient.connect(uri, {})
229
231
  // Select the database through the connection,
230
232
  // using the database path of the connection string
231
233
  const dbName = (new URL(uri)).pathname.substring(1) || 'twikoo'
@@ -1037,8 +1039,22 @@ function getIp (request) {
1037
1039
  return getUserIP(request)
1038
1040
  }
1039
1041
 
1042
+ async function shutdown () {
1043
+ if (requestTimesTimer) {
1044
+ clearInterval(requestTimesTimer)
1045
+ requestTimesTimer = null
1046
+ }
1047
+ if (client) {
1048
+ await client.close()
1049
+ client = null
1050
+ db = null
1051
+ }
1052
+ }
1053
+
1040
1054
  function clearRequestTimes () {
1041
1055
  requestTimes = {}
1042
1056
  }
1043
1057
 
1044
- setInterval(clearRequestTimes, TWIKOO_REQ_TIMES_CLEAR_TIME)
1058
+ requestTimesTimer = setInterval(clearRequestTimes, TWIKOO_REQ_TIMES_CLEAR_TIME)
1059
+
1060
+ module.exports.shutdown = shutdown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tkserver",
3
- "version": "1.7.9",
3
+ "version": "1.7.10",
4
4
  "description": "A simple comment system.",
5
5
  "keywords": [
6
6
  "twikoo",
@@ -31,7 +31,7 @@
31
31
  "get-user-ip": "^1.0.1",
32
32
  "lokijs": "^1.5.12",
33
33
  "mongodb": "^6.3.0",
34
- "twikoo-func": "1.7.9",
34
+ "twikoo-func": "1.7.10",
35
35
  "uuid": "^8.3.2"
36
36
  }
37
37
  }
package/server.js CHANGED
@@ -6,8 +6,20 @@ const logger = require('twikoo-func/utils/logger')
6
6
  const dbUrl = process.env.MONGODB_URI || process.env.MONGO_URL || null
7
7
  const twikoo = dbUrl ? require('./mongo') : require('./index')
8
8
  const server = http.createServer()
9
+ const sockets = new Set()
10
+ const TWIKOO_SHUTDOWN_TIMEOUT = parseInt(process.env.TWIKOO_SHUTDOWN_TIMEOUT) || 5000
11
+ let isShuttingDown = false
12
+ let shuttingDownPromise = null
9
13
 
10
14
  server.on('request', async function (request, response) {
15
+ if (isShuttingDown) {
16
+ response.writeHead(503, {
17
+ Connection: 'close',
18
+ 'Content-Type': 'application/json'
19
+ })
20
+ response.end(JSON.stringify({ code: 503, message: 'Twikoo server is shutting down' }))
21
+ return
22
+ }
11
23
  try {
12
24
  const buffers = []
13
25
  for await (const chunk of request) {
@@ -31,10 +43,83 @@ server.on('request', async function (request, response) {
31
43
  return await twikoo(request, response)
32
44
  })
33
45
 
46
+ server.on('connection', (socket) => {
47
+ sockets.add(socket)
48
+ socket.on('close', () => sockets.delete(socket))
49
+ })
50
+
34
51
  const port = parseInt(process.env.TWIKOO_PORT) || 8080
35
- const host = process.env.TWIKOO_LOCALHOST_ONLY === 'true' ? 'localhost' : '::'
52
+ const host = process.env.TWIKOO_HOST || (process.env.TWIKOO_LOCALHOST_ONLY === 'true' ? 'localhost' : '::')
36
53
 
37
54
  server.listen(port, host, function () {
38
55
  logger.info(`Twikoo is using ${dbUrl ? 'mongo' : 'loki'} database`)
39
56
  logger.info(`Twikoo function started on host ${host} port ${port}`)
40
57
  })
58
+
59
+ function closeServer () {
60
+ return new Promise((resolve, reject) => {
61
+ server.close((err) => {
62
+ if (err) {
63
+ reject(err)
64
+ } else {
65
+ resolve()
66
+ }
67
+ })
68
+ })
69
+ }
70
+
71
+ function destroySockets () {
72
+ for (const socket of sockets) {
73
+ socket.destroy()
74
+ }
75
+ }
76
+
77
+ async function shutdownWithTimeout () {
78
+ let timeoutId
79
+ const closeTask = closeServer()
80
+ const timeoutTask = new Promise((resolve) => {
81
+ timeoutId = setTimeout(() => {
82
+ logger.warn(`Twikoo server shutdown timed out after ${TWIKOO_SHUTDOWN_TIMEOUT}ms, destroying open connections`)
83
+ destroySockets()
84
+ resolve()
85
+ }, TWIKOO_SHUTDOWN_TIMEOUT)
86
+ })
87
+ await Promise.race([closeTask, timeoutTask])
88
+ clearTimeout(timeoutId)
89
+ await closeTask
90
+ }
91
+
92
+ async function runShutdown (signal) {
93
+ isShuttingDown = true
94
+ logger.info(`Received ${signal}, shutting down Twikoo server...`)
95
+ try {
96
+ await shutdownWithTimeout()
97
+ } catch (e) {
98
+ logger.error('Twikoo HTTP server shutdown failed:', e)
99
+ } finally {
100
+ if (typeof twikoo.shutdown === 'function') {
101
+ await twikoo.shutdown()
102
+ }
103
+ }
104
+ logger.info('Twikoo server stopped')
105
+ }
106
+
107
+ async function shutdown (signal) {
108
+ if (!shuttingDownPromise) {
109
+ shuttingDownPromise = runShutdown(signal)
110
+ }
111
+ return await shuttingDownPromise
112
+ }
113
+
114
+ async function handleSignal (signal) {
115
+ try {
116
+ await shutdown(signal)
117
+ process.exitCode = 0
118
+ } catch (e) {
119
+ logger.error('Twikoo server shutdown failed:', e)
120
+ process.exitCode = 1
121
+ }
122
+ }
123
+
124
+ process.on('SIGTERM', () => handleSignal('SIGTERM'))
125
+ process.on('SIGINT', () => handleSignal('SIGINT'))