diff --git a/external/LiteLoaderWrapper.zip b/external/LiteLoaderWrapper.zip index 1cca691c..000f0b37 100644 Binary files a/external/LiteLoaderWrapper.zip and b/external/LiteLoaderWrapper.zip differ diff --git a/manifest.json b/manifest.json index df5397bc..02ccb129 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "NapCatQQ", "slug": "NapCat.Framework", "description": "高性能的 OneBot 11 协议实现", - "version": "4.1.18", + "version": "4.1.21", "icon": "./logo.png", "authors": [ { diff --git a/napcat.webui/src/backend/shell.ts b/napcat.webui/src/backend/shell.ts index efc7f013..0819e0b8 100644 --- a/napcat.webui/src/backend/shell.ts +++ b/napcat.webui/src/backend/shell.ts @@ -74,6 +74,26 @@ export class QQLoginManager { } return false; } + public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string, isLogin: string } | undefined> { + try { + const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, { + method: 'POST', + headers: { + Authorization: 'Bearer ' + this.retCredential, + 'Content-Type': 'application/json', + }, + }); + if (QQLoginResponse.status == 200) { + const QQLoginResponseJson = await QQLoginResponse.json(); + if (QQLoginResponseJson.code == 0) { + return QQLoginResponseJson.data; + } + } + } catch (error) { + console.error('Error checking QQ login status:', error); + } + return undefined; + } public async checkWebUiLogined(): Promise { try { diff --git a/napcat.webui/src/components/QQLogin.vue b/napcat.webui/src/components/QQLogin.vue index f554b474..b9e59ca9 100644 --- a/napcat.webui/src/components/QQLogin.vue +++ b/napcat.webui/src/components/QQLogin.vue @@ -54,7 +54,7 @@ const selectedAccount = ref(''); const qrcodeCanvas = ref(null); const qqLoginManager = new QQLoginManager(localStorage.getItem('auth') || ''); let heartBeatTimer: number | null = null; - +let qrcodeUrl: string = ''; const selectAccount = async (accountName: string): Promise => { const { result, errMsg } = await qqLoginManager.setQuickLogin(accountName); if (result) { @@ -80,19 +80,26 @@ const generateQrCode = (data: string, canvas: HTMLCanvasElement | null): void => }; const HeartBeat = async (): Promise => { - const isLogined = await qqLoginManager.checkQQLoginStatus(); - if (isLogined) { + const isLogined = await qqLoginManager.checkQQLoginStatusWithQrcode(); + if (isLogined?.isLogin) { if (heartBeatTimer) { clearInterval(heartBeatTimer); } + //判断是否已经调转 + if (router.currentRoute.value.path !== '/dashboard/basic-info') { + return; + } await router.push({ path: '/dashboard/basic-info' }); + } else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) { + qrcodeUrl = isLogined.qrcodeurl; + generateQrCode(qrcodeUrl, qrcodeCanvas.value); } }; const InitPages = async (): Promise => { quickLoginList.value = await qqLoginManager.getQQQuickLoginList(); - const qrcodeData = await qqLoginManager.getQQLoginQrcode(); - generateQrCode(qrcodeData, qrcodeCanvas.value); + qrcodeUrl = await qqLoginManager.getQQLoginQrcode(); + generateQrCode(qrcodeUrl, qrcodeCanvas.value); heartBeatTimer = window.setInterval(HeartBeat, 3000); }; diff --git a/package.json b/package.json index b4f5ac4a..ab194dca 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "napcat", "private": true, "type": "module", - "version": "4.1.18", + "version": "4.1.21", "scripts": { "build:framework": "npm run build:webui && vite build --mode framework || exit 1", "build:shell": "npm run build:webui && vite build --mode shell || exit 1", diff --git a/src/common/version.ts b/src/common/version.ts index 393551b6..7ad19fa9 100644 --- a/src/common/version.ts +++ b/src/common/version.ts @@ -1 +1 @@ -export const napCatVersion = '4.1.18'; +export const napCatVersion = '4.1.21'; diff --git a/src/core/apis/file.ts b/src/core/apis/file.ts index 4b54f8e5..f5e9f52c 100644 --- a/src/core/apis/file.ts +++ b/src/core/apis/file.ts @@ -26,7 +26,7 @@ import pathLib from 'node:path'; import { defaultVideoThumbB64, getVideoInfo } from '@/common/video'; import ffmpeg from 'fluent-ffmpeg'; import { encodeSilk } from '@/common/audio'; -import { MessageContext } from '@/onebot/api'; +import { SendMessageContext } from '@/onebot/api'; import { getFileTypeForSendType } from '../helper/msg'; export class NTQQFileApi { @@ -91,7 +91,7 @@ export class NTQQFileApi { }; } - async createValidSendFileElement(context: MessageContext, filePath: string, fileName: string = '', folderId: string = '',): Promise { + async createValidSendFileElement(context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = '',): Promise { const { fileName: _fileName, path, @@ -113,7 +113,7 @@ export class NTQQFileApi { }; } - async createValidSendPicElement(context: MessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise { + async createValidSendPicElement(context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise { const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType); if (fileSize === 0) { throw new Error('文件异常,大小为0'); @@ -141,7 +141,7 @@ export class NTQQFileApi { }; } - async createValidSendVideoElement(context: MessageContext, filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise { + async createValidSendVideoElement(context: SendMessageContext, filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise { const logger = this.core.context.logger; let videoInfo = { width: 1920, diff --git a/src/core/types/msg.ts b/src/core/types/msg.ts index bc310f74..c068f2e0 100644 --- a/src/core/types/msg.ts +++ b/src/core/types/msg.ts @@ -383,12 +383,39 @@ export enum MemberAddShowType { K_YOU_INVITE_OTHER = 7, } +/** + * 群提示元素成员角色枚举 + */ +export enum NTGroupGrayElementRole { + KOTHER = 0, + KMEMBER = 1, + KADMIN = 2 +} + +/** + * 群灰色提示成员接口 + * */ + +export interface NTGroupGrayMember { + serialVersionUID: string; + uid: string; + name: string; +} +/** + * 群灰色提示邀请者和被邀请者接口 + * + * */ +export interface NTGroupGrayInviterAndInvite { + invited: NTGroupGrayMember; + inviter: NTGroupGrayMember; + serialVersionUID: string; +} /** * 群提示元素接口 */ export interface TipGroupElement { type: TipGroupElementType; - role: 0; + role: NTGroupGrayElementRole; groupName: string; memberUid: string; memberNick: string; @@ -399,13 +426,13 @@ export interface TipGroupElement { createGroup: null; memberAdd?: { showType: MemberAddShowType; - otherAdd: null; - otherAddByOtherQRCode: null; - otherAddByYourQRCode: null; - youAddByOtherQRCode: null; - otherInviteOther: null; - otherInviteYou: null; - youInviteOther: null + otherAdd: NTGroupGrayMember; + otherAddByOtherQRCode: NTGroupGrayInviterAndInvite; + otherAddByYourQRCode: NTGroupGrayMember; + youAddByOtherQRCode: NTGroupGrayMember; + otherInviteOther: NTGroupGrayInviterAndInvite; + otherInviteYou: NTGroupGrayMember; + youInviteOther: NTGroupGrayMember; }; shutUp?: { curTime: string; diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 9418a203..a1a771e0 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -113,6 +113,7 @@ export class OneBotMsgApi { return { type: OB11MessageDataType.image, data: { + pic_type: element.picType, summary: element.summary, file: encodedFileId, sub_type: element.picSubType, diff --git a/src/onebot/index.ts b/src/onebot/index.ts index cc0cf24d..0eb5bdfc 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -176,67 +176,48 @@ export class NapCatOneBot11Adapter { }; } - private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig) { + private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig): Promise { const prevLog = await this.creatOneBotLog(prev); const newLog = await this.creatOneBotLog(now); this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`); this.context.logger.log(`[Notice] [OneBot11] 配置变更后:\n${newLog}`); - const { added: addedHttpServers, removed: removedHttpServers } = this.findDifference(prev.network.httpServers, now.network.httpServers); - const { added: addedHttpClients, removed: removedHttpClients } = this.findDifference(prev.network.httpClients, now.network.httpClients); - const { added: addedWebSocketServers, removed: removedWebSocketServers } = this.findDifference(prev.network.websocketServers, now.network.websocketServers); - const { added: addedWebSocketClients, removed: removedWebSocketClients } = this.findDifference(prev.network.websocketClients, now.network.websocketClients); - - await this.handleRemovedAdapters(removedHttpServers); - await this.handleRemovedAdapters(removedHttpClients); - await this.handleRemovedAdapters(removedWebSocketServers); - await this.handleRemovedAdapters(removedWebSocketClients); - - await this.handlerConfigChange(now.network.httpServers); - await this.handlerConfigChange(now.network.httpClients); - await this.handlerConfigChange(now.network.websocketServers); - await this.handlerConfigChange(now.network.websocketClients); - - await this.handleAddedAdapters(addedHttpServers, OB11PassiveHttpAdapter); - await this.handleAddedAdapters(addedHttpClients, OB11ActiveHttpAdapter); - await this.handleAddedAdapters(addedWebSocketServers, OB11PassiveWebSocketAdapter); - await this.handleAddedAdapters(addedWebSocketClients, OB11ActiveWebSocketAdapter); + await this.handleConfigChange(prev.network.httpServers, now.network.httpServers, OB11PassiveHttpAdapter); + await this.handleConfigChange(prev.network.httpClients, now.network.httpClients, OB11ActiveHttpAdapter); + await this.handleConfigChange(prev.network.websocketServers, now.network.websocketServers, OB11PassiveWebSocketAdapter); + await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11ActiveWebSocketAdapter); } - private async handlerConfigChange(adapters: Array) { - for (const adapterConfig of adapters) { + private async handleConfigChange( + prevConfig: NetworkConfigAdapter[], + nowConfig: NetworkConfigAdapter[], + adapterClass: new (...args: any[]) => IOB11NetworkAdapter + ): Promise { + // 通知新配置重载 删除关闭的 加入新开的 + for (const adapterConfig of nowConfig) { const existingAdapter = this.networkManager.findSomeAdapter(adapterConfig.name); if (existingAdapter) { const networkChange = await existingAdapter.reload(adapterConfig); if (networkChange === OB11NetworkReloadType.NetWorkClose) { - this.networkManager.closeSomeAdapters([existingAdapter]); - + await this.networkManager.closeSomeAdaterWhenOpen([existingAdapter]); + } + } else { + const newAdapter = new adapterClass(adapterConfig.name, adapterConfig, this.core, this.actions); + await this.networkManager.registerAdapterAndOpen(newAdapter); + } + } + // 比较旧的找不到的回收 + for (const adapterConfig of prevConfig) { + const existingAdapter = nowConfig.find((e) => e.name === adapterConfig.name); + if (!existingAdapter) { + const existingAdapter = this.networkManager.findSomeAdapter(adapterConfig.name); + if (existingAdapter) { + await this.networkManager.closeSomeAdaterWhenOpen([existingAdapter]); } } } } - private async handleRemovedAdapters(adapters: Array<{ name: string }>): Promise { - for (const adapter of adapters) { - await this.networkManager.closeAdapterByPredicate((existingAdapter) => existingAdapter.name === adapter.name); - } - } - - private async handleAddedAdapters IOB11NetworkAdapter>(addedAdapters: Array, AdapterClass: T) { - for (const adapter of addedAdapters) { - if (adapter.enable) { - const newAdapter = new AdapterClass(adapter.name, adapter, this.core, this.actions); - await newAdapter.open(); - this.networkManager.registerAdapter(newAdapter); - } - } - } - private findDifference(prev: T[], now: T[]): { added: T[]; removed: T[] } { - const added = now.filter((item) => !prev.includes(item)); - const removed = prev.filter((item) => !now.includes(item)); - return { added, removed }; - } - private initMsgListener() { const msgListener = new NodeIKernelMsgListener(); msgListener.onRecvSysMsg = (msg) => { diff --git a/src/onebot/network/index.ts b/src/onebot/network/index.ts index d7f46c59..5663f241 100644 --- a/src/onebot/network/index.ts +++ b/src/onebot/network/index.ts @@ -68,6 +68,14 @@ export class OB11NetworkManager { await adapter.close(); } } + async closeSomeAdaterWhenOpen(adaptersToClose: IOB11NetworkAdapter[]) { + for (const adapter of adaptersToClose) { + this.adapters.delete(adapter.name); + if(adapter.isEnable){ + await adapter.close(); + } + } + } findSomeAdapter(name: string) { return this.adapters.get(name); diff --git a/src/onebot/network/passive-websocket.ts b/src/onebot/network/passive-websocket.ts index cb7d89fe..836f881f 100644 --- a/src/onebot/network/passive-websocket.ts +++ b/src/onebot/network/passive-websocket.ts @@ -31,13 +31,9 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter { ) { this.config = structuredClone(config); this.logger = core.context.logger; - if (this.config.host === '0.0.0.0') { - //兼容配置同时处理0.0.0.0逻辑 - this.config.host = ''; - } this.wsServer = new WebSocketServer({ port: this.config.port, - host: this.config.host, + host: this.config.host === '0.0.0.0' ? '' : this.config.host, maxPayload: 1024 * 1024 * 1024, }); this.wsServer.on('connection', async (wsClient, wsReq) => { diff --git a/src/webui/src/api/QQLogin.ts b/src/webui/src/api/QQLogin.ts index b2d17f00..ba78451f 100644 --- a/src/webui/src/api/QQLogin.ts +++ b/src/webui/src/api/QQLogin.ts @@ -33,6 +33,7 @@ export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => { message: 'success', data: { isLogin: await WebUiDataRuntime.getQQLoginStatus(), + qrcodeurl: await WebUiDataRuntime.getQQLoginQrcodeURL() }, }); };