diff --git a/TODOLIST.md b/TODOLIST.md index 122df67..6260308 100644 --- a/TODOLIST.md +++ b/TODOLIST.md @@ -11,6 +11,6 @@ - [ ] 接入统计 - [x] 配置文件写入初始化用户账号密码 - [ ] 接入AuthBox -- [ ] Redis 接入 +- [x] Redis 接入 - [x] 支持Session - - [ ] 缓存整理 \ No newline at end of file + - [x] 缓存整理 \ No newline at end of file diff --git a/package.json b/package.json index 4bc41fc..3020418 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@types/fs-extra": "^4.0.4", "@types/hasha": "^3.0.0", "@types/helmet": "0.0.37", + "@types/is-promise": "^2.1.0", "@types/lodash": "^4.14.85", "@types/md5": "^2.1.32", "@types/mocha": "^2.2.44", @@ -67,6 +68,7 @@ "typescript": "^2.6.1" }, "dependencies": { + "@keyv/redis": "^1.3.8", "@nestjs/common": "4.6.5", "@nestjs/core": "4.6.5", "@nestjs/swagger": "1.1.4", @@ -82,6 +84,8 @@ "fs-extra": "^4.0.2", "hasha": "^3.0.0", "helmet": "^3.11.0", + "is-promise": "^2.1.0", + "keyv": "^3.0.0", "lodash": "^4.17.4", "md5": "^2.2.1", "md5-file": "^3.2.3", @@ -90,7 +94,6 @@ "path-exists": "^3.0.0", "reflect-metadata": "^0.1.10", "rxjs": "^5.5.2", - "schedule-cache": "^1.0.0", "useragent": "^2.2.1", "uuid": "^3.1.0", "y-config": "^1.1.5" diff --git a/src/models/Categroy.ts b/src/models/Categroy.ts index 6e1797b..8bc8fda 100644 --- a/src/models/Categroy.ts +++ b/src/models/Categroy.ts @@ -5,9 +5,15 @@ import { DEF_PER_COUNT } from "@dtos/page"; import { isArray } from "util"; import { reduce, includes, difference } from "lodash"; import { MongoError } from "mongodb"; -import Cache = require("schedule-cache"); +import { config } from "@utils/config"; +import keyv = require("keyv"); -export const cache = Cache.create(`${Date.now()}${Math.random()}`); +import { isTest } from "../modules/common/helper/env"; + +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Categories" +}); export const FLAG = "categories"; export type CategoryDoc = IDoc; diff --git a/src/models/Collection.ts b/src/models/Collection.ts index 370c775..c68ceb6 100644 --- a/src/models/Collection.ts +++ b/src/models/Collection.ts @@ -4,11 +4,17 @@ import { } from "@models/common"; import { IGoods, FLAG as GoodFlag, Model as GoodsModels } from "@models/Good"; import { IUser, FLAG as UserFlag } from "@models/User"; -import Cache = require("schedule-cache"); +import { config } from "@utils/config"; +import keyv = require("keyv"); -export const FLAG = "collections"; +import { isTest } from "../modules/common/helper/env"; + +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Collections" +}); -export const cache = Cache.create(`${Date.now()}${Math.random()}`); +export const FLAG = "collections"; const Definition: SchemaDefinition = { name: { diff --git a/src/models/Good.ts b/src/models/Good.ts index bd96b28..b0604ac 100644 --- a/src/models/Good.ts +++ b/src/models/Good.ts @@ -5,9 +5,15 @@ import { import { IValues, Flag as ValueFlag } from "@models/Value"; import { IUser, FLAG as UserFlag } from "@models/User"; import { ICategory, FLAG as CategoryFlag } from "@models/Categroy"; -import Cache = require("schedule-cache"); +import { config } from "@utils/config"; +import keyv = require("keyv"); -const cache = Cache.create(`${Date.now()}${Math.random()}`); +import { isTest } from "../modules/common/helper/env"; + +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Goods" +}); export const FLAG = "goods"; export type GoodDoc = IDoc; diff --git a/src/models/Regexp.ts b/src/models/Regexp.ts index 7ef62d1..2e1494b 100644 --- a/src/models/Regexp.ts +++ b/src/models/Regexp.ts @@ -4,12 +4,17 @@ import { } from "@models/common"; import { ICategory, FLAG as CF, Model as CM } from "@models/Categroy"; import { DEF_PER_COUNT } from "@dtos/page"; -import Cache = require("schedule-cache"); import isRegExp = require("@utils/isRegExp"); +import { config } from "@utils/config"; +import keyv = require("keyv"); import { INewRegexp } from "../modules/regexps/regexps.dto"; +import { isTest } from "../modules/common/helper/env"; -export const cache = Cache.create(`${Date.now()}${Math.random()}`); +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Regexps" +}); const Definition: SchemaDefinition = { name: { type: String, required: true, unique: true }, diff --git a/src/models/Token.ts b/src/models/Token.ts index 17bd2bb..3eff4a7 100644 --- a/src/models/Token.ts +++ b/src/models/Token.ts @@ -3,10 +3,15 @@ import { Base, IDoc, IDocRaw, ObjectId, MODIFY_MOTHODS, existsValidator } from "@models/common"; import { IUser, FLAG as UserFlag } from "@models/User"; +import { config } from "@utils/config"; +import keyv = require("keyv"); -import Cache = require("schedule-cache"); +import { isTest } from "../modules/common/helper/env"; -export const cache = Cache.create(`${Date.now()}${Math.random()}`); +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Tokens" +}); export const Flag = "tokens"; diff --git a/src/models/User.ts b/src/models/User.ts index 4206ecd..6b10a86 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -3,10 +3,15 @@ import * as md5 from "md5"; import { config } from "@utils/config"; import { ObjectId, existsValidator } from "@models/common"; import { DEF_PER_COUNT } from "@dtos/page"; -import Cache = require("schedule-cache"); import { Base, IDoc, IDocRaw, MODIFY_MOTHODS } from "./common"; +import keyv = require("keyv"); -const cache = Cache.create(`${Date.now()}${Math.random()}`); +import { isTest } from "../modules/common/helper/env"; + +export const cache = new keyv({ + uri: isTest ? undefined : config.redis.url, + namespace: "Users" +}); export const FLAG = "users"; diff --git a/src/modules/common/services/base.service.ts b/src/modules/common/services/base.service.ts index 01246de..fdb8474 100644 --- a/src/modules/common/services/base.service.ts +++ b/src/modules/common/services/base.service.ts @@ -1,8 +1,8 @@ import { DEF_PER_COUNT } from "@dtos/page"; import { UtilService } from "@services/util"; import { DocumentQuery, ModelPopulateOptions } from "mongoose"; - -type TimeType = number | string; +import keyv = require("keyv"); +import isPromise = require("is-promise"); export interface IGetOptions { populate?: Array; @@ -14,28 +14,30 @@ export abstract class BaseService { protected readonly DEF_UPDATE_OPTIONS = { runValidators: true, context: "query" }; - private cache; + private cache: keyv; - protected setCache(cache) { + protected setCache(cache: keyv) { this.cache = cache; } - protected loadAndCache( - FLAG: string, value: () => T, time?: TimeType - ): T { + protected async loadAndCache( + FLAG: string, value: () => Promise, time?: number + ): Promise; + protected async loadAndCache( + FLAG: string, value: () => T, time = 1000 * 60 * 5 // 5 min + ): Promise { if (!this.cache) { return value(); } - const c = this.cache.get(FLAG); + const c: T = await this.cache.get(FLAG); if (c) { return c; } - const val = value(); - if (time) { - this.cache.put(FLAG, val, time); - } else { - this.cache.put(FLAG, val); + let val = value(); + if (isPromise(val)) { + val = await val; } + await this.cache.set(FLAG, val, time); return val; } diff --git a/src/modules/common/services/categories.service.ts b/src/modules/common/services/categories.service.ts index 4682356..63f7087 100644 --- a/src/modules/common/services/categories.service.ts +++ b/src/modules/common/services/categories.service.ts @@ -109,7 +109,9 @@ export class CategoriesService extends BaseService { } public count() { - return CategoriesModel.count({ }).exec(); + return this.loadAndCache( + "count", () => CategoriesModel.count({ }).exec() + ); } public async add(ctx: object) { diff --git a/src/modules/common/services/regexps.service.ts b/src/modules/common/services/regexps.service.ts index 1bd47f5..af73eaa 100644 --- a/src/modules/common/services/regexps.service.ts +++ b/src/modules/common/services/regexps.service.ts @@ -92,20 +92,32 @@ export class RegexpsService extends BaseService { } public count() { - const FLAG = "totalCount"; + const FLAG = "total"; return this.loadAndCache( FLAG, () => RegexpsModel.count({ }).exec() ); } - public getById(id: ObjectId, opts?: IGetOptions) { - let p = RegexpsModel.findById(id) - .populate({ path: "link", populate: { path: "pid" } }); + public get(conditions: object, opts?: IGetOptions) { + let p = RegexpsModel.find(conditions); p = this.documentQueryProcess(p, opts); return p.exec(); } + public async getById(id: ObjectId, opts?: IGetOptions) { + const extraPopulate = { path: "link", populate: { path: "pid" } }; + if (!opts) { + opts = { }; + } + if (opts.populate) { + opts.populate.push(extraPopulate); + } else { + opts.populate = [ extraPopulate ]; + } + return (await this.get({ _id: id }, opts))[0]; + } + /** * 规则列表 * @param perNum {number} 每页数量 @@ -129,6 +141,9 @@ export class RegexpsService extends BaseService { const DEF_CONDITIONS = { link: { $exists: true }, hidden: false }; + const DEF_OPTIONS = { + populate: [ "link" ] + }; if (opts.categroies && opts.categroies.length > 0) { // 指定Categroy @@ -141,7 +156,10 @@ export class RegexpsService extends BaseService { }; return this.loadAndCache( FLAG, - () => RegexpsModel.find(conditions).populate("link").exec(), + async () => { + const result = await this.get(conditions, DEF_OPTIONS); + return result.map((item) => item.toObject()); + }, 50 ); } else if (opts.appends && opts.appends.length > 0) { @@ -155,14 +173,20 @@ export class RegexpsService extends BaseService { }; return this.loadAndCache( FLAG, - () => RegexpsModel.find(conditions).populate("link").exec(), + async () => { + const result = await this.get(conditions, DEF_OPTIONS); + return result.map((item) => item.toObject()); + }, 50 ); } else { const FLAG = "default_scan_regexps"; return this.loadAndCache( FLAG, - () => RegexpsModel.find(DEF_CONDITIONS).populate("link").exec(), + async () => { + const result = await this.get(DEF_CONDITIONS, DEF_OPTIONS); + return result.map((item) => item.toObject()); + }, 50 ); } @@ -176,7 +200,7 @@ export class RegexpsService extends BaseService { const result = await this.getRegexps(opts); const list = [ ]; result.forEach((item) => { - const obj = item.toObject(); + const obj = item; const reg = new RegExp(obj.value); if (reg.test(name)) { list.push(obj.link); diff --git a/src/modules/common/services/users.service.ts b/src/modules/common/services/users.service.ts index 96aeb0a..ba03ca0 100644 --- a/src/modules/common/services/users.service.ts +++ b/src/modules/common/services/users.service.ts @@ -98,7 +98,10 @@ export class UsersService extends BaseService { * 返回总数 */ public conut() { - return UsersModel.count({ }).exec(); + return this.loadAndCache( + "count", + () => UsersModel.count({ }).exec() + ); } /** @@ -108,9 +111,13 @@ export class UsersService extends BaseService { * @param opts.page {number} 页数 */ public list(opts = this.DEF_PER_OBJ) { - return UsersModel.find().select("-password") - .skip((opts.page - 1) * opts.perNum).limit(opts.perNum) - .exec(); + const Flag = `list_${opts.perNum}_${opts.page}`; + return this.loadAndCache( + Flag, + () => UsersModel.find().select("-password") + .skip((opts.page - 1) * opts.perNum).limit(opts.perNum) + .exec() + ); } /** diff --git a/src/modules/goods/goods.controller.ts b/src/modules/goods/goods.controller.ts index ee92ec0..b400240 100644 --- a/src/modules/goods/goods.controller.ts +++ b/src/modules/goods/goods.controller.ts @@ -134,8 +134,9 @@ export class GoodsAdminController { } catch (error) { if (cb) { cb("Good", error); + } else { + throw error; } - return; } const newFilePath = `${config.paths.upload}/${categories[0]._id}/${obj.file.filename}`; @@ -222,22 +223,18 @@ export class GoodsAdminController { if (goods.length === 0) { throw new BadRequestException("The Collection no good"); } else { - try { - const collections = await this.collectionsSvr.create({ - goods: goods.reduce((arr, good) => { - arr.push(good._id); - return arr; - }, []), - creator: uploaderId - }); - const collection = - isArray(collections) ? collections[0] : collections; - return this.collectionsSvr.getById(collection._id, { - populate: [ "goods" ] - }); - } catch (error) { - throw new BadRequestException(error.toString()); - } + const collections = await this.collectionsSvr.create({ + goods: goods.reduce((arr, good) => { + arr.push(good._id); + return arr; + }, []), + creator: uploaderId + }); + const collection = + isArray(collections) ? collections[0] : collections; + return this.collectionsSvr.getById(collection._id, { + populate: [ "goods" ] + }); } }