From 2c8c3a09e5091c0aa1749157cf1901a05b57f96d Mon Sep 17 00:00:00 2001 From: "chibing.fy" Date: Mon, 5 Aug 2019 19:17:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=92=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.定时清除锁定 2.优化仓库查询 3.升级包 --- package.json | 5 +++- src/config/config.dev.ts | 4 +-- src/config/config.local.ts | 2 +- src/config/config.prod.ts | 4 +-- src/routes/mock.ts | 8 ++++-- src/routes/repository.ts | 55 ++++++++++++++++++++++++++------------ src/routes/router.ts | 2 +- src/routes/utils/const.ts | 11 +++++++- src/routes/utils/url.ts | 1 + src/scripts/app.ts | 3 +++ src/service/task.ts | 28 +++++++++++++++++++ src/types/index.d.ts | 4 +-- 12 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 src/service/task.ts diff --git a/package.json b/package.json index dcfbcc6..f09183f 100644 --- a/package.json +++ b/package.json @@ -43,13 +43,14 @@ "node-fetch": "^2.6.0", "node-print": "0.0.4", "nodemailer": "^6.2.1", + "node-schedule": "^1.3.2", "notevil": "^1.3.1", "path-to-regexp": "^3.0.0", "redis": "^2.8.0", "reflect-metadata": "^0.1.13", "request": "^2.88.0", "request-promise": "^4.2.4", - "sequelize": "^5.8.7", + "sequelize": "^5.10.1", "sequelize-typescript": "^1.0.0-beta.3", "svg-captcha": "^1.4.0", "underscore": "^1.9.1", @@ -70,9 +71,11 @@ "@types/mockjs": "^1.0.2", "@types/node": "^12.0.3", "@types/nodemailer": "^6.2.0", + "@types/node-schedule": "^1.2.3", "@types/redis": "^2.8.13", "@types/request": "^2.48.1", "@types/request-promise": "^4.1.44", + "@types/sequelize": "^4.28.4", "@types/underscore": "^1.8.18", "babel-eslint": "^10.0.1", "chai": "^4.2.0", diff --git a/src/config/config.dev.ts b/src/config/config.dev.ts index 8f440b8..e5f871c 100644 --- a/src/config/config.dev.ts +++ b/src/config/config.dev.ts @@ -1,10 +1,10 @@ import { IConfigOptions } from "../types" let config: IConfigOptions = { - version: '2.3', + version: 'v2.1.0', serve: { port: 8080, - path: "", // 服务context path + path: '', }, keys: ['some secret hurr'], session: { diff --git a/src/config/config.local.ts b/src/config/config.local.ts index a437aa4..e6017fc 100644 --- a/src/config/config.local.ts +++ b/src/config/config.local.ts @@ -4,7 +4,7 @@ let config: IConfigOptions = { version: '2.3', serve: { port: 8080, - path: "", // 服务context path + path: '', }, keys: ['some secret hurr'], session: { diff --git a/src/config/config.prod.ts b/src/config/config.prod.ts index 8195960..19876be 100644 --- a/src/config/config.prod.ts +++ b/src/config/config.prod.ts @@ -1,11 +1,11 @@ import { IConfigOptions } from "../types" // 先从环境变量取配置 -let config: IConfigOptions = { +let config: IConfigOptions = { version: '2.3', serve: { port: (process.env.EXPOSE_PORT && parseInt(process.env.EXPOSE_PORT)) || 8080, - path: process.env.EXPOSE_PATH || "" , // 服务context path + path: '', }, keys: ['some secret hurr'], session: { diff --git a/src/routes/mock.ts b/src/routes/mock.ts index d49efa2..7d49547 100644 --- a/src/routes/mock.ts +++ b/src/routes/mock.ts @@ -100,7 +100,6 @@ router.get('/app/plugin/:repositories', async (ctx) => { result.push(generatePlugin(protocol, ctx.host, repository)) } - ctx.enco ctx.type = 'application/x-javascript; charset=utf-8' ctx.body = result.join('\n') }) @@ -246,7 +245,7 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => { } } } else if (listMatched.length === 0) { - ctx.body = {isOk: false, errMsg: '未匹配到任何接口 No matched interface'} + ctx.body = { isOk: false, errMsg: '未匹配到任何接口 No matched interface' } return } else { loadDataId = listMatched[0].id @@ -302,6 +301,11 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => { ctx.type = 'json' ctx.status = itf.status ctx.body = JSON.stringify(data, undefined, 2) + const Location = data.Location + if (Location && itf.status === 301) { + ctx.redirect(Location) + return + } if (itf && itf.url.indexOf('[callback]=') > -1) { const query = querystring.parse(itf.url.substring(itf.url.indexOf('?') + 1)) const cbName = query['[callback]'] diff --git a/src/routes/repository.ts b/src/routes/repository.ts index dbbfe07..63da637 100644 --- a/src/routes/repository.ts +++ b/src/routes/repository.ts @@ -176,26 +176,47 @@ router.get('/repository/get', async (ctx) => { return } const tryCache = await RedisService.getCache(CACHE_KEY.REPOSITORY_GET, ctx.query.id) - let repository: Repository + let repository: Partial if (tryCache) { repository = JSON.parse(tryCache) } else { - repository = await Repository.findByPk(ctx.query.id, { - attributes: { exclude: [] }, - include: [ - QueryInclude.Creator, - QueryInclude.Owner, - QueryInclude.Locker, - QueryInclude.Members, - QueryInclude.Organization, - QueryInclude.RepositoryHierarchy, - QueryInclude.Collaborators - ], - order: [ - [{ model: Module, as: 'modules' }, 'priority', 'asc'], - [{ model: Module, as: 'modules' }, { model: Interface, as: 'interfaces' }, 'priority', 'asc'] - ] as any - }) + // 分开查询减少 + let [repositoryOmitModules, repositoryModules] = await Promise.all([ + Repository.findByPk(ctx.query.id, { + attributes: { exclude: [] }, + include: [ + QueryInclude.Creator, + QueryInclude.Owner, + QueryInclude.Locker, + QueryInclude.Members, + QueryInclude.Organization, + QueryInclude.Collaborators, + QueryInclude.Domains + ] + }), + Repository.findByPk(ctx.query.id, { + attributes: { exclude: [] }, + include: [QueryInclude.RepositoryHierarchy], + order: [ + [{ model: Module, as: 'modules' }, 'priority', 'asc'], + [ + { model: Module, as: 'modules' }, + { model: Interface, as: 'interfaces' }, + 'priority', + 'asc' + ] + ] + }) + ]) + repository = { + ...repositoryOmitModules.toJSON(), + ...repositoryModules.toJSON() + } + await RedisService.setCache( + CACHE_KEY.REPOSITORY_GET, + JSON.stringify(repository), + ctx.query.id + ) await RedisService.setCache(CACHE_KEY.REPOSITORY_GET, JSON.stringify(repository), ctx.query.id) } ctx.body = { diff --git a/src/routes/router.ts b/src/routes/router.ts index d278d42..95dae1b 100644 --- a/src/routes/router.ts +++ b/src/routes/router.ts @@ -1,7 +1,7 @@ import * as Router from 'koa-router' import config from '../config' -let router = new Router({prefix: config.serve.path}) + let router = new Router({prefix: config.serve.path}) // index router.get('/', (ctx) => { diff --git a/src/routes/utils/const.ts b/src/routes/utils/const.ts index f1e06a5..948243e 100644 --- a/src/routes/utils/const.ts +++ b/src/routes/utils/const.ts @@ -6,4 +6,13 @@ export const COMMON_ERROR_RES = { ERROR_PARAMS: { isOk: false, errMsg: '参数错误' }, ACCESS_DENY: { isOk: false, errMsg: '您没有访问权限' }, NOT_LOGIN: { isOk: false, errMsg: '您未登陆,或登陆状态过期。请登陆后重试' }, -} \ No newline at end of file +} + +export enum DATE_CONST { + SECOND = 1000, + MINUTE = 1000 * 60, + HOUR = 1000 * 60 * 60, + DAY = 1000 * 60 * 60 * 24, + MONTH = 1000 * 60 * 60 * 24 * 30, + YEAR = 1000 * 60 * 60 * 24 * 365, +} diff --git a/src/routes/utils/url.ts b/src/routes/utils/url.ts index 8bbd55f..5a06ce8 100644 --- a/src/routes/utils/url.ts +++ b/src/routes/utils/url.ts @@ -29,6 +29,7 @@ export default class UrlUtils { let re = pathToRegexp(pattern) return re.test(url) } + public static getUrlPattern = (pattern: string) => { pattern = UrlUtils.getRelative(pattern) return pathToRegexp(pattern) diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 7f5614d..877e51c 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -8,6 +8,7 @@ import * as cors from 'kcors' import * as bodyParser from 'koa-body' import router from '../routes' import config from '../config' +import { startTask } from '../service/task' const app = new Koa() let appAny: any = app @@ -54,4 +55,6 @@ app.use(bodyParser({ multipart: true })) app.use(router.routes()) +startTask() + export default app \ No newline at end of file diff --git a/src/service/task.ts b/src/service/task.ts new file mode 100644 index 0000000..ca196b2 --- /dev/null +++ b/src/service/task.ts @@ -0,0 +1,28 @@ +import * as schedule from 'node-schedule' +import { Interface } from '../models' +import { Op } from 'sequelize' +import { DATE_CONST } from '../routes/utils/const' + +export async function startTask() { + + console.log(`Starting task: locker check`) + + /** + * 每5分钟检查lock超时 + */ + schedule.scheduleJob('*/5 * * * *', async () => { + // tslint:disable-next-line: no-null-keyword + const [num] = await Interface.update({ lockerId: null }, { + where: { + lockerId: { + [Op.gt]: 0, + }, + updatedAt: { + [Op.lt]: new Date(Date.now() - DATE_CONST.DAY), + }, + }, + }) + + num > 0 && console.log(`cleared ${num} locks`) + }) +} \ No newline at end of file diff --git a/src/types/index.d.ts b/src/types/index.d.ts index a88872a..bfcb809 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -14,8 +14,8 @@ declare interface RedisAndClusterOptions extends RedisOptions { declare interface IConfigOptions { version: string serve: { - port: number, - path: string + port: number + path: string // Context Path }, keys: string[] session: {