From a2313ff7013cbd7279669557bcab9757730a92bc Mon Sep 17 00:00:00 2001 From: zhl Date: Mon, 12 Jun 2023 19:00:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84discord=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.server.ts | 208 +++++++++++++++----------- src/controllers/discord.controller.ts | 16 +- src/services/discord.svr.ts | 30 ++++ 3 files changed, 164 insertions(+), 90 deletions(-) diff --git a/src/api.server.ts b/src/api.server.ts index a63d059..5ceaf52 100644 --- a/src/api.server.ts +++ b/src/api.server.ts @@ -1,74 +1,89 @@ -import fastify, { FastifyError, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify' -import helmet from '@fastify/helmet' -import { IncomingMessage, Server, ServerResponse } from 'http' -import { RouterMap } from 'decorators/router' -import { mongoose } from '@typegoose/typegoose' -import logger from 'logger/logger' -import config from 'config/config' -import { ConnectOptions } from 'mongoose' +import fastify, { + FastifyError, + FastifyInstance, + FastifyReply, + FastifyRequest, +} from "fastify"; +import helmet from "@fastify/helmet"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { RouterMap } from "decorators/router"; +import { mongoose } from "@typegoose/typegoose"; +import logger from "logger/logger"; +import config from "config/config"; +import { ConnectOptions } from "mongoose"; +import { DiscordSvr } from "services/discord.svr"; -const zReqParserPlugin = require('plugins/zReqParser') +const zReqParserPlugin = require("plugins/zReqParser"); -const zTokenParserPlugin = require('plugins/zTokenParser') +const zTokenParserPlugin = require("plugins/zTokenParser"); -const apiAuthPlugin = require('plugins/apiauth') +const apiAuthPlugin = require("plugins/apiauth"); -const fs = require('fs') -const join = require('path').join +const fs = require("fs"); +const join = require("path").join; -require('./common/Extend') +require("./common/Extend"); export class ApiServer { - server: FastifyInstance + server: FastifyInstance; public constructor() { - this.server = fastify({ logger: true, trustProxy: true }) - this.registerPlugins() - console.log('version::' + process.version) + this.server = fastify({ logger: true, trustProxy: true }); + this.registerPlugins(); + console.log("version::" + process.version); } private registerPlugins() { - this.server.register(require('@fastify/formbody')) - this.server.register(zReqParserPlugin) - this.server.register(helmet, { hidePoweredBy: false, contentSecurityPolicy: false }) - this.server.register(zTokenParserPlugin) + this.server.register(require("@fastify/formbody")); + this.server.register(zReqParserPlugin); + this.server.register(helmet, { + hidePoweredBy: false, + contentSecurityPolicy: false, + }); + this.server.register(zTokenParserPlugin); this.server.register(apiAuthPlugin, { - secret: { private: config.api.token_secret_private, public: config.api.token_secret_public }, + secret: { + private: config.api.token_secret_private, + public: config.api.token_secret_public, + }, expiresIn: config.api.token_expiresIn, - }) - if (process.env.NODE_ENV !== 'production') { - this.server.register(require('@fastify/cors'), {}) + }); + if (process.env.NODE_ENV !== "production") { + this.server.register(require("@fastify/cors"), {}); } - this.server.register(require('@fastify/view'), { + this.server.register(require("@fastify/view"), { engine: { - ejs: require('ejs'), + ejs: require("ejs"), }, - }) + }); } private registerRouter() { - logger.log('register api routers') - let self = this + logger.log("register api routers"); + let self = this; for (let [controller, config] of RouterMap.decoratedRouters) { for (let data of config.data) { logger.info( - 'add router', - data.method || 'all', + "add router", + data.method || "all", data.path, - `${data.target.constructor.name}.${controller.name}()`, - ) + `${data.target.constructor.name}.${controller.name}()` + ); // @ts-ignore - self.server[data.method || 'all']( + self.server[data.method || "all"]( data.path, { - preValidation: async function (request: FastifyRequest, reply: FastifyReply) { - request.roles = config.roles - await this.apiAuth(request, reply) + preValidation: async function ( + request: FastifyRequest, + reply: FastifyReply + ) { + request.roles = config.roles; + await this.apiAuth(request, reply); }, }, - controller, - ) + controller + ); } } } @@ -76,56 +91,64 @@ export class ApiServer { * 加载所有的controller */ initControllers() { - logger.info('Bootstrap controllers...') - const controllers = join(__dirname, './controllers') + logger.info("Bootstrap controllers..."); + const controllers = join(__dirname, "./controllers"); fs.readdirSync(controllers) .filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/)) .forEach((file: any) => { // logger.log(file); - return require(join(controllers, file)) - }) + return require(join(controllers, file)); + }); } initSchedules() {} + initServcers() { + new DiscordSvr().init(); + } + async connectDB() { const options: ConnectOptions = { minPoolSize: 5, maxPoolSize: 10, keepAlive: true, keepAliveInitialDelay: 300000, - } - const uri = config.db_main - logger.info(`connect to ${uri} ...`) + }; + const uri = config.db_main; + logger.info(`connect to ${uri} ...`); try { // await mongoose.createConnection(uri, options) - await mongoose.connect(uri, options) - logger.log('DB Connected') + await mongoose.connect(uri, options); + logger.log("DB Connected"); } catch (err) { - logger.log(`DB Connection Error: ${err.message}`) + logger.log(`DB Connection Error: ${err.message}`); } } private setErrHandler() { this.server.setNotFoundHandler(function ( request: any, - reply: { send: (arg0: { errcode: number; errmsg: string }) => void }, + reply: { send: (arg0: { errcode: number; errmsg: string }) => void } ) { - reply.send({ errcode: 404, errmsg: 'page not found' }) - }) - this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) { - let statusCode = (error && error.statusCode) || 100 + reply.send({ errcode: 404, errmsg: "page not found" }); + }); + this.server.setErrorHandler(function ( + error: FastifyError, + request: FastifyRequest, + reply: FastifyReply + ) { + let statusCode = (error && error.statusCode) || 100; if (statusCode >= 500) { - logger.error(error) + logger.error(error); } else if (statusCode >= 400) { - logger.info(error) + logger.info(error); } else { - logger.error(error) + logger.error(error); } reply.code(200).send({ errcode: statusCode, - errmsg: error ? error.message : 'unknown error', - }) - }) + errmsg: error ? error.message : "unknown error", + }); + }); } /** * 格式化接口返回数据, 统一封装成如下格式 @@ -137,40 +160,47 @@ export class ApiServer { * @private */ private setFormatSend() { - this.server.addHook('preSerialization', async (request: FastifyRequest, reply: FastifyReply, payload) => { - reply.header('X-Powered-By', 'PHP/5.4.16') - // @ts-ignore - if (!payload.errcode) { + this.server.addHook( + "preSerialization", + async (request: FastifyRequest, reply: FastifyReply, payload) => { + reply.header("X-Powered-By", "PHP/5.4.16"); // @ts-ignore - if (payload.direct) { + if (!payload.errcode) { // @ts-ignore - delete payload.direct - return payload - } - payload = { - errcode: 0, - data: payload, + if (payload.direct) { + // @ts-ignore + delete payload.direct; + return payload; + } + payload = { + errcode: 0, + data: payload, + }; } + return payload; } - return payload - }) + ); } public async start() { - let self = this + let self = this; return new Promise(async (resolve, reject) => { - await self.connectDB() - self.initControllers() - self.registerRouter() - self.setErrHandler() - self.setFormatSend() - self.initSchedules() - this.server.listen({ port: config.api.port, host: config.api.host }, (err: any, address: any) => { - if (err) { - logger.log(err) - process.exit(0) + await self.connectDB(); + self.initControllers(); + self.registerRouter(); + self.setErrHandler(); + self.setFormatSend(); + self.initSchedules(); + self.initServcers(); + this.server.listen( + { port: config.api.port, host: config.api.host }, + (err: any, address: any) => { + if (err) { + logger.log(err); + process.exit(0); + } + resolve && resolve(address); } - resolve && resolve(address) - }) - }) + ); + }); } } diff --git a/src/controllers/discord.controller.ts b/src/controllers/discord.controller.ts index 6770a13..07edab8 100644 --- a/src/controllers/discord.controller.ts +++ b/src/controllers/discord.controller.ts @@ -2,7 +2,11 @@ import BaseController, { ROLE_ANON } from "common/base.controller"; import { ZError } from "common/ZError"; import { role, router } from "decorators/router"; import logger from "logger/logger"; -import { exchangeDiscrodCodeForToken, userInfo } from "services/discord.svr"; +import { + DiscordSvr, + exchangeDiscrodCodeForToken, + userInfo, +} from "services/discord.svr"; class DiscordController extends BaseController { @role(ROLE_ANON) @@ -14,9 +18,19 @@ class DiscordController extends BaseController { if (code) { access_token = await exchangeDiscrodCodeForToken(code); let uinfo = await userInfo(access_token); + console.log(uinfo); return res.view("/templates/discord_redirect.ejs"); } else { return res.view("/templates/discord_redirect.ejs"); } } + + @role(ROLE_ANON) + @router("get /discord/check_user_role") + async checkUserRole(req, res) { + // let { uid } = req.params; + let uid = "1034482894690861116"; + let role = await new DiscordSvr().checkUserRole(uid); + return { role }; + } } diff --git a/src/services/discord.svr.ts b/src/services/discord.svr.ts index 18617e4..d985f4d 100644 --- a/src/services/discord.svr.ts +++ b/src/services/discord.svr.ts @@ -1,3 +1,7 @@ +import { ZError } from "common/ZError"; +import { singleton } from "decorators/singleton"; +const { Client, Events, GatewayIntentBits } = require("discord.js"); + export async function exchangeDiscrodCodeForToken(code: string) { const clientId = process.env.DISCORD_CLIENT_ID; const clientSecret = process.env.DISCORD_CLIENT_SECRET; @@ -34,3 +38,29 @@ export async function userInfo(token: string) { console.log(data); return data; } + +@singleton +export class DiscordSvr { + private client: any; + private guild: any; + public async init() { + console.log("DiscordSvr init"); + this.client = new Client({ intents: [GatewayIntentBits.Guilds] }); + this.client.once(Events.ClientReady, async (c) => { + console.log(`Ready! Logged in as ${c.user.tag}`); + this.guild = await this.client.guilds.fetch(process.env.DISCROD_GUILD_ID); + }); + this.client.login(process.env.DISCORD_BOT_TOKEN); + } + + public async checkUserRole(uid: string) { + if (!this.guild) { + throw new ZError(10, "DiscordSvr not init"); + } + const member = await this.guild.members.fetch(uid); + if (!member) { + return false; + } + return member.roles.cache.has(process.env.DISCORD_ROLE_ID); + } +}