const fs = require('fs') const path = require('path') const Koa = require('koa') const Router = require('koa-router') const bodyParser = require('koa-bodyparser') const LRU = require('lru-cache') const WebSocket = require('ws') const koaStatic = require('koa-static') const { routerOptions, lruOptions, watchFileOptions, filePath, ports } = require('./config') const { dataPath, reviewDataPath, staticPath } = filePath const { appPort, wsPort } = ports const router = new Router(routerOptions) const cache = new LRU(lruOptions) let STATIC_DATA = '' const readFile = () => { fs.readFile(dataPath, (err, buf) => { if (err) { console.error(err) return } STATIC_DATA = buf.toString().replace('\n', '').split(',') }) } readFile() setInterval(() => { readFile() }, 60 * 60 * 24e3) fs.watchFile(dataPath, watchFileOptions, (curr, prev) => { if (curr.mtime !== prev.mtime) { STATIC_DATA = '' fs.readFile(dataPath, (err, buf) => { if (err) { console.error(err) return } STATIC_DATA = buf.toString().split(',') }) } }) const app = new Koa() const wss = new WebSocket.Server({ port: wsPort }) app.use(koaStatic(path.join(__dirname, staticPath))) wss.on('connection', ws => { ws.on('message', msg => { if (msg) { try { const res = JSON.parse(msg) console.log('msg: ', res) if (res.code) { const list = cache.get(res.code) if (res.status === 'update') { const data = JSON.stringify({ data: list }) wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(data) } }) } else if (res.status === 'over') { list.forEach(el => { el.status = 1 }) const data = JSON.stringify({ data: list }) wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(data) } }) } } } catch (error) { console.error(error) } } }) }) app.use(bodyParser()) // 判断是不是api // app.use((ctx, next) => { // const url = ctx.url // const isApi = /^\/api/.test(url) // ctx.$isApi = isApi // next() // }) router.get('/list', (ctx, next) => { const { code } = ctx.query let data if (cache.has(code)) { data = cache.get(code) } else { const jsonData = STATIC_DATA || '' const len = 25 const sum = jsonData.length - len const arr = new Array(25).fill(1).map(el => Math.floor(Math.random() * sum)) const groupList = [1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0] data = new Array(25).fill(1).map((el, i) => { const del = groupList.length ? Math.floor(Math.random() * groupList.length) : 0 const group = groupList.splice(del, 1)[0] return { text: jsonData.splice(arr[i], 1)[0], status: 0, group } }) cache.set(code, data) } ctx.body = { code, data } }) router.put('/status/:code', ctx => { const { params, request } = ctx const { code } = params const { index } = request.body const list = cache.get(code) || [] if (!index && index !== 0) { throw new Error('index is not find') } if (!list || !list.length) { throw new Error('cache list is not find') } list[index].status = list[index].status ? 0 : 1 cache.set(code, list) ctx.body = { success: true, msg: '更新成功', data: list[index] } }) router.post('/words', ctx => { const { request } = ctx const { words = '' } = request.body const wordsList = words.split(',') const noExist = [] const exist = wordsList.filter(el => { if (STATIC_DATA.indexOf(el) !== -1) { return true } noExist.push(el) return false }) const pushNewWords = noExist.join(',') fs.appendFile(reviewDataPath, pushNewWords, (err) => { if (err) { console.error('appendFile error:', err) } }) let body = {} if (exist.length) { body = { success: false, exist } } else { body = { success: true } } ctx.body = body }) router.get('/reviews', ctx => { const buf = fs.readFileSync(reviewDataPath) const text = buf.toString() let list = [] if (text) { list = text.split(',') } ctx.body = { success: true, list } }) router.post('/reviews', ctx => { const { request } = ctx const { words = '' } = request.body const wordsList = words.split(',') const noExist = [] const exist = wordsList.filter(el => { if (STATIC_DATA.indexOf(el) !== -1) { return true } if (el) { noExist.push(el) } return false }) try { fs.appendFileSync(dataPath, `,${noExist.join(',')}`) fs.writeFile(reviewDataPath, '', err => { if (err) { return console.error('clear reviewData error:', err) } }) if (exist.length) { ctx.body = { success: true, msg: `${exist.join(',')} 添加失败,词已存在` } } else { ctx.body = { success: true, msg: '添加成功' } } } catch (error) { console.error('appendFile error:', error) ctx.body = { success: false, msg: JSON.stringify(error) } } }) app.use(router.routes()).use(router.allowedMethods()) app.on('error', err => console.error(err)) app.listen(appPort) console.log(`http://127.0.0.1:${appPort}`)