@@ -2,15 +2,12 @@ import { AxiosRequestConfig } from 'axios'
|
||||
import cluster from 'cluster'
|
||||
import { argv } from 'zx-cjs'
|
||||
|
||||
export const isDev = process.env.NODE_ENV == 'development'
|
||||
|
||||
export const isTest = !!process.env.TEST
|
||||
export const cwd = process.cwd()
|
||||
import { cwd, isDev, isMainCluster, isTest } from './global/env.global'
|
||||
|
||||
export const PORT = argv.port || process.env.PORT || 2333
|
||||
export const API_VERSION = 2
|
||||
|
||||
export const isInDemoMode = argv.demo || false
|
||||
export const DEMO_MODE = argv.demo || false
|
||||
|
||||
export const CROSS_DOMAIN = {
|
||||
allowedOrigins: argv.allowed_origins
|
||||
@@ -32,7 +29,7 @@ export const CROSS_DOMAIN = {
|
||||
}
|
||||
|
||||
export const MONGO_DB = {
|
||||
dbName: argv.collection_name || (isInDemoMode ? 'mx-space_demo' : 'mx-space'),
|
||||
dbName: argv.collection_name || (DEMO_MODE ? 'mx-space_demo' : 'mx-space'),
|
||||
host: argv.db_host || '127.0.0.1',
|
||||
port: argv.db_port || 27017,
|
||||
get uri() {
|
||||
@@ -69,11 +66,6 @@ export const CLUSTER = {
|
||||
workers: argv.cluster_workers,
|
||||
}
|
||||
|
||||
/** Is main cluster in PM2 */
|
||||
export const isMainCluster =
|
||||
process.env.NODE_APP_INSTANCE && parseInt(process.env.NODE_APP_INSTANCE) === 0
|
||||
export const isMainProcess = cluster.isPrimary || isMainCluster
|
||||
|
||||
export const DEBUG_MODE = {
|
||||
httpRequestVerbose:
|
||||
argv.httpRequestVerbose ?? argv.http_request_verbose ?? true,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ApiController } from '~/common/decorator/api-controller.decorator'
|
||||
import { InjectModel } from '~/transformers/model.transformer'
|
||||
|
||||
import PKG from '../package.json'
|
||||
import { isInDemoMode } from './app.config'
|
||||
import { DEMO_MODE } from './app.config'
|
||||
import { Auth } from './common/decorator/auth.decorator'
|
||||
import { HttpCache } from './common/decorator/cache.decorator'
|
||||
import { IpLocation, IpRecord } from './common/decorator/ip.decorator'
|
||||
@@ -36,7 +36,7 @@ export class AppController {
|
||||
return {
|
||||
name: PKG.name,
|
||||
author: PKG.author,
|
||||
version: isDev ? 'dev' : `${isInDemoMode ? 'demo/' : ''}${PKG.version}`,
|
||||
version: isDev ? 'dev' : `${DEMO_MODE ? 'demo/' : ''}${PKG.version}`,
|
||||
homepage: PKG.homepage,
|
||||
issues: PKG.issues,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module, NestModule, Type } from '@nestjs/common'
|
||||
import { DynamicModule, Module, NestModule, Type } from '@nestjs/common'
|
||||
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'
|
||||
|
||||
import { isInDemoMode } from './app.config'
|
||||
import { DEMO_MODE } from './app.config'
|
||||
import { AppController } from './app.controller'
|
||||
import { AllExceptionsFilter } from './common/filters/any-exception.filter'
|
||||
import { RolesGuard } from './common/guard/roles.guard'
|
||||
@@ -52,92 +52,97 @@ import { HelperModule } from './processors/helper/helper.module'
|
||||
import { LoggerModule } from './processors/logger/logger.module'
|
||||
import { RedisModule } from './processors/redis/redis.module'
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
LoggerModule,
|
||||
DatabaseModule,
|
||||
RedisModule,
|
||||
@Module({})
|
||||
export class AppModule {
|
||||
static register(isInit: boolean): DynamicModule {
|
||||
return {
|
||||
module: AppModule,
|
||||
imports: [
|
||||
LoggerModule,
|
||||
DatabaseModule,
|
||||
RedisModule,
|
||||
|
||||
AggregateModule,
|
||||
AnalyzeModule,
|
||||
AuthModule,
|
||||
BackupModule,
|
||||
CategoryModule,
|
||||
CommentModule,
|
||||
ConfigsModule,
|
||||
isInDemoMode && DemoModule,
|
||||
DependencyModule,
|
||||
FeedModule,
|
||||
FileModule,
|
||||
HealthModule,
|
||||
InitModule,
|
||||
LinkModule,
|
||||
MarkdownModule,
|
||||
NoteModule,
|
||||
OptionModule,
|
||||
PageModule,
|
||||
PostModule,
|
||||
ProjectModule,
|
||||
PTYModule,
|
||||
RecentlyModule,
|
||||
UpdateModule,
|
||||
TopicModule,
|
||||
SayModule,
|
||||
SearchModule,
|
||||
ServerlessModule,
|
||||
SitemapModule,
|
||||
SnippetModule,
|
||||
ToolModule,
|
||||
UserModule,
|
||||
AggregateModule,
|
||||
AnalyzeModule,
|
||||
AuthModule,
|
||||
BackupModule,
|
||||
CategoryModule,
|
||||
CommentModule,
|
||||
ConfigsModule,
|
||||
DEMO_MODE && DemoModule,
|
||||
DependencyModule,
|
||||
FeedModule,
|
||||
FileModule,
|
||||
HealthModule,
|
||||
!isInit && InitModule,
|
||||
LinkModule,
|
||||
MarkdownModule,
|
||||
NoteModule,
|
||||
OptionModule,
|
||||
PageModule,
|
||||
PostModule,
|
||||
ProjectModule,
|
||||
PTYModule,
|
||||
RecentlyModule,
|
||||
UpdateModule,
|
||||
TopicModule,
|
||||
SayModule,
|
||||
SearchModule,
|
||||
ServerlessModule,
|
||||
SitemapModule,
|
||||
SnippetModule,
|
||||
ToolModule,
|
||||
UserModule,
|
||||
|
||||
PageProxyModule,
|
||||
RenderEjsModule,
|
||||
PageProxyModule,
|
||||
RenderEjsModule,
|
||||
|
||||
GatewayModule,
|
||||
HelperModule,
|
||||
GatewayModule,
|
||||
HelperModule,
|
||||
|
||||
isDev ? DebugModule : undefined,
|
||||
].filter(Boolean) as Type<NestModule>[],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: QueryInterceptor,
|
||||
},
|
||||
isDev ? DebugModule : undefined,
|
||||
].filter(Boolean) as Type<NestModule>[],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: QueryInterceptor,
|
||||
},
|
||||
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: HttpCacheInterceptor, // 4
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: AnalyzeInterceptor,
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: CountingInterceptor, // 3
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: JSONTransformInterceptor, // 2
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ResponseInterceptor, // 1
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: IdempotenceInterceptor, // 0
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: HttpCacheInterceptor, // 4
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: AnalyzeInterceptor,
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: CountingInterceptor, // 3
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: JSONTransformInterceptor, // 2
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ResponseInterceptor, // 1
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: IdempotenceInterceptor, // 0
|
||||
},
|
||||
|
||||
{
|
||||
provide: APP_FILTER,
|
||||
useClass: AllExceptionsFilter,
|
||||
},
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useClass: RolesGuard,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
{
|
||||
provide: APP_FILTER,
|
||||
useClass: AllExceptionsFilter,
|
||||
},
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useClass: RolesGuard,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,17 @@ import { LogLevel, Logger, ValidationPipe } from '@nestjs/common'
|
||||
import { ContextIdFactory, NestFactory } from '@nestjs/core'
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
|
||||
import { API_VERSION, CROSS_DOMAIN, PORT, isMainProcess } from './app.config'
|
||||
import { API_VERSION, CROSS_DOMAIN, PORT } from './app.config'
|
||||
import { AppModule } from './app.module'
|
||||
import { fastifyApp } from './common/adapters/fastify.adapter'
|
||||
import { RedisIoAdapter } from './common/adapters/socket.adapter'
|
||||
import { SpiderGuard } from './common/guard/spider.guard'
|
||||
import { LoggingInterceptor } from './common/interceptors/logging.interceptor'
|
||||
import { AggregateByTenantContextIdStrategy } from './common/strategies/context.strategy'
|
||||
import { isTest } from './global/env.global'
|
||||
import { isMainProcess, isTest } from './global/env.global'
|
||||
import { migrateDatabase } from './migration/migrate'
|
||||
import { MyLogger } from './processors/logger/logger.service'
|
||||
import { checkInit } from './utils/check-init.util'
|
||||
|
||||
const Origin: false | string[] = Array.isArray(CROSS_DOMAIN.allowedOrigins)
|
||||
? [...CROSS_DOMAIN.allowedOrigins, '*.shizuri.net', '22333322.xyz']
|
||||
@@ -26,8 +27,10 @@ declare const module: any
|
||||
export async function bootstrap() {
|
||||
process.title = `Mix Space (${cluster.isPrimary ? 'master' : 'worker'})`
|
||||
await migrateDatabase()
|
||||
const isInit = await checkInit()
|
||||
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
AppModule.register(isInit),
|
||||
fastifyApp,
|
||||
{
|
||||
logger: ['error'].concat(
|
||||
|
||||
@@ -2,7 +2,7 @@ import cluster from 'cluster'
|
||||
|
||||
import { Cron } from '@nestjs/schedule'
|
||||
|
||||
import { isMainProcess } from '~/app.config'
|
||||
import { isMainProcess } from '~/global/env.global'
|
||||
|
||||
export const CronOnce = (...rest: Parameters<typeof Cron>): MethodDecorator => {
|
||||
// If not in cluster mode, and PM2 main worker
|
||||
|
||||
@@ -14,7 +14,15 @@ import { isDev, isTest } from './env.global'
|
||||
|
||||
class Reporter extends FancyReporter {
|
||||
isInVirtualTerminal = typeof process.stdout.columns === 'undefined' // HACK: if got `undefined` that means in PM2 pty
|
||||
private latestLogTime: number = performance.now()
|
||||
protected formatDate(date: Date): string {
|
||||
if (isDev) {
|
||||
const now = performance.now()
|
||||
const delta = now - this.latestLogTime
|
||||
this.latestLogTime = now
|
||||
return `+${delta | 0}ms ${super.formatDate(date)}`
|
||||
}
|
||||
|
||||
return this.isInVirtualTerminal ? '' : super.formatDate(date)
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
export { isDev, cwd, isTest } from '~/app.config'
|
||||
import cluster from 'cluster'
|
||||
|
||||
export const isMainCluster =
|
||||
process.env.NODE_APP_INSTANCE && parseInt(process.env.NODE_APP_INSTANCE) === 0
|
||||
export const isMainProcess = cluster.isPrimary || isMainCluster
|
||||
|
||||
export const isDev = process.env.NODE_ENV == 'development'
|
||||
|
||||
export const isTest = !!process.env.TEST
|
||||
export const cwd = process.cwd()
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'zx-cjs/globals'
|
||||
|
||||
import { Logger } from '@nestjs/common'
|
||||
|
||||
import { CLUSTER } from '~/app.config'
|
||||
import {
|
||||
DATA_DIR,
|
||||
LOG_DIR,
|
||||
@@ -20,6 +19,8 @@ import { consola, registerStdLogger } from './consola.global'
|
||||
|
||||
import './dayjs.global'
|
||||
|
||||
import { CLUSTER } from '~/app.config'
|
||||
|
||||
import { cwd, isDev } from './env.global'
|
||||
import { registerJSONGlobal } from './json.global'
|
||||
|
||||
@@ -56,8 +57,9 @@ function registerGlobal() {
|
||||
}
|
||||
|
||||
export function register() {
|
||||
registerStdLogger()
|
||||
mkdirs()
|
||||
registerGlobal()
|
||||
registerStdLogger()
|
||||
registerJSONGlobal()
|
||||
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { existsSync } from 'fs-extra'
|
||||
import { MongoClient } from 'mongodb'
|
||||
|
||||
import * as APP_CONFIG from '../app.config'
|
||||
import { isMainProcess } from '~/global/env.global'
|
||||
import { getDatabaseConnection } from '~/utils/database.util'
|
||||
|
||||
import { DATA_DIR } from '../constants/path.constant'
|
||||
import VersionList from './history'
|
||||
|
||||
const { MONGO_DB } = APP_CONFIG
|
||||
|
||||
export async function migrateDatabase() {
|
||||
if (!APP_CONFIG.isMainProcess) {
|
||||
if (!isMainProcess) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,9 +18,8 @@ export async function migrateDatabase() {
|
||||
|
||||
const migratedSet = new Set(migrateRecord.split('\n'))
|
||||
|
||||
const client = new MongoClient(`mongodb://${MONGO_DB.host}:${MONGO_DB.port}`)
|
||||
await client.connect()
|
||||
const db = client.db(MONGO_DB.dbName)
|
||||
const connection = await getDatabaseConnection()
|
||||
const db = connection.db
|
||||
|
||||
for (const migrate of VersionList) {
|
||||
if (migratedSet.has(migrate.name)) {
|
||||
@@ -39,6 +37,4 @@ export async function migrateDatabase() {
|
||||
await fs.writeFile(migrateFilePath, [...migratedSet].join('\n'), {
|
||||
flag: 'w+',
|
||||
})
|
||||
|
||||
await client.close()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isInDemoMode } from '~/app.config'
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
|
||||
import { IConfig } from './configs.interface'
|
||||
|
||||
@@ -41,7 +41,7 @@ export const generateDefaultConfig: () => IConfig = () => ({
|
||||
},
|
||||
friendLinkOptions: { allowApply: true },
|
||||
backupOptions: {
|
||||
enable: isInDemoMode ? false : true,
|
||||
enable: DEMO_MODE ? false : true,
|
||||
region: null!,
|
||||
bucket: null!,
|
||||
secretId: null!,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
Get,
|
||||
Param,
|
||||
Patch,
|
||||
Scope,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@@ -16,10 +15,7 @@ import { ConfigsService } from '../configs/configs.service'
|
||||
import { ConfigKeyDto } from '../option/dtos/config.dto'
|
||||
import { InitService } from './init.service'
|
||||
|
||||
@ApiController({
|
||||
path: '/init',
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
@ApiController('/init')
|
||||
@ApiName
|
||||
export class InitController {
|
||||
constructor(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable, Logger } from '@nestjs/common'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
import { DATA_DIR, TEMP_DIR } from '~/constants/path.constant'
|
||||
|
||||
@@ -6,7 +6,6 @@ import { UserService } from '../user/user.service'
|
||||
|
||||
@Injectable()
|
||||
export class InitService {
|
||||
private logger = new Logger(InitService.name)
|
||||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
getTempdir() {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { Module } from '@nestjs/common'
|
||||
|
||||
import { InitModule } from '../init/init.module'
|
||||
import { PageProxyController } from './pageproxy.controller'
|
||||
import { PageProxyService } from './pageproxy.service'
|
||||
|
||||
@Module({
|
||||
controllers: [PageProxyController],
|
||||
providers: [PageProxyService],
|
||||
imports: [InitModule],
|
||||
})
|
||||
export class PageProxyModule {}
|
||||
|
||||
@@ -7,14 +7,10 @@ import PKG from '~/../package.json'
|
||||
import { API_VERSION } from '~/app.config'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { InitService } from '../init/init.service'
|
||||
|
||||
@Injectable()
|
||||
export class PageProxyService {
|
||||
constructor(
|
||||
private readonly configs: ConfigsService,
|
||||
private readonly initService: InitService,
|
||||
) {}
|
||||
constructor(private readonly configs: ConfigsService) {}
|
||||
|
||||
async checkCanAccessAdminProxy() {
|
||||
const { adminExtra } = await this.configs.waitForConfigReady()
|
||||
@@ -61,7 +57,6 @@ export class PageProxyService {
|
||||
LOGIN_BG: adminExtra.background,
|
||||
TITLE: adminExtra.title,
|
||||
WEB_URL: webUrl,
|
||||
INIT: await this.initService.isInit(),
|
||||
} as IInjectableData)}`}
|
||||
${
|
||||
BASE_API
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
WebSocketGateway,
|
||||
} from '@nestjs/websockets'
|
||||
|
||||
import { isInDemoMode } from '~/app.config'
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
import { BusinessEvents } from '~/constants/business-event.constant'
|
||||
import { RedisKeys } from '~/constants/cache.constant'
|
||||
import { DATA_DIR } from '~/constants/path.constant'
|
||||
@@ -43,7 +43,7 @@ export class PTYGateway
|
||||
client: Socket,
|
||||
data?: { password?: string; cols: number; rows: number },
|
||||
) {
|
||||
if (isInDemoMode) {
|
||||
if (DEMO_MODE) {
|
||||
client.send(
|
||||
this.gatewayMessageFormat(
|
||||
BusinessEvents.PTY_MESSAGE,
|
||||
|
||||
@@ -1,52 +1,7 @@
|
||||
/**
|
||||
* @copy https://github.com/surmon-china/nodepress/blob/main/src/processors/database/database.provider.ts
|
||||
*/
|
||||
import { mongoose } from '@typegoose/typegoose'
|
||||
|
||||
import { MONGO_DB } from '~/app.config'
|
||||
import { DB_CONNECTION_TOKEN } from '~/constants/system.constant'
|
||||
import { getDatabaseConnection } from '~/utils/database.util'
|
||||
|
||||
export const databaseProvider = {
|
||||
provide: DB_CONNECTION_TOKEN,
|
||||
useFactory: async () => {
|
||||
let reconnectionTask: NodeJS.Timeout | null = null
|
||||
const RECONNECT_INTERVAL = 6000
|
||||
|
||||
const connection = () => {
|
||||
return mongoose.connect(MONGO_DB.uri, {})
|
||||
}
|
||||
const Badge = `[${chalk.yellow('MongoDB')}]`
|
||||
|
||||
const color = (str: TemplateStringsArray, ...args: any[]) => {
|
||||
return str.map((s) => chalk.green(s)).join('')
|
||||
}
|
||||
mongoose.connection.on('connecting', () => {
|
||||
consola.info(Badge, color`connecting...`)
|
||||
})
|
||||
|
||||
mongoose.connection.on('open', () => {
|
||||
consola.info(Badge, color`readied!`)
|
||||
if (reconnectionTask) {
|
||||
clearTimeout(reconnectionTask)
|
||||
reconnectionTask = null
|
||||
}
|
||||
})
|
||||
|
||||
mongoose.connection.on('disconnected', () => {
|
||||
consola.error(
|
||||
Badge,
|
||||
chalk.red(
|
||||
`disconnected! retry when after ${RECONNECT_INTERVAL / 1000}s`,
|
||||
),
|
||||
)
|
||||
reconnectionTask = setTimeout(connection, RECONNECT_INTERVAL)
|
||||
})
|
||||
|
||||
mongoose.connection.on('error', (error) => {
|
||||
consola.error(Badge, 'error!', error)
|
||||
mongoose.disconnect()
|
||||
})
|
||||
|
||||
return await connection().then((mongoose) => mongoose.connection)
|
||||
},
|
||||
useFactory: getDatabaseConnection,
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Inject, Injectable, Logger, forwardRef } from '@nestjs/common'
|
||||
import { OnEvent } from '@nestjs/event-emitter'
|
||||
import { CronExpression } from '@nestjs/schedule'
|
||||
|
||||
import { isInDemoMode } from '~/app.config'
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
import { CronDescription } from '~/common/decorator/cron-description.decorator'
|
||||
import { CronOnce } from '~/common/decorator/cron-once.decorator'
|
||||
import { RedisKeys } from '~/constants/cache.constant'
|
||||
@@ -64,7 +64,7 @@ export class CronService {
|
||||
@CronOnce(CronExpression.EVERY_DAY_AT_1AM, { name: 'backupDB' })
|
||||
@CronDescription('备份 DB 并上传 COS')
|
||||
async backupDB({ uploadCOS = true }: { uploadCOS?: boolean } = {}) {
|
||||
if (isInDemoMode) {
|
||||
if (DEMO_MODE) {
|
||||
return
|
||||
}
|
||||
const backup = await this.backupService.backup()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { isInDemoMode } from '~/app.config'
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
import { BanInDemoExcpetion } from '~/common/exceptions/ban-in-demo.exception'
|
||||
|
||||
/**
|
||||
* 检查是否在 demo 模式下,禁用此功能
|
||||
*/
|
||||
export const banInDemo = () => {
|
||||
if (isInDemoMode) {
|
||||
if (DEMO_MODE) {
|
||||
throw new BanInDemoExcpetion()
|
||||
}
|
||||
}
|
||||
|
||||
9
src/utils/check-init.util.ts
Normal file
9
src/utils/check-init.util.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { getDatabaseConnection } from './database.util'
|
||||
|
||||
export const checkInit = async () => {
|
||||
const connection = await getDatabaseConnection()
|
||||
const db = connection.db
|
||||
const isUserExist = (await db.collection('users').countDocuments()) > 0
|
||||
|
||||
return isUserExist
|
||||
}
|
||||
55
src/utils/database.util.ts
Normal file
55
src/utils/database.util.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @see https://github.com/surmon-china/nodepress/blob/main/src/processors/database/database.provider.ts
|
||||
*/
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
import { MONGO_DB } from '~/app.config'
|
||||
|
||||
let databaseConnection: mongoose.Connection | null = null
|
||||
export const getDatabaseConnection = async () => {
|
||||
if (databaseConnection) {
|
||||
return databaseConnection
|
||||
}
|
||||
let reconnectionTask: NodeJS.Timeout | null = null
|
||||
const RECONNECT_INTERVAL = 6000
|
||||
|
||||
const connection = () => {
|
||||
return mongoose.connect(MONGO_DB.uri, {})
|
||||
}
|
||||
const Badge = `[${chalk.yellow('MongoDB')}]`
|
||||
|
||||
const color = (str: TemplateStringsArray) => {
|
||||
return str.map((s) => chalk.green(s)).join('')
|
||||
}
|
||||
mongoose.connection.on('connecting', () => {
|
||||
consola.info(Badge, color`connecting...`)
|
||||
})
|
||||
|
||||
mongoose.connection.on('open', () => {
|
||||
consola.info(Badge, color`readied!`)
|
||||
if (reconnectionTask) {
|
||||
clearTimeout(reconnectionTask)
|
||||
reconnectionTask = null
|
||||
}
|
||||
})
|
||||
|
||||
mongoose.connection.on('disconnected', () => {
|
||||
consola.error(
|
||||
Badge,
|
||||
chalk.red(`disconnected! retry when after ${RECONNECT_INTERVAL / 1000}s`),
|
||||
)
|
||||
reconnectionTask = setTimeout(connection, RECONNECT_INTERVAL)
|
||||
})
|
||||
|
||||
mongoose.connection.on('error', (error) => {
|
||||
consola.error(Badge, 'error!', error)
|
||||
mongoose.disconnect()
|
||||
})
|
||||
|
||||
databaseConnection = await connection().then(
|
||||
(mongoose) => mongoose.connection,
|
||||
)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return databaseConnection!
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { isInDemoMode } from '~/app.config'
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
import { RedisKeys } from '~/constants/cache.constant'
|
||||
|
||||
type Prefix = 'mx' | 'mx-demo'
|
||||
const prefix = isInDemoMode ? 'mx-demo' : 'mx'
|
||||
const prefix = DEMO_MODE ? 'mx-demo' : 'mx'
|
||||
|
||||
export const getRedisKey = <T extends string = RedisKeys | '*'>(
|
||||
key: T,
|
||||
|
||||
Reference in New Issue
Block a user