fix: app config shared

This commit is contained in:
Innei
2021-10-02 13:11:40 +08:00
parent 6faf5a8cec
commit b7db64e3ae
17 changed files with 909 additions and 693 deletions

View File

@@ -42,5 +42,6 @@ jobs:
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }},innei/mx-server:latest
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -19,4 +19,5 @@
"cSpell.words": [
"qaqdmin"
],
"typescript.tsdk": "node_modules/typescript/lib",
}

View File

@@ -53,18 +53,18 @@
},
"dependencies": {
"@algolia/client-search": "*",
"@nestjs/common": "8.0.7",
"@nestjs/common": "8.0.9",
"@nestjs/config": "1.0.1",
"@nestjs/core": "8.0.7",
"@nestjs/core": "8.0.9",
"@nestjs/graphql": "9.0.5",
"@nestjs/jwt": "8.0.0",
"@nestjs/mapped-types": "*",
"@nestjs/passport": "8.0.1",
"@nestjs/platform-fastify": "8.0.7",
"@nestjs/platform-socket.io": "8.0.7",
"@nestjs/platform-fastify": "8.0.9",
"@nestjs/platform-socket.io": "8.0.9",
"@nestjs/schedule": "1.0.1",
"@nestjs/swagger": "5.0.9",
"@nestjs/websockets": "8.0.7",
"@nestjs/swagger": "5.1.0",
"@nestjs/websockets": "8.0.9",
"@typegoose/auto-increment": "1.0.0",
"@typegoose/typegoose": "8.3.0",
"algoliasearch": "4.10.5",
@@ -117,9 +117,9 @@
"devDependencies": {
"@innei-util/eslint-config-ts": "latest",
"@innei-util/prettier": "latest",
"@nestjs/cli": "8.1.1",
"@nestjs/cli": "8.1.2",
"@nestjs/schematics": "8.0.3",
"@nestjs/testing": "8.0.7",
"@nestjs/testing": "8.0.9",
"@types/bcrypt": "5.0.0",
"@types/cache-manager": "3.4.2",
"@types/ejs": "3.1.0",
@@ -128,7 +128,7 @@
"@types/jest": "27.0.2",
"@types/lodash": "4.14.175",
"@types/marked": "3.0.1",
"@types/mongoose-paginate-v2": "1.3.11",
"@types/mongoose-paginate-v2": "1.4.0",
"@types/node": "16.9.2",
"@types/nodemailer": "6.4.4",
"@types/passport-jwt": "3.0.6",
@@ -140,7 +140,7 @@
"fastify": "*",
"husky": "7.0.2",
"ioredis": "*",
"jest": "27.2.3",
"jest": "27.2.4",
"lint-staged": "11.1.2",
"prettier": "2.4.1",
"rimraf": "3.0.2",
@@ -156,6 +156,7 @@
"webpack-node-externals": "3.0.0"
},
"resolutions": {
"typescript": "4.4.3"
"typescript": "4.4.3",
"apollo-server-fastify/fastify": "*"
}
}

41
patch/bootstrap.js vendored Normal file
View File

@@ -0,0 +1,41 @@
// import { getModelForClass, mongoose } from '@typegoose/typegoose'
// import { config } from 'dotenv'
// import { ConnectionBase } from 'mongoose'
// import * as APP from '../src/app.config.mjs'
// import { CategoryModel } from '../src/modules/category/category.model'
// import { NoteModel } from '../src/modules/note/note.model'
// import { PostModel } from '../src/modules/post/post.model'
// const env = config().parsed || {}
// const url = APP.MONGO_DB.uri
// const opt = {
// useCreateIndex: true,
// useFindAndModify: false,
// useNewUrlParser: true,
// useUnifiedTopology: true,
// autoIndex: true,
// }
// mongoose.connect(url, opt)
// const post = getModelForClass(PostModel)
// const note = getModelForClass(NoteModel)
// const category = getModelForClass(CategoryModel)
// const Config = {
// env,
// db: (mongoose.connection as any).client.db(
// APP.MONGO_DB.collectionName,
// ) as ConnectionBase,
// models: {
// post,
// note,
// category,
// },
// }
// async function bootstrap(cb: (config: typeof Config) => any) {
// await cb.call(this, Config)
// mongoose.disconnect()
// process.exit()
// }
// export { bootstrap as patch }

View File

@@ -1,41 +0,0 @@
import { getModelForClass, mongoose } from '@typegoose/typegoose'
import { config } from 'dotenv'
import { ConnectionBase } from 'mongoose'
import * as APP from '../src/app.config'
import { CategoryModel } from '../src/modules/category/category.model'
import { NoteModel } from '../src/modules/note/note.model'
import { PostModel } from '../src/modules/post/post.model'
const env = config().parsed || {}
const url = APP.MONGO_DB.uri
const opt = {
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser: true,
useUnifiedTopology: true,
autoIndex: true,
}
mongoose.connect(url, opt)
const post = getModelForClass(PostModel)
const note = getModelForClass(NoteModel)
const category = getModelForClass(CategoryModel)
const Config = {
env,
db: (mongoose.connection as any).client.db(
APP.MONGO_DB.collectionName,
) as ConnectionBase,
models: {
post,
note,
category,
},
}
async function bootstrap(cb: (config: typeof Config) => any) {
await cb.call(this, Config)
mongoose.disconnect()
process.exit()
}
export { bootstrap as patch }

11
patch/global.d.ts vendored
View File

@@ -1,11 +0,0 @@
import { ModelType } from '@typegoose/typegoose/lib/types'
import { Document, PaginateModel } from 'mongoose'
/// <reference types="../global" />
declare global {
export type KV<T = any> = Record<string, T>
// @ts-ignore
export type MongooseModel<T> = ModelType<T> & PaginateModel<T & Document>
}
export {}

View File

@@ -1,34 +0,0 @@
{
"compilerOptions": {
"module": "CommonJS",
"declaration": false,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": false,
"outDir": "./dist",
"baseUrl": ".",
"noImplicitAny": false,
"incremental": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"paths": {
"~": [
"../src"
],
"~/*": [
"../src/*"
]
},
},
"include": [
"*.ts",
"../src"
],
"exclude": [
"dist"
]
}

View File

@@ -1,17 +1,17 @@
// patch for version lower than v2.0.0-alpha.1
// // patch for version lower than v2.0.0-alpha.1
import { patch } from './bootstrap'
// import { patch } from './bootstrap'
patch(async ({ models: { note, post, category } }) => {
await Promise.all([
[note, post].map((model) => {
return model.updateMany(
{},
{
$unset: ['options'],
},
)
}),
category.updateMany({}, { $unset: { count: '' } }),
])
})
// patch(async ({ models: { note, post, category } }) => {
// await Promise.all([
// [note, post].map((model) => {
// return model.updateMany(
// {},
// {
// $unset: ['options'],
// },
// )
// }),
// category.updateMany({}, { $unset: { count: '' } }),
// ])
// })

1166
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

63
src/app.config.js Normal file
View File

@@ -0,0 +1,63 @@
const yargs = require('yargs')
const isDev = process.env.NODE_ENV === 'development'
Object.defineProperty(exports, '__esModule', { value: true })
/**
* @type {any}
*/
const argv = yargs.argv
console.log(argv)
exports.API_VERSION = 2
exports.CROSS_DOMAIN = {
allowedOrigins: argv.allowedOrigins
? argv.allowedOrigins?.split?.(',')
: [
'innei.ren',
'shizuri.net',
'localhost:9528',
'localhost:2323',
'127.0.0.1',
'mbp.cc',
'local.innei.test',
'22333322.xyz',
],
// allowedReferer: 'innei.ren',
}
exports.MONGO_DB = {
collectionName: argv.collection_name || 'mx-space',
host: argv.db_host || '127.0.0.1',
port: argv.db_port || 27017,
get uri() {
return `mongodb://${this.host}:${this.port}/${
process.env.TEST ? 'mx-space_unitest' : this.collectionName
}`
},
}
exports.REDIS = {
host: argv.redis_host || 'localhost',
port: argv.redis_port || 6379,
password: argv.redis_password || null,
ttl: null,
httpCacheTTL: 5,
max: 5,
disableApiCache:
(isDev || argv.disableCache) && !process.env['ENABLE_CACHE_DEBUG'],
}
/**
* @type {import('axios').AxiosRequestConfig}
*/
exports.AXIOS_CONFIG = {
timeout: 10000,
}
exports.SECURITY = {
jwtSecret: argv.jwtSecret || 'asjhczxiucipoiopiqm2376',
jwtExpire: '7d',
// 跳过登陆鉴权
skipAuth: argv.skipAuth ?? false,
}

View File

@@ -1,52 +0,0 @@
import type { AxiosRequestConfig } from 'axios'
import yargs from 'yargs'
const argv = yargs.argv as any
console.log(argv)
export const API_VERSION = 2
export const CROSS_DOMAIN = {
allowedOrigins: [
'innei.ren',
'shizuri.net',
'localhost:9528',
'localhost:2323',
'127.0.0.1',
'mbp.cc',
'local.innei.test',
'22333322.xyz',
],
allowedReferer: 'innei.ren',
}
export const MONGO_DB = {
collectionName: (argv.collection_name as string) || 'mx-space',
host: argv.db_host || '127.0.0.1',
port: argv.db_port || 27017,
get uri() {
return `mongodb://${this.host}:${this.port}/${
process.env.TEST ? 'mx-space_unitest' : this.collectionName
}`
},
}
export const REDIS = {
host: argv.redis_host || 'localhost',
port: argv.redis_port || 6379,
password: (argv.redis_password || null) as string,
ttl: null,
httpCacheTTL: 5,
max: 5,
disableApiCache:
(isDev || argv.disableCache) && !process.env['ENABLE_CACHE_DEBUG'],
}
export const AXIOS_CONFIG: AxiosRequestConfig = {
timeout: 10000,
}
export const SECURITY = {
jwtSecret: argv.jwtSecret || 'asjhczxiucipoiopiqm2376',
jwtExpire: '7d',
// 跳过登陆鉴权
skipAuth: argv.skipAuth ?? false,
}

View File

@@ -82,6 +82,7 @@ mkdirs()
playground: isDev,
autoSchemaFile: join(process.cwd(), 'schema.gql'),
context: ({ req }) => ({ req }),
cors: false,
}),
AggregateModule,

View File

@@ -102,41 +102,45 @@ export class AnalyzeInterceptor implements NestInterceptor {
const url = request.url
try {
this.parser.setUA(request.headers['user-agent'])
process.nextTick(async () => {
try {
this.parser.setUA(request.headers['user-agent'])
const ua = this.parser.getResult()
const ua = this.parser.getResult()
await this.model.create({
ip,
ua,
path: new URL('http://a.com' + url).pathname,
})
const apiCallTimeRecord = await this.options.findOne({
name: 'apiCallTime',
})
if (!apiCallTimeRecord) {
await this.options.create({
name: 'apiCallTime',
value: 1,
await this.model.create({
ip,
ua,
path: new URL('http://a.com' + url).pathname,
})
} else {
await this.options.updateOne(
{ name: 'apiCallTime' },
{
$inc: {
value: 1,
const apiCallTimeRecord = await this.options.findOne({
name: 'apiCallTime',
})
if (!apiCallTimeRecord) {
await this.options.create({
name: 'apiCallTime',
value: 1,
})
} else {
await this.options.updateOne(
{ name: 'apiCallTime' },
{
$inc: {
value: 1,
},
},
},
)
}
// ip access in redis
const client = this.cacheService.getClient()
)
}
// ip access in redis
const client = this.cacheService.getClient()
const count = await client.sadd(
getRedisKey(RedisKeys.Access, 'ips'),
ip,
)
if (count) {
// record uv to db
const count = await client.sadd(getRedisKey(RedisKeys.Access, 'ips'), ip)
if (count) {
// record uv to db
process.nextTick(async () => {
const uvRecord = await this.options.findOne({ name: 'uv' })
if (uvRecord) {
await uvRecord.updateOne({
@@ -150,11 +154,11 @@ export class AnalyzeInterceptor implements NestInterceptor {
value: 1,
})
}
})
}
} catch (e) {
console.error(e)
}
} catch (e) {
console.error(e)
}
})
return call$
}

View File

@@ -24,7 +24,7 @@ export class CacheConfigService implements CacheOptionsFactory {
port: REDIS.port as number,
}
if (REDIS.password) {
redisOptions.password = REDIS.password
redisOptions.password = REDIS.password as any
}
return {
store: redisStore,

View File

@@ -0,0 +1,52 @@
import { GraphQLModule } from '@nestjs/graphql'
import { NestFastifyApplication } from '@nestjs/platform-fastify'
import { Test } from '@nestjs/testing'
import { join } from 'path'
import { AppResolver } from '~/app.resolver'
import { fastifyApp } from '~/common/adapt/fastify'
describe('GQL test (e2e)', () => {
let app: NestFastifyApplication
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
GraphQLModule.forRoot({
autoSchemaFile: join(process.cwd(), 'schema.gql'),
context: ({ req }) => ({ req }),
}),
AppResolver,
],
}).compile()
app = moduleRef.createNestApplication<NestFastifyApplication>(fastifyApp)
await app.init()
await app.getHttpAdapter().getInstance().ready()
})
it('GET /graphql', () => {
return app
.inject({
method: 'post',
url: '/graphql',
payload: {
operationName: null,
variables: {},
query: ` {
sayHello
}`,
},
})
.then((res) => {
expect(res.statusCode).toBe(200)
expect(res.json()).toStrictEqual({
data: {
sayHello: 'Hello World!',
},
})
})
})
afterAll(async () => {
await app.close()
})
})

View File

@@ -1,4 +1,9 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
"exclude": [
"node_modules",
"test",
"dist",
"**/*spec.ts"
]
}

View File

@@ -10,6 +10,7 @@
"target": "ES2019",
"sourceMap": true,
"outDir": "./dist",
"allowJs": true,
"baseUrl": ".",
"noImplicitAny": false,
"incremental": true,