diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 9300fe9ef..0eb57b150 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.34.2", + "version": "2.34.3", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/entry/worker.ts b/packages/hydrooj/src/entry/worker.ts index 35ad3decf..66c338533 100644 --- a/packages/hydrooj/src/entry/worker.ts +++ b/packages/hydrooj/src/entry/worker.ts @@ -12,7 +12,7 @@ import { builtinScript, handler, lib, locale, model, script, service, setting, template, uistatic, } from './common'; -const logger = new Logger('loader/worker'); +const logger = new Logger('worker'); const detail = cac().parse().options.loaderDetail; const tmpdir = path.resolve(os.tmpdir(), 'hydro'); @@ -105,5 +105,7 @@ export async function load() { await modelSystem.set('db.ver', dbVer); } } + logger.success('Server started'); + if (process.send) process.send('ready'); return { active, fail }; } diff --git a/packages/hydrooj/src/model/blacklist.ts b/packages/hydrooj/src/model/blacklist.ts index e621d38c9..4fe4a338b 100644 --- a/packages/hydrooj/src/model/blacklist.ts +++ b/packages/hydrooj/src/model/blacklist.ts @@ -32,10 +32,9 @@ class BlackListModel { } } -async function ensureIndexes() { - return await coll.createIndex('expireAt', { expireAfterSeconds: 0 }); -} - -bus.once('app/started', ensureIndexes); +bus.once('app/started', () => db.ensureIndexes( + coll, + { key: { expireAt: -1 }, name: 'expire', expireAfterSeconds: 0 }, +)); export default BlackListModel; global.Hydro.model.blacklist = BlackListModel; diff --git a/packages/hydrooj/src/model/message.ts b/packages/hydrooj/src/model/message.ts index 1ab928542..ce17bcace 100644 --- a/packages/hydrooj/src/model/message.ts +++ b/packages/hydrooj/src/model/message.ts @@ -65,13 +65,10 @@ class MessageModel { } } -function ensureIndexes() { - return Promise.all([ - coll.createIndex({ to: 1, _id: -1 }), - coll.createIndex({ from: 1, _id: -1 }), - ]); -} - -bus.once('app/started', ensureIndexes); +bus.once('app/started', () => db.ensureIndexes( + coll, + { key: { to: 1, _id: -1 }, name: 'to' }, + { key: { from: 1, _id: -1 }, name: 'from' }, +)); export default MessageModel; global.Hydro.model.message = MessageModel; diff --git a/packages/hydrooj/src/model/opcount.ts b/packages/hydrooj/src/model/opcount.ts index d8e39798f..e22b05775 100644 --- a/packages/hydrooj/src/model/opcount.ts +++ b/packages/hydrooj/src/model/opcount.ts @@ -20,12 +20,9 @@ export async function inc(op: string, ident: string, periodSecs: number, maxOper } } -function ensureIndexes() { - return Promise.all([ - coll.createIndex('expireAt', { expireAfterSeconds: 0 }), - coll.createIndex({ op: 1, ident: 1, expireAt: 1 }, { unique: true }), - ]); -} - -bus.once('app/started', ensureIndexes); +bus.once('app/started', () => db.ensureIndexes( + coll, + { key: { expireAt: -1 }, name: 'expire', expireAfterSeconds: 0 }, + { key: { op: 1, ident: 1, expireAt: 1 }, name: 'unique', unique: true }, +)); global.Hydro.model.opcount = { inc }; diff --git a/packages/hydrooj/src/model/record.ts b/packages/hydrooj/src/model/record.ts index 523f94785..9c8481f45 100644 --- a/packages/hydrooj/src/model/record.ts +++ b/packages/hydrooj/src/model/record.ts @@ -234,14 +234,12 @@ bus.on('domain/delete', (domainId) => Promise.all([ RecordModel.coll.updateMany({ pdomain: domainId }, { $set: { docId: -1 } }), ])); -bus.on('app/started', () => { - return db.ensureIndexes( - RecordModel.coll, - { key: { domainId: 1, 'contest.tid': 1, hidden: 1, _id: -1 }, name: 'basic' }, - { key: { domainId: 1, 'contest.tid': 1, hidden: 1, uid: 1, _id: -1 }, name: 'withUser' }, - { key: { domainId: 1, 'contest.tid': 1, hidden: 1, pid: 1, _id: -1 }, name: 'withProblem' }, - ); -}); +bus.once('app/started', () => db.ensureIndexes( + RecordModel.coll, + { key: { domainId: 1, 'contest.tid': 1, hidden: 1, _id: -1 }, name: 'basic' }, + { key: { domainId: 1, 'contest.tid': 1, hidden: 1, uid: 1, _id: -1 }, name: 'withUser' }, + { key: { domainId: 1, 'contest.tid': 1, hidden: 1, pid: 1, _id: -1 }, name: 'withProblem' }, +)); export default RecordModel; global.Hydro.model.record = RecordModel; diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 685d89f08..728e1b1aa 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -163,6 +163,7 @@ SystemSetting( Setting('setting_file', 'file.secretKey', null, 'password', 'file.secretKey', 'Storage engine secret', FLAG_SECRET), Setting('setting_file', 'file.bucket', 'hydro', 'text', 'file.bucket', 'Storage engine bucket'), Setting('setting_file', 'file.region', 'us-east-1', 'text', 'file.region', 'Storage engine region'), + Setting('setting_file', 'file.pathStyle', true, 'boolean', 'file.pathStyle', 'pathStyle endpoint'), Setting('setting_file', 'file.endPointForUser', '/fs/', 'text', 'file.endPointForUser', 'EndPoint for user'), Setting('setting_file', 'file.endPointForJudge', '/fs/', 'text', 'file.endPointForJudge', 'EndPoint for judge'), Setting('setting_smtp', 'smtp.user', null, 'text', 'smtp.user', 'SMTP Username'), diff --git a/packages/hydrooj/src/model/token.ts b/packages/hydrooj/src/model/token.ts index 6ea539761..728476946 100644 --- a/packages/hydrooj/src/model/token.ts +++ b/packages/hydrooj/src/model/token.ts @@ -92,13 +92,10 @@ class TokenModel { } } -function ensureIndexes() { - return Promise.all([ - TokenModel.coll.createIndex({ uid: 1, tokenType: 1, updateAt: -1 }, { sparse: true }), - TokenModel.coll.createIndex('expireAt', { expireAfterSeconds: 0 }), - ]); -} - -bus.once('app/started', ensureIndexes); +bus.once('app/started', () => db.ensureIndexes( + TokenModel.coll, + { key: { uid: 1, tokenType: 1, updateAt: -1 }, name: 'basic', sparse: true }, + { key: { expireAt: -1 }, name: 'expire', expireAfterSeconds: 0 }, +)); export default TokenModel; global.Hydro.model.token = TokenModel; diff --git a/packages/hydrooj/src/model/user.ts b/packages/hydrooj/src/model/user.ts index dda1a439b..c2c072212 100644 --- a/packages/hydrooj/src/model/user.ts +++ b/packages/hydrooj/src/model/user.ts @@ -3,8 +3,9 @@ import LRU from 'lru-cache'; import { Collection } from 'mongodb'; import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error'; import { - FileInfo, - Udict, Udoc, User as _User } from '../interface'; + FileInfo, Udict, Udoc, + User as _User, +} from '../interface'; import pwhash from '../lib/hash.hydro'; import { Logger } from '../logger'; import * as bus from '../service/bus'; @@ -338,13 +339,10 @@ class UserModel { } } -function ensureIndexes() { - return Promise.all([ - coll.createIndex('unameLower', { unique: true }), - coll.createIndex('mailLower', { sparse: true }), - ]); -} - -bus.once('app/started', ensureIndexes); +bus.once('app/started', () => db.ensureIndexes( + coll, + { key: { unameLower: 1 }, name: 'uname', unique: true }, + { key: { mailLower: 1 }, name: 'mail', unique: true }, +)); export default UserModel; global.Hydro.model.user = UserModel; diff --git a/packages/hydrooj/src/service/db.ts b/packages/hydrooj/src/service/db.ts index f0033dcde..27c85ee1c 100644 --- a/packages/hydrooj/src/service/db.ts +++ b/packages/hydrooj/src/service/db.ts @@ -49,15 +49,16 @@ class MongoService implements BaseService { } public async ensureIndexes(coll: Collection, ...args: IndexSpecification[]) { + if (process.env.NODE_APP_INSTANCE !== '0') return; const existed = await coll.listIndexes().toArray(); for (const index of args) { - const i = existed.find(t => t.name == index.name); + const i = existed.find(t => t.name == index.name || JSON.stringify(t.key) == JSON.stringify(index.key)); if (!i) { logger.info('Indexing %s.%s with key %o', coll.collectionName, index.name, index.key); await coll.createIndexes([index]); - } else if (i.v < 2 || JSON.stringify(i.key) !== JSON.stringify(index.key)) { + } else if (i.v < 2 || i.name !== index.name || JSON.stringify(i.key) !== JSON.stringify(index.key)) { logger.info('Re-Index %s.%s with key %o', coll.collectionName, index.name, index.key); - await coll.dropIndex(index.name); + await coll.dropIndex(i.name); await coll.createIndexes([index]); } } diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 2fc4697ea..2925c34ea 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -13,18 +13,18 @@ import proxy from 'koa-proxies'; import Router from 'koa-router'; import cache from 'koa-static-cache'; import { - cloneDeep, - Dictionary, filter, isSafeInteger } from 'lodash'; + cloneDeep, Dictionary, filter, isSafeInteger, +} from 'lodash'; import moment from 'moment-timezone'; import { ObjectID } from 'mongodb'; import sockjs from 'sockjs'; import { parseMemoryMB } from '@hydrooj/utils/lib/utils'; import { - BlacklistedError, CsrfTokenError, HydroError, InvalidOperationError, MethodNotAllowedError, - NotFoundError, PermissionError, - PrivilegeError, - SystemError, - UserFacingError, UserNotFoundError, ValidationError } from '../error'; + BlacklistedError, CsrfTokenError, HydroError, + InvalidOperationError, MethodNotAllowedError, NotFoundError, + PermissionError, PrivilegeError, SystemError, + UserFacingError, UserNotFoundError, ValidationError, +} from '../error'; import { DomainDoc, User } from '../interface'; import avatar from '../lib/avatar'; import { isContent, isName, isTitle } from '../lib/validator'; @@ -890,7 +890,6 @@ export function start() { app.use(router.routes()).use(router.allowedMethods()); server.listen(argv.options.port || port); logger.success('Server listening at: %d', argv.options.port || port); - if (process.send) process.send('ready'); // PM2 0-sec-down reload started = true; } diff --git a/packages/hydrooj/src/service/storage.ts b/packages/hydrooj/src/service/storage.ts index 739f8125b..fb8984679 100644 --- a/packages/hydrooj/src/service/storage.ts +++ b/packages/hydrooj/src/service/storage.ts @@ -15,6 +15,7 @@ interface StorageOptions { secretKey: string; bucket: string; region?: string; + pathStyle: boolean; endPointForUser?: string; endPointForJudge?: string; } @@ -81,15 +82,20 @@ class StorageService { async start() { try { - const [endPoint, accessKey, secretKey, bucket, region, endPointForUser, endPointForJudge] = system.getMany([ + const [ + endPoint, accessKey, secretKey, bucket, region, + pathStyle, endPointForUser, endPointForJudge, + ] = system.getMany([ 'file.endPoint', 'file.accessKey', 'file.secretKey', 'file.bucket', 'file.region', - 'file.endPointForUser', 'file.endPointForJudge', + 'file.pathStyle', 'file.endPointForUser', 'file.endPointForJudge', ]); this.opts = { - endPoint, accessKey, secretKey, bucket, region, endPointForUser, endPointForJudge, + endPoint, accessKey, secretKey, bucket, region, + pathStyle, endPointForUser, endPointForJudge, }; this.client = new Client({ ...parseMainEndpointUrl(this.opts.endPoint), + pathStyle: this.opts.pathStyle, accessKey: this.opts.accessKey, secretKey: this.opts.secretKey, });