From 23009af167d08db4dac970a9666f042fbf6acbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B3=89?= Date: Tue, 22 Nov 2022 15:11:00 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B7=AF=E7=94=B1=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E6=96=B9=E5=BC=8F=EF=BC=8C=E4=BF=AE=E5=A4=8D=E7=A4=BE?= =?UTF-8?q?=E4=BA=A4=E7=99=BB=E9=99=86=E6=97=A0=E6=B3=95=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/api/auth/ApiSocial.ts | 1 + src/api/custom/auth-callback.ts | 38 +- src/api/custom/index.ts | 17 +- src/kernel/auth/abstract-provider.ts | 23 +- src/kernel/auth/index.ts | 2 +- src/kernel/auth/providers/qq.ts | 7 +- src/kernel/redis.ts | 8 +- src/kernel/withHttpServer/index.ts | 192 ++++----- src/shared/db/index.ts | 274 ++++++------ src/shared/protocols/auth/PtlSocial.ts | 2 +- src/shared/protocols/serviceProto.ts | 572 ++++++++++++------------- src/type.ts | 1 + src/utils/auth.ts | 1 - yarn.lock | 5 + 15 files changed, 570 insertions(+), 574 deletions(-) diff --git a/package.json b/package.json index 3b8c2a2..8ffdfd0 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "putil-promisify": "^1.8.5", "qcloud-cos-sts": "^3.1.0", "qs": "^6.11.0", + "route-recognizer": "^0.3.4", "tsrpc": "^3.4.10", "zod": "^3.19.1" } diff --git a/src/api/auth/ApiSocial.ts b/src/api/auth/ApiSocial.ts index 20a43d0..20c37af 100644 --- a/src/api/auth/ApiSocial.ts +++ b/src/api/auth/ApiSocial.ts @@ -28,6 +28,7 @@ export default async function (call: ApiCall) { let qqUrl = await redis.getCacheKey(`auth:${call.req.id}`) if (!qqUrl) { qqUrl = await qqProvider.getAuthorizationUrl({ + id: call.req.id as never, srp: call.req.srp, erp: call.req.erp, }) diff --git a/src/api/custom/auth-callback.ts b/src/api/custom/auth-callback.ts index 9f6c88b..4a7d142 100644 --- a/src/api/custom/auth-callback.ts +++ b/src/api/custom/auth-callback.ts @@ -1,13 +1,17 @@ import { ApiHandle } from '../../kernel/withHttpServer/types' import { z } from 'zod' import authManager from '../../kernel/auth' +import redis from '../../kernel/redis' -const schema = z.object({ - erp: z.string().nullable().optional(), - srp: z.string().nullable().optional(), - sn: z.string(), - state: z.string(), -}) +const schema = z + .object({ + erp: z.string().nullable().optional(), + srp: z.string().nullable().optional(), + sn: z.string(), + state: z.string(), + id: z.string().optional().nullable(), + }) + .passthrough() function addParams(url: string, params: Record) { const u = new URL(url) @@ -24,29 +28,39 @@ export const AuthCallback: ApiHandle = async (req, res) => { if (!provider) { if (inputData.erp) { return res.redirect( - addParams(inputData.erp, { error: 'provider not found' }), + addParams(inputData.erp, { + error: '登陆服务错误,请联系管理员', + }), ) } - return res.send('No provider found', 404) + return res.send('登陆服务错误,请联系管理员', 404) } const result = await provider.verifyCallback(inputData) + + console.info('verifyCallback result', result) + if (result) { const accessToken = await provider.getUserAccessToken(inputData) const user = await provider.getUserInfo(accessToken) - console.log(user) + // TODO 处理用户信息 if (inputData.srp) { return res.redirect(addParams(inputData.srp, { success: 'true' })) } - return res.json({}) + return res.json(user) + } + + if (inputData.id) { + await redis.delCacheKey(`auth:${inputData.id}`) } if (inputData.erp) { return res.redirect( - addParams(inputData.erp, { error: 'verify input data error' }), + addParams(inputData.erp, { error: '参数错误无法登陆' }), ) } - return res.send('fail', 404) + + return res.send('登陆失败,即将回到主站', 404) } diff --git a/src/api/custom/index.ts b/src/api/custom/index.ts index 64f5c78..c1ef541 100644 --- a/src/api/custom/index.ts +++ b/src/api/custom/index.ts @@ -1,17 +1,8 @@ -import { ApiHandleMap } from '../../kernel/withHttpServer/types' import { WechatCallback } from './wechat-callback' import { AuthCallback } from './auth-callback' +import RouteRecognizer from 'route-recognizer' -export const TrdApis: ApiHandleMap = { - '/trd/wechat': WechatCallback, - '/custom/auth/social': AuthCallback, -} +export const customRouter = new RouteRecognizer() -export const TrdApiKeys = Object.keys(TrdApis) - .map((item) => { - return [item.replaceAll('//', '/').toLowerCase(), item] as [ - string, - keyof typeof TrdApis, - ] - }) - .filter((item) => item[0].length) +customRouter.add([{ path: '/custom/auth/social', handler: AuthCallback }]) +customRouter.add([{ path: '/trd/wechat', handler: WechatCallback }]) diff --git a/src/kernel/auth/abstract-provider.ts b/src/kernel/auth/abstract-provider.ts index 277ef1f..28d3c9c 100644 --- a/src/kernel/auth/abstract-provider.ts +++ b/src/kernel/auth/abstract-provider.ts @@ -10,6 +10,7 @@ export interface OAuthProviderBaseOptions { export interface BaseAuthorizationUrl { erp?: string srp?: string + id: string } function resolve(from: string, to: string) { @@ -36,30 +37,27 @@ export abstract class OAuthProvider { return id } - static async getStateValue(state: string): Promise { - const value = await redis.get(`oauth:state:${state}`) - if (value) { - await redis.del(`oauth:state:${state}`) - } - return value + static getStateValue(state: string): Promise { + return redis.get(`oauth:state:${state}`) } static async verifyState(state: string) { const result = await redis.get(`oauth:state:${state}`) - if (result) { - await redis.del(`oauth:state:${state}`) - return true - } - return false + return !!result + } + + static async clearState(state: string): Promise { + return redis.del(`oauth:state:${state}`) } getCallbackUrl( + id: string, errorRedirectPath?: string, successRedirectPath?: string, ): Promise { const appUrl = env.APP_URL const callbackPath = this.options.callbackPath || '/custom/auth/social' - const callbackUrl = resolve(callbackPath, appUrl) + const callbackUrl = resolve(appUrl, callbackPath) const url = new URL(callbackUrl) // 如果失败了,就跳转到 errorRedirectPath @@ -72,6 +70,7 @@ export abstract class OAuthProvider { } url.searchParams.set('sn', this.options.name) + url.searchParams.set('id', id) return Promise.resolve(url.toString()) } diff --git a/src/kernel/auth/index.ts b/src/kernel/auth/index.ts index 3392ddb..3511650 100644 --- a/src/kernel/auth/index.ts +++ b/src/kernel/auth/index.ts @@ -36,7 +36,7 @@ export class AuthManager { const driveClass = AuthManager.getDrive(driver) const instance = new driveClass({ name, - options, + ...options, }) this.instances.set(name, instance) return instance diff --git a/src/kernel/auth/providers/qq.ts b/src/kernel/auth/providers/qq.ts index 1c5e464..9475195 100644 --- a/src/kernel/auth/providers/qq.ts +++ b/src/kernel/auth/providers/qq.ts @@ -61,7 +61,11 @@ export class QQProvider extends OAuthProvider { async getAuthorizationUrl(params: BaseAuthorizationUrl): Promise { const scope = ['get_user_info'] - const redirectUrl = await this.getCallbackUrl(params.erp, params.srp) + const redirectUrl = await this.getCallbackUrl( + params.id, + params.erp, + params.srp, + ) const url = new URL('https://graph.qq.com/oauth2.0/authorize') url.searchParams.set('response_type', 'code') url.searchParams.set('client_id', this.options.clientId) @@ -118,6 +122,7 @@ export class QQProvider extends OAuthProvider { if (isQQApiError(data)) { return reject(new Error(data.error_description)) } + OAuthProvider.clearState(params.state) return resolve(data) }) .catch((error) => { diff --git a/src/kernel/redis.ts b/src/kernel/redis.ts index 9a5053c..a8a2348 100644 --- a/src/kernel/redis.ts +++ b/src/kernel/redis.ts @@ -2,11 +2,15 @@ import Redis, { RedisOptions } from 'ioredis' class RedisHelper extends Redis { async setCacheKey(key: string, value: string, ttl = 60 * 10) { - await this.set(key, value, 'EX', ttl) + await this.set(`cache:${key}`, value, 'EX', ttl) } async getCacheKey(key: string): Promise { - return this.get(key) + return this.get(`cache:${key}`) + } + + async delCacheKey(key: string): Promise { + return this.del(`cache:${key}`) } } diff --git a/src/kernel/withHttpServer/index.ts b/src/kernel/withHttpServer/index.ts index 94d08e8..ed4141f 100644 --- a/src/kernel/withHttpServer/index.ts +++ b/src/kernel/withHttpServer/index.ts @@ -1,9 +1,9 @@ import { HttpConnection, HttpServer, WsServer } from 'tsrpc' -import { TrdApiKeys, TrdApis } from '../../api/custom' -import * as Url from 'url' +import { customRouter } from '../../api/custom' import contentType from 'content-type' -import { get } from 'lodash' +import { first, get } from 'lodash' import * as multipart from 'parse-multipart-data' +import { ApiHandle } from './types' const faviconData = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAMAAABHPGVmAAAAnFBMVEUAAACNGP+OGP+QE/6QE/6QE/+QE/6QE/6QE/+QE/+OEP6QE/6QE/+QE/6QE/+PEv6QE/6QE/+NFf+QE/6PE/6PE/6QE/+PEv6QE/6QE/6RFf+QE/6QE/+QE/6QEv+RE/6RE/+PE/6PEv+OEvyPFv+PE/6QE/6QEv+QE/+QE/+QE/6QE/6QE/6QFP2PE/+QEv6QE/+YFP+TE/+VFP9J4z+dAAAAMHRSTlMAEwelooVhlGnqIYAm97gs88MW2HFO5NK1WAvu3cZ8d1xAOBs7NKlTSa2d+8uPvolR0VdZAAAETUlEQVRo3u1a6XKjMAw2V0JK7vskR5umSdquj/d/t7XAi41TsKeFmWYn348MNsafELYkS0EPPPBbMAy9btcLh6g+PA0ITkAGT6gmNAjOQBqoFvxhWAELUA1YJBydy3Z76SQsJ1Q9EiVF6XVEoFU9RxOEX+Req1k5CajIk02PN/tVc7S56ORZtp+5wli7YpI3qknex5i+VUyy4yQbtWPASXYVkyw4yVrtmHKSqhfxEb6J2gHf5IgqBqzZUDZDWNGoanT5rDSzvg7lzW7lJG0CO+NJmGPYNaQGS+wlBsuf9HoTj8G19wO3FKwZIfgzRDpGGEAZoxgwQjrCASaEjQKjS/Mzn9G58RjvFGeg7zfeppP5Gr+UwmmpHuNmbEQzjghpeKVYouUUc7ipMIyQ9InzzYDtDPpnWxdpOKfchLBUDW4hSTIDDY6OM5kzuBwjHUvC1bFEOsYUhJtPHOcY0ESOMvuER0KGPQbcCOQAyY0yXAoi7UVjhEvsWgu0mbVe4F0CO5IA3uOQm2haEPAQORLgwVA7kikfepHNg3Q+OkL+ziul3YOhrg3JEsTrIYkV11f4JUmk72J49NmG5Ek30a98qqgwVPC1+IS9GEnE57vmtjR/9KPwTeZqx1fzOYWdasecTxV/STKhXJOaW2d2H55oDh9mmsimNhSP8wZxYEcyyG+/MZZLRscG7mWLpAni7OxIdjC2mS1LoomnbRSOhmLwWshEItcspq/CHLNSjxZQGLtqjiOggLVvJpF7CmiicXOVTBKUOHKKFbAJsiVBJ4YV0FL33yTKyBdkT4JeFPnIhyG+WjPhGbwlsiYBLD3hhdj6aA5LYn8z9xsuQiYSHW7Dn2/8uI3sYU+i40Hy/5E0OiLuqw+9ERX7dNRD9WB5VtMe5yWqARHDANbtiouocopTP9XT9IDQoZVqbXWq9gQ0E0Y2zA5zADar7iTvivMEa8q+i9CZ735P6tgf5AzkVoi9ycVgzxvxctucgRzYGMiDbur36QegrbebJMW/O3sEcKxNfZPlndZQkfcWWyrecciFUZ0W6NXW/S6EoyRegeZdj4hZG9bu908aSHyMYy/VRPrErF227sSg5MeLxx8ykLAMiQD9hSHr0v8n/lnYNyxDInNwZ5vPDEBVlsGdHqZOIbpbWlk1ebQyhaknLeCeUOscDdECbCratkcHa0+mZ3vi7x2CJCwPQfbHOSPMxznzwdQA48HUfMReIytM80rYFx+x0dSYLJAwJwvK0h5rLe1hBReraY81NHaGBM5BT+CYIRM4h3T/z36QiorfKb/5HptTUd9PqsEMBaGKz7SkWt3pwYs50TlihFwLE538JitKdH5eDYlO25Tt3nH2vpqyrS/53AettCsn+QThh5lSlTT6nRUESkobd1akKSk33VnhrP4SIKBfWsy8p7JsWmAOhCeso8AsS+VXKJVf9VL5fRX9jX9fuKM/Yqh/KXnggV+CvzLSIHrncBfgAAAAAElFTkSuQmCC', @@ -87,116 +87,100 @@ export function withHttpServer(server: HttpServer | WsServer) { const serviceId = node.serviceId if (!serviceId) { const conn = node.conn as HttpConnection + const urlPath = conn.httpReq.url || '' + + if (urlPath.startsWith('favicon.ico')) { + // png + conn.httpRes.writeHead(200, { + 'Content-Type': 'image/png', + }) + conn.httpRes.end(faviconData, 'binary') + return + } + + const handleResults = customRouter.recognize(urlPath) + const handleResult = first(handleResults) + + if (handleResult) { + const handler = handleResult.handler as ApiHandle + const params = handleResult.params + + conn.httpReq.query = handleResults?.queryParams || {} + conn.httpReq.rawQuery = urlPath.split('?')[1] || '' + + const contentTypeStr = get(conn.httpReq.headers, 'content-type') - if (Object.keys(TrdApis).length) { - const urlParse = Url.parse(conn.httpReq.url || '', true) - let urlPath = urlParse.pathname || '' - urlPath = urlPath.replaceAll('//', '/').toLowerCase() + const charset = contentTypeStr + ? (contentType.parse(conn.httpReq).parameters + .charset as BufferEncoding) + : 'utf-8' - if (urlPath == 'favicon.ico') { - // png + conn.httpReq.params = params + conn.httpReq.body = parseBody( + conn.httpReq.rawBody, + charset, + conn.httpReq.headers['content-type'] || '', + ) + + conn.httpRes.json = (data: any) => { conn.httpRes.writeHead(200, { - 'Content-Type': 'image/png', + 'Content-Type': 'application/json', }) - conn.httpRes.end(faviconData, 'binary') - return + conn.httpRes.end(JSON.stringify(data)) + } + conn.httpRes.xml = (data: any) => { + conn.httpRes.writeHead(200, { + 'Content-Type': 'text/xml', + }) + conn.httpRes.end(data) + } + conn.httpRes.text = (data: any) => { + conn.httpRes.writeHead(200, { + 'Content-Type': 'text/plain', + }) + conn.httpRes.end(data) + } + conn.httpRes.html = (data: any) => { + conn.httpRes.writeHead(200, { + 'Content-Type': 'text/html', + }) + conn.httpRes.end(data) + } + conn.httpRes.file = (data: Buffer, filename) => { + conn.httpRes.writeHead(200, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename=${filename}`, + }) + conn.httpRes.end(data) + } + conn.httpRes.redirect = (url: string) => { + conn.httpRes.writeHead(302, { + Location: url, + }) + conn.httpRes.end() + } + conn.httpRes.redirectBack = () => { + conn.httpRes.writeHead(302, { + Location: conn.httpReq.headers.referer || '/', + }) + conn.httpRes.end() + } + conn.httpRes.send = (data: any, code = 200) => { + conn.httpRes.statusCode = code + conn.httpRes.end(data) } - if (urlPath.length !== 0) { - const handleKey = TrdApiKeys.reduce< - keyof typeof TrdApis | undefined - >( - ( - previousValue, - [currentValue, handleKey], - currentIndex, - array, - ) => { - if (urlPath === currentValue) { - previousValue = handleKey - array.splice(1) - } - return previousValue - }, - undefined, - ) - - const handle = handleKey ? TrdApis[handleKey] : undefined - if (handle) { - conn.httpReq.query = urlParse.query - conn.httpReq.rawQuery = urlParse.search - - const contentTypeStr = get( - conn.httpReq.headers, - 'content-type', - ) - - const charset = contentTypeStr - ? (contentType.parse(conn.httpReq).parameters - .charset as BufferEncoding) - : 'utf-8' - - conn.httpReq.body = parseBody( - conn.httpReq.rawBody, - charset, - conn.httpReq.headers['content-type'] || '', - ) - - conn.httpRes.json = (data: any) => { - conn.httpRes.writeHead(200, { - 'Content-Type': 'application/json', - }) - conn.httpRes.end(JSON.stringify(data)) - } - conn.httpRes.xml = (data: any) => { - conn.httpRes.writeHead(200, { - 'Content-Type': 'text/xml', - }) - conn.httpRes.end(data) - } - conn.httpRes.text = (data: any) => { - conn.httpRes.writeHead(200, { - 'Content-Type': 'text/plain', - }) - conn.httpRes.end(data) - } - conn.httpRes.html = (data: any) => { - conn.httpRes.writeHead(200, { - 'Content-Type': 'text/html', - }) - conn.httpRes.end(data) - } - conn.httpRes.file = (data: Buffer, filename) => { - conn.httpRes.writeHead(200, { - 'Content-Type': 'application/octet-stream', - 'Content-Disposition': `attachment; filename=${filename}`, - }) - conn.httpRes.end(data) - } - conn.httpRes.redirect = (url: string) => { - conn.httpRes.writeHead(302, { - Location: url, - }) - conn.httpRes.end() - } - conn.httpRes.redirectBack = () => { - conn.httpRes.writeHead(302, { - Location: conn.httpReq.headers.referer || '/', - }) - conn.httpRes.end() - } - conn.httpRes.send = (data: any, code = 200) => { - conn.httpRes.statusCode = code - conn.httpRes.end(data) - } - - server.logger.log(`custom http request: ${urlPath}`) + server.logger.log(`custom http request: ${urlPath}`) - await handle(conn.httpReq, conn.httpRes) - return null - } + try { + await handler(conn.httpReq, conn.httpRes) + } catch (e: any) { + server.logger.error(e) + conn.httpRes.send(e.message || 'Server error', 500) } + return null } + conn.httpRes.statusCode = 404 conn.httpRes.end() return null diff --git a/src/shared/db/index.ts b/src/shared/db/index.ts index b80ddfa..8033125 100644 --- a/src/shared/db/index.ts +++ b/src/shared/db/index.ts @@ -2,283 +2,277 @@ /* Enum 消费类型 */ export enum UserFileConsumeType { - MEMBER = "MEMBER", - RESOURCE_PACKAGE = "RESOURCE_PACKAGE", - OTHER = "OTHER" + MEMBER = 'MEMBER', + RESOURCE_PACKAGE = 'RESOURCE_PACKAGE', + OTHER = 'OTHER', } - - /* Enum 用户记录来源 */ export enum UserRecordSource { - Promoter = "Promoter", - Order = "Order", - System = "System", - Activity = "Activity", - Other = "Other" + Promoter = 'Promoter', + Order = 'Order', + System = 'System', + Activity = 'Activity', + Other = 'Other', } - - /* Enum 用户记录类型 */ export enum UserRecordType { - Alliance = "Alliance", - Withdraw = "Withdraw", - ResourcePackage = "ResourcePackage", - Member = "Member", - Other = "Other" + Alliance = 'Alliance', + Withdraw = 'Withdraw', + ResourcePackage = 'ResourcePackage', + Member = 'Member', + Other = 'Other', } - - /* Model 用户 */ export type User = { /* ID 主键 */ - id: number; + id: number /* 昵称 */ - nickname: string; + nickname: string /* 头像 */ - avatar: string | null; + avatar: string | null /* 手机号 */ - phone: string | null; + phone: string | null /* 手机区号 */ - phoneCode: string | null; + phoneCode: string | null /* 手机是否验证 */ - phoneVerififedAt: Date | null; + phoneVerififedAt: Date | null /* 是否会员 */ - isMember: boolean; + isMember: boolean /* 会员等级 */ - memberLevel: number; + memberLevel: number /* 会员过期时间 */ - memberExpiredAt: Date | null; + memberExpiredAt: Date | null /* 会员开通时间 */ - memberStartedAt: Date | null; + memberStartedAt: Date | null /* 登陆 IP */ - loginIp: string | null; + loginIp: string | null /* 登陆时间 */ - loginAt: Date | null; + loginAt: Date | null /* 注册 IP */ - registerIp: string | null; + registerIp: string | null /* 注册时间 */ - registerAt: Date | null; + registerAt: Date | null /* 注册渠道 */ - registerChannel: string | null; + registerChannel: string | null /* 邀请人 ID */ - inviterId: number | null; + inviterId: number | null /* 邀请活动 ID */ - inviteActivityId: number | null; + inviteActivityId: number | null /* 是否开通推广联盟 */ - isPromoter: boolean; + isPromoter: boolean /* 推广联盟会员订单分成 */ - promoterOrderDivide: number | null; + promoterOrderDivide: number | null /* 推广联盟资源包订单分成 */ - promoterPackageDivide: number | null; + promoterPackageDivide: number | null /* 推广联盟其他类型订单分成 */ - promoterOtherDivide: number | null; + promoterOtherDivide: number | null /* 总提成 */ - totalDivide: number | null; + totalDivide: number | null /* 已提现 */ - withdrawedDivide: number | null; + withdrawedDivide: number | null /* 未提现 */ - unwithdrawDivide: number | null; + unwithdrawDivide: number | null /* 已结算提成 */ - settledDivide: number | null; + settledDivide: number | null /* 未结算提成 */ - unsettledDivide: number | null; + unsettledDivide: number | null /* 会员天数奖励 */ - memberDayReward: number | null; + memberDayReward: number | null /* 资源包次数奖励 */ - packageCountReward: number | null; + packageCountReward: number | null /* 提现方式 */ - withdrawType: string | null; + withdrawType: string | null /* 提现账号 */ - withdrawAccount: string | null; + withdrawAccount: string | null /* 是否封禁 */ - isBanned: boolean; + isBanned: boolean /* 封禁原因 */ - bannedReason: string | null; + bannedReason: string | null /* 封禁时间 */ - bannedAt: Date | null; + bannedAt: Date | null /* 封禁过期时间 */ - bannedExpiredAt: Date | null; + bannedExpiredAt: Date | null /* 创建时间 */ - createdAt: Date; + createdAt: Date /* 更新时间 */ - updatedAt: Date; + updatedAt: Date /* 删除时间 */ - deletedAt: Date | null; + deletedAt: Date | null /* 文件 */ - files: UserFile[]; + files: UserFile[] /* 批量文件处理记录 */ - batchFiles: UserBatchFile[]; + batchFiles: UserBatchFile[] /* 资源包 */ - resourcePackages: UserResourcePackage[]; + resourcePackages: UserResourcePackage[] /* 用户记录 */ - records: UserRecord[]; -}; + records: UserRecord[] +} /* Model 用户文件 */ export type UserFile = { /* ID 主键 */ - id: number; + id: number /* 文件名 */ - fileName: string | null; + fileName: string | null /* 文件大小 */ - fileSize: number | null; + fileSize: number | null /* 文件尺寸 [width,height] */ - fileDimension: number[]; + fileDimension: number[] /* 文件 MD5 */ - fileMd5: string | null; + fileMd5: string | null /* 文件路径 */ - filePath: string | null; + filePath: string | null /* 结果路径 */ - resultPath: string | null; + resultPath: string | null /* 结果大小 */ - resultSize: number | null; + resultSize: number | null /* 结果尺寸 [width,height] */ - resultDimension: number[]; + resultDimension: number[] /* 结果 MD5 */ - resultMd5: string | null; + resultMd5: string | null /* 结果缩略图路径 */ - thumbnailResultPath: string | null; + thumbnailResultPath: string | null /* 结果缩略图大小 */ - thumbnailResultSize: number | null; + thumbnailResultSize: number | null /* 结果缩略图尺寸 [width,height] */ - thumbnailResultDimension: number[]; + thumbnailResultDimension: number[] /* 结果缩略图 MD5 */ - thumbnailResultMd5: string | null; + thumbnailResultMd5: string | null /* 缩略图路径 */ - thumbnailPath: string | null; + thumbnailPath: string | null /* 缩略图大小 */ - thumbnailSize: number | null; + thumbnailSize: number | null /* 缩略图尺寸 [width,height] */ - thumbnailDimension: number[]; + thumbnailDimension: number[] /* 缩略图 MD5 */ - thumbnailMd5: string | null; + thumbnailMd5: string | null /* 任务状态 */ - taskStatus: string | null; + taskStatus: string | null /* 任务重试次数 */ - taskRetryCount: number | null; + taskRetryCount: number | null /* 任务错误信息 */ - taskError: string | null; + taskError: string | null /* 任务最近一次启动时间 */ - taskLastStartedAt: Date | null; + taskLastStartedAt: Date | null /* 任务最近一次数据汇报时间 */ - taskLastReportedAt: Date | null; + taskLastReportedAt: Date | null /* 任务人脸数据 */ - taskFaceData: any | null; + taskFaceData: any | null /* 任务类型 */ - taskType: string | null; + taskType: string | null /* 原始数据是否删除 */ - isOriginalFileDeleted: boolean | null; + isOriginalFileDeleted: boolean | null /* 原始数据删除时间 */ - originalFileDeletedAt: Date | null; + originalFileDeletedAt: Date | null /* 是否来自小程序上传 */ - isFromMiniProgram: boolean | null; + isFromMiniProgram: boolean | null /* 是否来自应用上传 */ - isFromApp: boolean | null; + isFromApp: boolean | null /* 是否来自桌面端上传 */ - isFromDesktop: boolean | null; + isFromDesktop: boolean | null /* 分享 短Key */ - shareShortKey: string | null; + shareShortKey: string | null /* 分享查看次数 */ - shareViewCount: number | null; + shareViewCount: number | null /* 分享下载次数 */ - shareDownloadCount: number | null; + shareDownloadCount: number | null /* 是否已经消费 */ - isConsumed: boolean | null; + isConsumed: boolean | null /* 消费类型 */ - consumeType: UserFileConsumeType | null; + consumeType: UserFileConsumeType | null /* 创建时间 */ - createdAt: Date; + createdAt: Date /* 更新时间 */ - updatedAt: Date; + updatedAt: Date /* 删除时间 */ - deletedAt: Date | null; + deletedAt: Date | null /* 用户 */ - user: User | null; + user: User | null /* 用户 ID */ - userId: number | null; + userId: number | null /* 批量执行 */ - batch: UserBatchFile | null; + batch: UserBatchFile | null /* 批量执行 ID */ - batchId: number | null; -}; + batchId: number | null +} /* Model 用户批量文件处理记录 */ export type UserBatchFile = { /* ID 主键 */ - id: number; + id: number /* 总文件 */ - total: number | null; + total: number | null /* 已完成文件 */ - completed: number | null; + completed: number | null /* 失败的文件 */ - failed: number | null; + failed: number | null /* 总大小 */ - totalSize: number | null; + totalSize: number | null /* 压缩包路径 */ - zipPath: string | null; + zipPath: string | null /* 压缩包大小 */ - zipSize: number | null; + zipSize: number | null /* 创建时间 */ - createdAt: Date; + createdAt: Date /* 更新时间 */ - updatedAt: Date; + updatedAt: Date /* 删除时间 */ - deletedAt: Date | null; + deletedAt: Date | null /* 文件 */ - files: UserFile[]; + files: UserFile[] /* 用户 */ - user: User | null; + user: User | null /* 用户 ID */ - userId: number | null; -}; + userId: number | null +} /* Model 用户资源包 */ export type UserResourcePackage = { /* ID 主键 */ - id: number; + id: number /* 总次数 */ - total: number | null; + total: number | null /* 已使用次数 */ - used: number | null; + used: number | null /* 上一次消费时间 */ - lastUsedAt: Date | null; + lastUsedAt: Date | null /* 来源 */ - source: string | null; + source: string | null /* 创建时间 */ - createdAt: Date; + createdAt: Date /* 更新时间 */ - updatedAt: Date; + updatedAt: Date /* 删除时间 */ - deletedAt: Date | null; + deletedAt: Date | null /* 用户 */ - user: User | null; + user: User | null /* 用户 ID */ - userId: number | null; -}; + userId: number | null +} /* Model 用户记录 */ export type UserRecord = { /* ID 主键 */ - id: number; + id: number /* 来源 */ - source: UserRecordSource; + source: UserRecordSource /* 类型 */ - type: UserRecordType; + type: UserRecordType /* 具体数据 */ - data: any | null; + data: any | null /* 备注 */ - remark: string | null; + remark: string | null /* 创建时间 */ - createdAt: Date; + createdAt: Date /* 更新时间 */ - updatedAt: Date; + updatedAt: Date /* 删除时间 */ - deletedAt: Date | null; + deletedAt: Date | null /* 用户 */ - user: User | null; + user: User | null /* 用户 ID */ - userId: number | null; -}; \ No newline at end of file + userId: number | null +} diff --git a/src/shared/protocols/auth/PtlSocial.ts b/src/shared/protocols/auth/PtlSocial.ts index 6c8b144..62424b2 100644 --- a/src/shared/protocols/auth/PtlSocial.ts +++ b/src/shared/protocols/auth/PtlSocial.ts @@ -1,4 +1,4 @@ -import { BaseRequest, BaseResponse, BaseConf } from '../base' +import { BaseConf, BaseRequest, BaseResponse } from '../base' export interface ReqSocial extends BaseRequest { id?: string diff --git a/src/shared/protocols/serviceProto.ts b/src/shared/protocols/serviceProto.ts index 0de6f57..11ba922 100644 --- a/src/shared/protocols/serviceProto.ts +++ b/src/shared/protocols/serviceProto.ts @@ -1,385 +1,383 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { ReqSocial, ResSocial } from './auth/PtlSocial'; -import { ReqSession, ResSession } from './test/PtlSession'; -import { ReqThrottler, ResThrottler } from './test/PtlThrottler'; +import { ServiceProto } from 'tsrpc-proto' +import { ReqSocial, ResSocial } from './auth/PtlSocial' +import { ReqSession, ResSession } from './test/PtlSession' +import { ReqThrottler, ResThrottler } from './test/PtlThrottler' export interface ServiceType { api: { - "auth/Social": { - req: ReqSocial, + 'auth/Social': { + req: ReqSocial res: ResSocial - }, - "test/Session": { - req: ReqSession, + } + 'test/Session': { + req: ReqSession res: ResSession - }, - "test/Throttler": { - req: ReqThrottler, + } + 'test/Throttler': { + req: ReqThrottler res: ResThrottler } - }, - msg: { - } + msg: {} } export const serviceProto: ServiceProto = { - "version": 12, - "services": [ + version: 12, + services: [ { - "id": 3, - "name": "auth/Social", - "type": "api", - "conf": {} + id: 3, + name: 'auth/Social', + type: 'api', + conf: {}, }, { - "id": 1, - "name": "test/Session", - "type": "api", - "conf": {} + id: 1, + name: 'test/Session', + type: 'api', + conf: {}, }, { - "id": 2, - "name": "test/Throttler", - "type": "api", - "conf": { - "throttler": { - "ttl": 120, - "limit": 10 - } - } - } + id: 2, + name: 'test/Throttler', + type: 'api', + conf: { + throttler: { + ttl: 120, + limit: 10, + }, + }, + }, ], - "types": { - "auth/PtlSocial/ReqSocial": { - "type": "Interface", - "extends": [ + types: { + 'auth/PtlSocial/ReqSocial': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseRequest" - } - } + id: 0, + type: { + type: 'Reference', + target: 'base/BaseRequest', + }, + }, ], - "properties": [ + properties: [ { - "id": 0, - "name": "id", - "type": { - "type": "String" + id: 0, + name: 'id', + type: { + type: 'String', }, - "optional": true + optional: true, }, { - "id": 1, - "name": "erp", - "type": { - "type": "String" + id: 1, + name: 'erp', + type: { + type: 'String', }, - "optional": true + optional: true, }, { - "id": 2, - "name": "srp", - "type": { - "type": "String" + id: 2, + name: 'srp', + type: { + type: 'String', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "base/BaseRequest": { - "type": "Interface", - "properties": [ + 'base/BaseRequest': { + type: 'Interface', + properties: [ { - "id": 1, - "name": "_publicData", - "type": { - "type": "Reference", - "target": "base/PublicData" + id: 1, + name: '_publicData', + type: { + type: 'Reference', + target: 'base/PublicData', }, - "optional": true + optional: true, }, { - "id": 2, - "name": "_timestamp", - "type": { - "type": "Number" + id: 2, + name: '_timestamp', + type: { + type: 'Number', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "base/PublicData": { - "type": "Interface", - "extends": [ + 'base/PublicData': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/SessionData" - } - } + id: 0, + type: { + type: 'Reference', + target: 'base/SessionData', + }, + }, ], - "properties": [ + properties: [ { - "id": 0, - "name": "_hash", - "type": { - "type": "String" + id: 0, + name: '_hash', + type: { + type: 'String', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "base/SessionData": { - "type": "Interface", - "indexSignature": { - "keyType": "String", - "type": { - "type": "Union", - "members": [ + 'base/SessionData': { + type: 'Interface', + indexSignature: { + keyType: 'String', + type: { + type: 'Union', + members: [ { - "id": 0, - "type": { - "type": "Tuple", - "elementTypes": [ + id: 0, + type: { + type: 'Tuple', + elementTypes: [ { - "type": "Union", - "members": [ + type: 'Union', + members: [ { - "id": 0, - "type": { - "type": "Number" - } + id: 0, + type: { + type: 'Number', + }, }, { - "id": 1, - "type": { - "type": "Literal", - "literal": null - } + id: 1, + type: { + type: 'Literal', + literal: null, + }, }, { - "id": 2, - "type": { - "type": "Literal" - } - } - ] + id: 2, + type: { + type: 'Literal', + }, + }, + ], }, { - "type": "Any" - } - ] - } + type: 'Any', + }, + ], + }, }, { - "id": 1, - "type": { - "type": "Any" - } - } - ] - } - } + id: 1, + type: { + type: 'Any', + }, + }, + ], + }, + }, }, - "auth/PtlSocial/ResSocial": { - "type": "Interface", - "extends": [ + 'auth/PtlSocial/ResSocial': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseResponse" - } - } + id: 0, + type: { + type: 'Reference', + target: 'base/BaseResponse', + }, + }, ], - "properties": [ + properties: [ { - "id": 0, - "name": "qq", - "type": { - "type": "String" - } - } - ] + id: 0, + name: 'qq', + type: { + type: 'String', + }, + }, + ], }, - "base/BaseResponse": { - "type": "Interface", - "properties": [ + 'base/BaseResponse': { + type: 'Interface', + properties: [ { - "id": 3, - "name": "_publicData", - "type": { - "type": "Reference", - "target": "base/PublicData" + id: 3, + name: '_publicData', + type: { + type: 'Reference', + target: 'base/PublicData', }, - "optional": true + optional: true, }, { - "id": 1, - "name": "_timestamp", - "type": { - "type": "Number" + id: 1, + name: '_timestamp', + type: { + type: 'Number', }, - "optional": true + optional: true, }, { - "id": 2, - "name": "_throttler", - "type": { - "type": "Interface", - "properties": [ + id: 2, + name: '_throttler', + type: { + type: 'Interface', + properties: [ { - "id": 0, - "name": "limit", - "type": { - "type": "Number" + id: 0, + name: 'limit', + type: { + type: 'Number', }, - "optional": true + optional: true, }, { - "id": 1, - "name": "remaining", - "type": { - "type": "Number" + id: 1, + name: 'remaining', + type: { + type: 'Number', }, - "optional": true + optional: true, }, { - "id": 2, - "name": "reset", - "type": { - "type": "Number" + id: 2, + name: 'reset', + type: { + type: 'Number', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "optional": true - } - ] + optional: true, + }, + ], }, - "test/PtlSession/ReqSession": { - "type": "Interface", - "extends": [ + 'test/PtlSession/ReqSession': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseRequest" - } - } + id: 0, + type: { + type: 'Reference', + target: 'base/BaseRequest', + }, + }, ], - "properties": [ + properties: [ { - "id": 0, - "name": "type", - "type": { - "type": "Union", - "members": [ + id: 0, + name: 'type', + type: { + type: 'Union', + members: [ { - "id": 0, - "type": { - "type": "Literal", - "literal": "public" - } + id: 0, + type: { + type: 'Literal', + literal: 'public', + }, }, { - "id": 1, - "type": { - "type": "Literal", - "literal": "private" - } + id: 1, + type: { + type: 'Literal', + literal: 'private', + }, }, { - "id": 2, - "type": { - "type": "Literal", - "literal": "user" - } + id: 2, + type: { + type: 'Literal', + literal: 'user', + }, }, { - "id": 3, - "type": { - "type": "Literal", - "literal": null - } - } - ] - } + id: 3, + type: { + type: 'Literal', + literal: null, + }, + }, + ], + }, }, { - "id": 1, - "name": "userId", - "type": { - "type": "Number" + id: 1, + name: 'userId', + type: { + type: 'Number', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "test/PtlSession/ResSession": { - "type": "Interface", - "extends": [ + 'test/PtlSession/ResSession': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseResponse" - } - } + id: 0, + type: { + type: 'Reference', + target: 'base/BaseResponse', + }, + }, ], - "properties": [ + properties: [ { - "id": 0, - "name": "count", - "type": { - "type": "Number" - } + id: 0, + name: 'count', + type: { + type: 'Number', + }, }, { - "id": 1, - "name": "before", - "type": { - "type": "Number" - } + id: 1, + name: 'before', + type: { + type: 'Number', + }, }, { - "id": 2, - "name": "userId", - "type": { - "type": "Number" + id: 2, + name: 'userId', + type: { + type: 'Number', }, - "optional": true - } - ] + optional: true, + }, + ], }, - "test/PtlThrottler/ReqThrottler": { - "type": "Interface", - "extends": [ + 'test/PtlThrottler/ReqThrottler': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseRequest" - } - } - ] + id: 0, + type: { + type: 'Reference', + target: 'base/BaseRequest', + }, + }, + ], }, - "test/PtlThrottler/ResThrottler": { - "type": "Interface", - "extends": [ + 'test/PtlThrottler/ResThrottler': { + type: 'Interface', + extends: [ { - "id": 0, - "type": { - "type": "Reference", - "target": "base/BaseResponse" - } - } - ] - } - } -}; \ No newline at end of file + id: 0, + type: { + type: 'Reference', + target: 'base/BaseResponse', + }, + }, + ], + }, + }, +} diff --git a/src/type.ts b/src/type.ts index 1193fc9..ee09c4e 100644 --- a/src/type.ts +++ b/src/type.ts @@ -34,6 +34,7 @@ declare module 'http' { rawQuery: any body: any rawBody: any + params: Record } export interface ServerResponse { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 35a6a6f..e69de29 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1 +0,0 @@ -import { authManager, QQProvider } from '../kernel/auth' diff --git a/yarn.lock b/yarn.lock index 98597fc..116c25b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3712,6 +3712,11 @@ rimraf@^2.6.1: dependencies: glob "^7.1.3" +route-recognizer@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3" + integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g== + run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"