From ee78271a840e70a2f0d5ac2607d872e573c4007e Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 25 Jul 2020 19:23:48 +0800 Subject: [PATCH] remove server.log setting item --- hydro/error.ts | 37 +++++++++++++++++++----------------- hydro/handler/domain.ts | 9 ++++++--- hydro/handler/home.ts | 4 ++-- hydro/handler/misc.ts | 9 --------- hydro/handler/user.ts | 6 +++--- hydro/interface.ts | 40 +++++++++++++++++++++++++++++++++++---- hydro/lib/jwt.ts | 1 - hydro/lib/logger.ts | 6 ------ hydro/lib/mail.ts | 1 - hydro/lib/misc.ts | 23 +++++++++++----------- hydro/lib/nav.ts | 2 +- hydro/lib/paginate.ts | 6 ++++-- hydro/lib/rating.ts | 19 +++++++++++-------- hydro/lib/validator.ts | 18 ++---------------- hydro/model/blacklist.ts | 12 +++++++++++- hydro/model/discussion.ts | 28 +++++++++++++++++---------- hydro/model/message.ts | 4 ++-- hydro/model/problem.ts | 10 ++++++---- hydro/model/record.ts | 2 -- hydro/model/setting.ts | 1 - hydro/model/token.ts | 1 - hydro/options.ts | 9 ++++++++- hydro/script/rating.ts | 2 +- hydro/service/monitor.ts | 11 ++++++++++- hydro/service/server.ts | 4 ++-- hydro/utils.ts | 6 +++--- package.json | 2 +- 27 files changed, 159 insertions(+), 114 deletions(-) diff --git a/hydro/error.ts b/hydro/error.ts index e1ef92c8c..cccb4ae3f 100644 --- a/hydro/error.ts +++ b/hydro/error.ts @@ -1,21 +1,24 @@ /* eslint-disable func-names */ -const { isClass } = require('./utils'); +import { isClass } from './utils'; interface IHydroError { - new(...args: any[]): HydroError + new(...args: any[]): HydroError } -const Err = (name: string, ...info: Array) => { +function isHydroError(item: any): item is IHydroError { + return isClass(item); +} + +const Err = (name: string, ...info: Array string) | string | number>) => { let Class: IHydroError; - let msg; - let code; + let msg: () => string; + let code: number; for (const item of info) { if (typeof item === 'number') { code = item; } else if (typeof item === 'string') { msg = function () { return item; }; - } else if (isClass(item)) { - // @ts-ignore + } else if (isHydroError(item)) { Class = item; } else if (typeof item === 'function') { msg = item; @@ -29,19 +32,19 @@ const Err = (name: string, ...info: Array; +export type Pdict = NumericDictionary; export interface TestCase { time: number, @@ -245,7 +245,38 @@ export interface Bdoc { expireAt: Date, } -interface ContestStat extends Dictionary { +// Discussion +export interface Ddoc { + _id: ObjectID, + docType: number, + docId: ObjectID, + owner: number, + title: string, + content: string, + ip: string, +} + +// Discussion reply +export interface Drdoc { + _id: ObjectID, + docType: number, + docId: ObjectID, + parentType: number, + parentId: ObjectID, + owner: number, + ip: string, + reply: Drrdoc[], +} + +// Discussion Tail Reply +export interface Drrdoc { + _id: ObjectID, + owner: number, + content: string, + ip: string, +} + +export interface ContestStat extends Dictionary { detail: any, } @@ -330,6 +361,7 @@ declare global { gridfs: GridFSBucket, monitor: typeof import('./service/monitor'), server: typeof import('./service/server'), + [key: string]: any, }, lib: { download: typeof import('./lib/download').default, @@ -363,9 +395,9 @@ declare global { }, error: typeof import('./error'), locales: Dict>, - postInit: Function[], + postInit: Array<() => Promise>, }, - onDestory: Function[], + onDestory: Array<() => void>, addons: string[], } } diff --git a/hydro/lib/jwt.ts b/hydro/lib/jwt.ts index e41334841..509b3b993 100644 --- a/hydro/lib/jwt.ts +++ b/hydro/lib/jwt.ts @@ -27,7 +27,6 @@ function decodeJWT(idToken: string) { } } -// eslint-disable-next-line import/prefer-default-export export function decode(idToken: string) { const decodedJWT = decodeJWT(idToken); return decodedJWT.payload; diff --git a/hydro/lib/logger.ts b/hydro/lib/logger.ts index 0d7baff62..718644ebe 100644 --- a/hydro/lib/logger.ts +++ b/hydro/lib/logger.ts @@ -6,12 +6,6 @@ function wrap(func: Function, type: string) { func(...args); if (global.Hydro.model.message) { try { - for (let i = 0; i <= args.length; i++) { - if (args[i] instanceof Error) { - // js-yaml cannot dump [object Error] - args[i] = `${args[i].message}\n${args[i].stack}`; - } - } global.Hydro.model.message.send(1, 1, serialize({ time, type, args }), 0); } catch (e) { func(e.message); diff --git a/hydro/lib/mail.ts b/hydro/lib/mail.ts index 6862779c1..7d5827106 100644 --- a/hydro/lib/mail.ts +++ b/hydro/lib/mail.ts @@ -1,7 +1,6 @@ import nodemailer from 'nodemailer'; import { SendMailError } from '../error'; -// eslint-disable-next-line import/prefer-default-export export async function sendMail(to: string, subject: string, text: string, html: string) { let t: unknown; try { diff --git a/hydro/lib/misc.ts b/hydro/lib/misc.ts index db5bb016f..5de94f04a 100644 --- a/hydro/lib/misc.ts +++ b/hydro/lib/misc.ts @@ -1,19 +1,20 @@ import AnsiUp from 'ansi_up'; +import { ObjectID } from 'mongodb'; import md5 from './md5'; const AU = new AnsiUp(); -export function ansiToHtml(str) { +export function ansiToHtml(str: string) { return AU.ansi_to_html(str); } -export function gravatar(email, s = 32) { +export function gravatar(email: string, s = 32) { return `//gravatar.loli.net/avatar/${md5((email || '').toString().trim().toLowerCase())}?d=mm&s=${s}`; } -export function datetimeSpan(dt, relative = true, format = '%Y-%m-%d %H:%M:%S') { +export function datetimeSpan(dt: Date | ObjectID, relative = true, format = '%Y-%m-%d %H:%M:%S') { if (!dt) return 'DATETIME_SPAN_ERROR'; - if (dt.generationTime) dt = new Date(dt.generationTime * 1000); + if (dt instanceof ObjectID) dt = new Date(dt.generationTime * 1000); else if (typeof dt === 'number' || typeof dt === 'string') dt = new Date(dt); return '{2}'.format( relative ? ' relative' : '', @@ -22,9 +23,10 @@ export function datetimeSpan(dt, relative = true, format = '%Y-%m-%d %H:%M:%S') ); } -export function* paginate(page, numPages) { - const radius = 2; let first; let - last; +export function* paginate(page: number, numPages: number) { + const radius = 2; + let first: number; + let last: number; if (page > 1) { yield ['first', 1]; yield ['previous', page - 1]; @@ -45,7 +47,7 @@ export function* paginate(page, numPages) { yield ['last', numPages]; } -export function size(s, base = 1) { +export function size(s: number, base = 1) { s *= base; const unit = 1024; const unitNames = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; @@ -53,12 +55,11 @@ export function size(s, base = 1) { if (s < unit) return '{0} {1}'.format(Math.round(s * 10) / 10, unitName); s /= unit; } - return '{0} {1}'.format(Math.round(s * unit), unitNames[unitNames.length - 1]); + return `${Math.round(s * unit)} ${unitNames[unitNames.length - 1]}`; } function _digit2(number: number) { - if (number < 10) return `0${number}`; - return number.toString(); + return number < 10 ? `0${number}` : number.toString(); } export function formatSeconds(_seconds = '0') { diff --git a/hydro/lib/nav.ts b/hydro/lib/nav.ts index 62a82bd9a..e0a03a9b3 100644 --- a/hydro/lib/nav.ts +++ b/hydro/lib/nav.ts @@ -12,7 +12,7 @@ const Checker = (perm: bigint, priv: number, checker: Function = trueChecker) => const Item = ( name: string, args: any, prefix: string, - ...permPrivChecker: Array> + ...permPrivChecker: Array ) => { let _priv: number; let _perm: bigint; diff --git a/hydro/lib/paginate.ts b/hydro/lib/paginate.ts index cd38eae38..8cb8f5a76 100644 --- a/hydro/lib/paginate.ts +++ b/hydro/lib/paginate.ts @@ -1,6 +1,9 @@ +import { Cursor } from 'mongodb'; import { ValidationError } from '../error'; -async function paginate(cursor: import('mongodb').Cursor, page: number, pageSize: number): Promise<[any[], number, number]> { +export default async function paginate( + cursor: Cursor, page: number, pageSize: number, +): Promise<[any[], number, number]> { if (page <= 0) throw new ValidationError('page'); const [count, pageDocs] = await Promise.all([ cursor.count(), @@ -11,4 +14,3 @@ async function paginate(cursor: import('mongodb').Cursor, page: number, pageSize } global.Hydro.lib.paginate = paginate; -export default paginate; diff --git a/hydro/lib/rating.ts b/hydro/lib/rating.ts index c445dfcfc..f56e12171 100644 --- a/hydro/lib/rating.ts +++ b/hydro/lib/rating.ts @@ -1,12 +1,16 @@ class User { - rank: any; + rank: number; - old: any; + old: number; seed: number; uid: number; + delta?: number; + + new: number; + constructor(rank: number, old: number, uid = 0) { this.rank = rank; this.old = old; @@ -16,7 +20,7 @@ class User { } class RatingCalculator { - users: any; + users: User[]; constructor(users) { this.users = []; @@ -26,11 +30,11 @@ class RatingCalculator { } // eslint-disable-next-line class-methods-use-this - calP(a, b) { + calP(a: User, b: User) { return 1 / (1 + 10 ** ((b.old - a.old) / 400)); } - getExSeed(rating, ownUser) { + getExSeed(rating: number, ownUser: User) { const exUser = new User(0.0, rating); let result = 1; for (const user of this.users) { @@ -39,7 +43,7 @@ class RatingCalculator { return result; } - calRating(rank, user) { + calRating(rank: number, user: User) { let left = 1; let right = 8000; while (right - left > 1) { @@ -101,10 +105,9 @@ interface RatingOutputUser { uid: number, } -function calculate(users: RatingInputUser[]): RatingOutputUser[] { +export default function calculate(users: RatingInputUser[]): RatingOutputUser[] { const calculator = new RatingCalculator(users); return calculator.calculate(); } global.Hydro.lib.rating = calculate; -export default calculate; diff --git a/hydro/lib/validator.ts b/hydro/lib/validator.ts index 07ba60923..7e9cbee41 100644 --- a/hydro/lib/validator.ts +++ b/hydro/lib/validator.ts @@ -67,22 +67,8 @@ function _validate(scheme: any, arg: any, base: string): void { } } -function descriptor(scheme: any): Function { - return function desc(target: any, name: string, obj: any) { - const originalMethod = obj.value; - obj.value = function func(...args: any[]) { - _validate(scheme, args[0], ''); - return originalMethod.call(this, ...args); - }; - return obj; - }; -} - -export function validate(scheme: any): Function; -export function validate(scheme: any, arg: any): void; -export function validate(...args: any[]): any { - if (args.length === 1) return descriptor(args[0]); - return _validate(args[0], args[1], ''); +export function validate(scheme: any, arg: any) { + return _validate(scheme, arg, ''); } export const isTitle = (s) => s && s.length < 64; diff --git a/hydro/model/blacklist.ts b/hydro/model/blacklist.ts index 1ab5d015c..118b9b4dd 100644 --- a/hydro/model/blacklist.ts +++ b/hydro/model/blacklist.ts @@ -4,6 +4,11 @@ import { Bdoc } from '../interface'; const coll = db.collection('blacklist'); export async function add(ip: string): Promise { + /** + * Add a ip into blacklist. + * @param {string} ip + * @returns {Promise} + */ const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000); const res = await coll.findOneAndUpdate( { _id: ip }, @@ -13,7 +18,12 @@ export async function add(ip: string): Promise { return res.value; } -export function get(ip: string): Promise { +export function get(ip: string): Promise { + /** + * Get a ip, return null if not. + * @param {string} ip + * @returns {Promise} + */ return coll.findOne({ _id: ip }); } diff --git a/hydro/model/discussion.ts b/hydro/model/discussion.ts index 320e19351..01d021a0c 100644 --- a/hydro/model/discussion.ts +++ b/hydro/model/discussion.ts @@ -5,6 +5,7 @@ import * as training from './training'; import * as document from './document'; import { PERM } from './builtin'; import { DocumentNotFoundError } from '../error'; +import { Ddoc, Drdoc, Drrdoc } from '../interface'; export const typeDisplay = { [document.TYPE_PROBLEM]: 'problem', @@ -18,7 +19,7 @@ export function add( domainId: string, parentType: number, parentId: ObjectID | number | string, owner: number, title: string, content: string, ip: string | null = null, highlight: boolean = false, -) { +): Promise { return document.add( domainId, content, owner, document.TYPE_DISCUSSION, null, parentType, parentId, @@ -33,14 +34,14 @@ export function add( ); } -export function get(domainId: string, did: ObjectID) { +export function get(domainId: string, did: ObjectID): Promise { return document.get(domainId, document.TYPE_DISCUSSION, did); } export function edit( domainId: string, did: ObjectID, title: string, content: string, highlight: boolean, -) { +): Promise { return document.set(domainId, document.TYPE_DISCUSSION, did, { title, content, highlight }); } @@ -65,7 +66,7 @@ export function getMulti(domainId: string, query: any = {}) { export async function addReply( domainId: string, did: ObjectID, owner: number, content: string, ip: string, -) { +): Promise { const [drdoc] = await Promise.all([ document.add( domainId, content, owner, document.TYPE_DISCUSSION_REPLY, @@ -76,11 +77,13 @@ export async function addReply( return drdoc; } -export function getReply(domainId: string, drid: ObjectID) { +export function getReply(domainId: string, drid: ObjectID): Promise { return document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid); } -export async function editReply(domainId: string, drid: ObjectID, content: string) { +export async function editReply( + domainId: string, drid: ObjectID, content: string, +): Promise { return document.set(domainId, document.TYPE_DISCUSSION_REPLY, drid, { content }); } @@ -100,14 +103,14 @@ export function getMultiReply(domainId: string, did: ObjectID) { ).sort('_id', -1); } -export function getListReply(domainId: string, did: ObjectID) { +export function getListReply(domainId: string, did: ObjectID): Promise { return getMultiReply(domainId, did).toArray(); } export async function addTailReply( domainId: string, drid: ObjectID, owner: number, content: string, ip: string, -) { +): Promise<[Drdoc, ObjectID]> { let drdoc = await document.get(domainId, document.TYPE_DISCUSSION_REPLY, drid); const sid = new ObjectID(); [drdoc] = await Promise.all([ @@ -117,11 +120,16 @@ export async function addTailReply( return [drdoc, sid]; } -export function getTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) { +export function getTailReply( + domainId: string, drid: ObjectID, drrid: ObjectID, +): Promise<[Drdoc, Drrdoc] | [null, null]> { + // @ts-ignore return document.getSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid); } -export function editTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) { +export function editTailReply( + domainId: string, drid: ObjectID, drrid: ObjectID, content: string, +): Promise { return document.setSub(domainId, document.TYPE_DISCUSSION_REPLY, drid, 'reply', drrid, { content }); } diff --git a/hydro/model/message.ts b/hydro/model/message.ts index b64d469eb..adc4dd15c 100644 --- a/hydro/model/message.ts +++ b/hydro/model/message.ts @@ -27,7 +27,7 @@ export async function send( return mdoc; } -export async function get(_id: ObjectID): Promise { +export async function get(_id: ObjectID): Promise { return await coll.findOne({ _id }); } @@ -41,7 +41,7 @@ export async function getMany(query: any, sort: any, page: number, limit: number .toArray(); } -export async function setFlag(messageId: ObjectID, flag: number) { +export async function setFlag(messageId: ObjectID, flag: number): Promise { const result = await coll.findOneAndUpdate( { _id: messageId }, { $bit: { flag: { xor: flag } } }, diff --git a/hydro/model/problem.ts b/hydro/model/problem.ts index bdf87a963..f964fc2a1 100644 --- a/hydro/model/problem.ts +++ b/hydro/model/problem.ts @@ -77,7 +77,7 @@ export function edit(domainId: string, _id: number, $set: any): Promise { return document.set(domainId, document.TYPE_PROBLEM, _id, $set); } -export function inc(domainId: string, _id: number, field: string, n: number) { +export function inc(domainId: string, _id: number, field: string, n: number): Promise { return document.inc(domainId, document.TYPE_PROBLEM, _id, field, n); } @@ -85,7 +85,7 @@ export function count(domainId: string, query: any) { return document.count(domainId, document.TYPE_PROBLEM, query); } -export async function random(domainId: string, query: any) { +export async function random(domainId: string, query: any): Promise { const cursor = document.getMulti(domainId, document.TYPE_PROBLEM, query); const pcount = await cursor.count(); if (pcount) { @@ -100,16 +100,18 @@ export async function getList( ): Promise { pids = Array.from(new Set(pids)); const r = {}; + const l = {}; const q: any = { $or: [{ docId: { $in: pids } }, { pid: { $in: pids } }] }; if (!getHidden) q.hidden = false; const pdocs = await document.getMulti(domainId, document.TYPE_PROBLEM, q).toArray(); for (const pdoc of pdocs) { r[pdoc.docId] = pdoc; - r[pdoc.pid] = pdoc; + l[pdoc.pid] = pdoc; } + // TODO enhance if (pdocs.length !== pids.length) { for (const pid of pids) { - if (!r[pid]) { + if (!(r[pid] || l[pid])) { if (doThrow) { throw new ProblemNotFoundError(domainId, pid); } else { diff --git a/hydro/model/record.ts b/hydro/model/record.ts index 2c6357552..b27235304 100644 --- a/hydro/model/record.ts +++ b/hydro/model/record.ts @@ -1,5 +1,3 @@ -import _ from 'lodash'; -import yaml from 'js-yaml'; import { ObjectID } from 'mongodb'; import { STATUS } from './builtin'; import * as task from './task'; diff --git a/hydro/model/setting.ts b/hydro/model/setting.ts index 17eba5763..bb4f9ebf2 100644 --- a/hydro/model/setting.ts +++ b/hydro/model/setting.ts @@ -121,7 +121,6 @@ SystemSetting( Setting('setting_server', 'server.cdn', null, '/', 'text', 'CDN Prefix', 'Ends with /'), Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'), Setting('setting_server', 'server.xff', null, null, 'text', 'IP Header', 'e.g. x-forwarded-for (lowercase)'), - Setting('setting_server', 'server.log', null, false, 'boolean', 'Disable Access Log'), Setting('setting_session', 'session.keys', null, [String.random(32)], 'text', 'session.keys', null, FLAG_DISABLED | FLAG_HIDDEN), Setting('setting_session', 'session.secure', null, false, 'boolean', 'session.secure'), Setting('setting_session', 'session.saved_expire_seconds', null, 3600 * 24 * 30, 'number', 'Saved session expire seconds'), diff --git a/hydro/model/token.ts b/hydro/model/token.ts index 44f26c1f0..52965a604 100644 --- a/hydro/model/token.ts +++ b/hydro/model/token.ts @@ -1,4 +1,3 @@ -import { ValidationError } from '../error'; import * as db from '../service/db'; const coll = db.collection('token'); diff --git a/hydro/options.ts b/hydro/options.ts index ffcff2866..54e9601d6 100644 --- a/hydro/options.ts +++ b/hydro/options.ts @@ -8,5 +8,12 @@ export default function load() { if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json'); if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.hydro', 'config.json'); if (!fs.existsSync(f)) f = path.resolve('/config/config.json'); - return JSON.parse(fs.readFileSync(f).toString()); + let result: any = {}; + try { + result = JSON.parse(fs.readFileSync(f).toString()); + } catch (e) { + console.error('Cannot read config file', e); + result = {}; + } + return result; } diff --git a/hydro/script/rating.ts b/hydro/script/rating.ts index c003e1f52..9b7f0d72b 100644 --- a/hydro/script/rating.ts +++ b/hydro/script/rating.ts @@ -15,7 +15,7 @@ type ND = NumericDictionary function calc(udict: ND, rankedDocs: [number, number][]) { const users = []; for (const [rank, uid] of rankedDocs) { - users.push({ uid, rank, old: users[uid] || 1500 }); + users.push({ uid, rank, old: udict[uid] || 1500 }); } const rated = rating(users); for (const udoc of rated) { diff --git a/hydro/service/monitor.ts b/hydro/service/monitor.ts index 49b0a477a..7d9d9fa84 100644 --- a/hydro/service/monitor.ts +++ b/hydro/service/monitor.ts @@ -13,6 +13,15 @@ export async function update() { global.Hydro.stat.reqCount = 0; } +export function updateJudger(args) { + args.type = 'judger'; + return coll.updateOne( + { mid: args.mid, type: 'judger' }, + { $set: args }, + { upsert: true }, + ); +} + global.Hydro.postInit.push( async () => { const info = await sysinfo.get(); @@ -25,4 +34,4 @@ global.Hydro.postInit.push( }, ); -global.Hydro.service.monitor = { update }; +global.Hydro.service.monitor = { update, updateJudger }; diff --git a/hydro/service/server.ts b/hydro/service/server.ts index 0f5d8dac7..c26f0ef16 100644 --- a/hydro/service/server.ts +++ b/hydro/service/server.ts @@ -743,8 +743,8 @@ export function Connection( // TODO use postInit? export async function start() { - const [disableLog, port] = await system.getMany(['server.log', 'server.port']); - if (!disableLog) { + const port = await system.get('server.port'); + if (!argv.debug) { app.use(morgan(':method :url :status :res[content-length] - :response-time ms', { skip: (req, res) => res.hasHeader('nolog'), })); diff --git a/hydro/utils.ts b/hydro/utils.ts index f99a6a856..6b43f61ee 100644 --- a/hydro/utils.ts +++ b/hydro/utils.ts @@ -1,8 +1,8 @@ import fs from 'fs'; -import { serialize } from 'v8'; import cluster from 'cluster'; import path from 'path'; import * as superagent from 'superagent'; +import serialize from 'serialize-javascript'; import proxy from 'superagent-proxy'; import Lru from 'lru-cache'; @@ -147,13 +147,13 @@ const TIME_UNITS = { '': 1000, m: 1, u: 0.001 }; const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i; const MEMORY_UNITS = { k: 0.1, m: 1, g: 1024 }; -export function parseTimeMS(str) { +export function parseTimeMS(str: string) { const match = TIME_RE.exec(str); if (!match) throw new Error(`${str} error parsing time`); return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]); } -export function parseMemoryMB(str) { +export function parseMemoryMB(str: string) { const match = MEMORY_RE.exec(str); if (!match) throw new Error(`${str} error parsing memory`); return Math.floor(parseFloat(match[1]) * MEMORY_UNITS[match[2]]); diff --git a/package.json b/package.json index 0c5337af1..d68581945 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.10.7", + "version": "2.10.8", "main": "dist/loader.js", "bin": "bin/hydrooj.js", "repository": "https://github.com/hydro-dev/Hydro.git",