From e7156a7c22f59765f8d6e1009d71594fbbdfd69a Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 18 May 2021 13:17:42 +0800 Subject: [PATCH] core: better discussion sort method --- .eslintrc.yaml | 1 + packages/hydrooj/package.json | 2 +- packages/hydrooj/src/handler/discussion.ts | 2 +- packages/hydrooj/src/interface.ts | 2 ++ packages/hydrooj/src/model/discussion.ts | 32 +++++++++++++++++++++- packages/hydrooj/src/model/task.ts | 11 +++----- packages/hydrooj/src/upgrade.ts | 12 ++++++++ 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 5aa9c168..976157a7 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -39,6 +39,7 @@ rules: max-len: - warn - 150 + newline-per-chained-call: 0 no-bitwise: 0 no-console: 0 no-continue: 0 diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 35ba9b75..4f8ab983 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.26.10", + "version": "2.26.11", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/handler/discussion.ts b/packages/hydrooj/src/handler/discussion.ts index a863d070..7f537d06 100644 --- a/packages/hydrooj/src/handler/discussion.ts +++ b/packages/hydrooj/src/handler/discussion.ts @@ -158,7 +158,7 @@ class DiscussionCreateHandler extends DiscussionHandler { await this.limitRate('add_discussion', 3600, 60); let name: ObjectID | string | number; if (ObjectID.isValid(_name)) name = new ObjectID(_name); - else if (isSafeInteger(parseInt(_name, 10))) name = parseInt(_name, 10); + else if (isSafeInteger(+name)) name = +name; else name = _name; if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION); if (pin) this.checkPerm(PERM.PERM_PIN_DISCUSSION); diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 1ee53e80..fe794276 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -360,6 +360,8 @@ declare module './model/discussion' { nReply: number, views: number, history: HistoryDoc[], + sort: number, + lastRCount: number, } } diff --git a/packages/hydrooj/src/model/discussion.ts b/packages/hydrooj/src/model/discussion.ts index c10cee9e..feda948d 100644 --- a/packages/hydrooj/src/model/discussion.ts +++ b/packages/hydrooj/src/model/discussion.ts @@ -1,9 +1,11 @@ import { FilterQuery, ObjectID } from 'mongodb'; import { omit } from 'lodash'; +import moment from 'moment'; import problem from './problem'; import * as contest from './contest'; import * as training from './training'; import * as document from './document'; +import TaskModel from './task'; import { DiscussionNodeNotFoundError, DocumentNotFoundError } from '../error'; import { DiscussionReplyDoc, DiscussionTailReplyDoc, Document } from '../interface'; import { buildProjection } from '../utils'; @@ -82,6 +84,7 @@ export async function add( pin, updateAt: new Date(), views: 0, + sort: 100, }; await bus.serial('discussion/before-add', payload); const res = await document.add( @@ -125,7 +128,7 @@ export function count(domainId: string, query: FilterQuery) { export function getMulti(domainId: string, query: FilterQuery = {}, projection = PROJECTION_LIST) { return document.getMulti(domainId, document.TYPE_DISCUSSION, query) - .sort({ pin: -1, updateAt: -1 }) + .sort({ pin: -1, sort: -1 }) .project(buildProjection(projection)); } @@ -277,6 +280,33 @@ bus.on('problem/delete', async (domainId, docId) => { ]); }); +const t = Math.exp(-0.15); + +async function updateSort() { + const cursor = document.coll.find({ docType: document.TYPE_DISCUSSION }); + while (cursor.hasNext()) { + // eslint-disable-next-line no-await-in-loop + const data = await cursor.next(); + // eslint-disable-next-line no-await-in-loop + const rCount = await getMultiReply(data.domainId, data.docId).count(); + const sort = ((data.sort || 100) + Math.max(rCount - (data.lastRCount || 0), 0) * 10) * t; + // eslint-disable-next-line no-await-in-loop + await document.coll.updateOne({ _id: data._id }, { $set: { sort, lastRCount: rCount } }); + } +} +TaskModel.Worker.addHandler('discussion.sort', updateSort); + +bus.once('app/started', async () => { + if (!await TaskModel.count({ type: 'schedule', subType: 'discussion.sort' })) { + await TaskModel.add({ + type: 'schedule', + subType: 'discussion.sort', + executeAfter: moment().minute(0).second(0).millisecond(0).toDate(), + interval: [1, 'hour'], + }); + } +}); + global.Hydro.model.discussion = { typeDisplay, DiscussionDoc, diff --git a/packages/hydrooj/src/model/task.ts b/packages/hydrooj/src/model/task.ts index 24bffcb8..7b6fae00 100644 --- a/packages/hydrooj/src/model/task.ts +++ b/packages/hydrooj/src/model/task.ts @@ -25,14 +25,10 @@ async function getFirst(query: FilterQuery) { class Consumer { consuming: boolean; running?: any; - filter: any; - func: Function; timeout: NodeJS.Timeout; - constructor(filter: any, func: Function) { + constructor(public filter: any, public func: Function, public destoryOnError = true) { this.consuming = true; - this.filter = filter; - this.func = func; this.get = this.get.bind(this); this.get(); } @@ -48,7 +44,7 @@ class Consumer { } } catch (e) { logger.error(e); - this.destory(); + if (this.destoryOnError) this.destory(); } this.timeout = setTimeout(this.get, 100); } @@ -71,6 +67,7 @@ class WorkerService implements BaseService { logger.debug('Worker task: %o', doc); return this.handlers[doc.subType](doc); }, + false, ); this.started = true; } @@ -113,7 +110,7 @@ class TaskModel { static async getDelay(query?: FilterQuery) { const now = new Date(); - const [res] = await coll.find(query).sort({ executeAfter: 1 }).limit(1).toArray(); + const res = await coll.findOne(query, { sort: { executeAfter: 1 } }); if (res) return [Math.max(0, now.getTime() - res.executeAfter.getTime()), res.executeAfter]; return [0, now]; } diff --git a/packages/hydrooj/src/upgrade.ts b/packages/hydrooj/src/upgrade.ts index f2127e3a..3544a1ee 100644 --- a/packages/hydrooj/src/upgrade.ts +++ b/packages/hydrooj/src/upgrade.ts @@ -20,6 +20,7 @@ import db from './service/db'; import difficultyAlgorithm from './lib/difficulty'; import problem from './model/problem'; import user from './model/user'; +import * as discussion from './model/discussion'; import domain from './model/domain'; import * as document from './model/document'; import * as system from './model/system'; @@ -352,6 +353,17 @@ const scripts: UpgradeScript[] = [ }); return true; }, + async function _27_28() { + const cursor = document.coll.find({ docType: document.TYPE_DISCUSSION }); + while (cursor.hasNext()) { + const data = await cursor.next(); + const t = Math.exp(-0.15 * (((new Date().getTime() / 1000) - data._id.generationTime) / 3600)); + const rCount = await discussion.getMultiReply(data.domainId, data.docId).count(); + const sort = ((data.sort || 100) + Math.max(rCount - (data.lastRCount || 0), 0) * 10) * t; + await document.coll.updateOne({ _id: data._id }, { $set: { sort, lastRCount: rCount } }); + } + return true; + }, ]; export default scripts;