mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7557b71869 | ||
![]() |
d07187bd5d | ||
![]() |
2c6a6ba440 | ||
![]() |
4592bf7817 | ||
![]() |
afd6d450a0 | ||
![]() |
b134849dcf | ||
![]() |
e7d0f6d6da | ||
![]() |
16a29b0127 | ||
![]() |
1f5596ef16 | ||
![]() |
bef05432d0 | ||
![]() |
67533d7743 | ||
![]() |
0cc86c6348 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,14 +1,12 @@
|
|||||||
# Develop
|
# Develop
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
pnpm-lock.yaml
|
|
||||||
out/
|
out/
|
||||||
dist/
|
dist/
|
||||||
/src/core.lib/common/
|
/src/core.lib/common/
|
||||||
/localdebug/
|
/localdebug/
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
.idea/*
|
.idea/*
|
||||||
|
|
||||||
|
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"explorer.fileNesting.enabled": true,
|
||||||
|
"explorer.fileNesting.expand": false,
|
||||||
|
"explorer.fileNesting.patterns": {
|
||||||
|
".env.universal": ".env.*",
|
||||||
|
"tsconfig.json": "tsconfig.*.json, env.d.ts, vite.config.ts",
|
||||||
|
"package.json": "package-lock.json, eslint*, .prettier*, .editorconfig, manifest.json, logo.png, .gitignore, LICENSE"
|
||||||
|
}
|
||||||
|
}
|
@@ -32,7 +32,7 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
|||||||
|
|
||||||
[Server.Other](https://docs.napcat.cyou/)
|
[Server.Other](https://docs.napcat.cyou/)
|
||||||
|
|
||||||
[Qbot.News](https://neko.qbot.news)
|
[NapCat.Wiki](https://www.napcat.wiki)
|
||||||
|
|
||||||
## 回家旅途
|
## 回家旅途
|
||||||
[QQ Group#1](https://qm.qq.com/q/I6LU87a0Yq)
|
[QQ Group#1](https://qm.qq.com/q/I6LU87a0Yq)
|
||||||
@@ -46,7 +46,7 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
|||||||
## 性能设计/协议标准
|
## 性能设计/协议标准
|
||||||
NapCat 已实现90%+的 OneBot / GoCQ 标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
|
NapCat 已实现90%+的 OneBot / GoCQ 标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
|
||||||
|
|
||||||
由此设计带来一系列好处,在开发中,获取群员列表通常小于50Ms,单条文本消息发送在320Ms以内,在1k+的群聊流畅运行,同时带来一些副作用,上报数据中大量使用Magic生成字段,消息Id无法持久,无法上报撤回消息原始内容。
|
由此设计带来一系列好处,在开发中,获取群员列表通常小于50Ms,单条文本消息发送在320Ms以内,在1k+的群聊流畅运行,同时带来一些副作用,消息Id无法持久,无法上报撤回消息原始内容。
|
||||||
|
|
||||||
NapCat 在设计理念下遵守 OneBot 规范大多数要求并且积极改进,任何合理的标准化 Issue 与 Pr 将被接收。
|
NapCat 在设计理念下遵守 OneBot 规范大多数要求并且积极改进,任何合理的标准化 Issue 与 Pr 将被接收。
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.3.4",
|
"version": "4.3.7",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.3.4",
|
"version": "4.3.7",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||||
|
@@ -1,6 +1,72 @@
|
|||||||
import { Peer } from '@/core';
|
import { Peer } from '@/core';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
class TimeBasedCache<K, V> {
|
||||||
|
private cache = new Map<K, { value: V, timestamp: number, frequency: number }>();
|
||||||
|
private keyList = new Set<K>();
|
||||||
|
private operationCount = 0;
|
||||||
|
|
||||||
|
constructor(private maxCapacity: number, private ttl: number = 30 * 1000 * 60, private cleanupCount: number = 10) {}
|
||||||
|
|
||||||
|
public put(key: K, value: V): void {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const cacheEntry = { value, timestamp, frequency: 1 };
|
||||||
|
this.cache.set(key, cacheEntry);
|
||||||
|
this.keyList.add(key);
|
||||||
|
this.operationCount++;
|
||||||
|
if (this.keyList.size > this.maxCapacity) this.evict();
|
||||||
|
if (this.operationCount >= this.cleanupCount) this.cleanup(this.cleanupCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: K): V | undefined {
|
||||||
|
const entry = this.cache.get(key);
|
||||||
|
if (entry && Date.now() - entry.timestamp < this.ttl) {
|
||||||
|
entry.timestamp = Date.now();
|
||||||
|
entry.frequency++;
|
||||||
|
this.operationCount++;
|
||||||
|
if (this.operationCount >= this.cleanupCount) this.cleanup(this.cleanupCount);
|
||||||
|
return entry.value;
|
||||||
|
} else {
|
||||||
|
this.deleteKey(key);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private cleanup(count: number): void {
|
||||||
|
const currentTime = Date.now();
|
||||||
|
let cleaned = 0;
|
||||||
|
for (const key of this.keyList) {
|
||||||
|
if (cleaned >= count) break;
|
||||||
|
const entry = this.cache.get(key);
|
||||||
|
if (entry && currentTime - entry.timestamp >= this.ttl) {
|
||||||
|
this.deleteKey(key);
|
||||||
|
cleaned++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.operationCount = 0; // 重置操作计数器
|
||||||
|
}
|
||||||
|
|
||||||
|
private deleteKey(key: K): void {
|
||||||
|
this.cache.delete(key);
|
||||||
|
this.keyList.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private evict(): void {
|
||||||
|
while (this.keyList.size > this.maxCapacity) {
|
||||||
|
let oldestKey: K | undefined;
|
||||||
|
let minFrequency = Infinity;
|
||||||
|
for (const key of this.keyList) {
|
||||||
|
const entry = this.cache.get(key);
|
||||||
|
if (entry && entry.frequency < minFrequency) {
|
||||||
|
minFrequency = entry.frequency;
|
||||||
|
oldestKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldestKey !== undefined) this.deleteKey(oldestKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface FileUUIDData {
|
interface FileUUIDData {
|
||||||
peer: Peer;
|
peer: Peer;
|
||||||
modelId?: string;
|
modelId?: string;
|
||||||
@@ -10,49 +76,11 @@ interface FileUUIDData {
|
|||||||
fileUUID?: string;
|
fileUUID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeBasedCache<K, V> {
|
|
||||||
private cache: Map<K, { value: V, timestamp: number }>;
|
|
||||||
private ttl: number;
|
|
||||||
|
|
||||||
constructor(ttl: number) {
|
|
||||||
this.cache = new Map();
|
|
||||||
this.ttl = ttl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public put(key: K, value: V): void {
|
|
||||||
const timestamp = Date.now();
|
|
||||||
this.cache.set(key, { value, timestamp });
|
|
||||||
this.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: K): V | undefined {
|
|
||||||
const entry = this.cache.get(key);
|
|
||||||
if (entry) {
|
|
||||||
const currentTime = Date.now();
|
|
||||||
if (currentTime - entry.timestamp < this.ttl) {
|
|
||||||
return entry.value;
|
|
||||||
} else {
|
|
||||||
this.cache.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private cleanup(): void {
|
|
||||||
const currentTime = Date.now();
|
|
||||||
for (const [key, entry] of this.cache.entries()) {
|
|
||||||
if (currentTime - entry.timestamp >= this.ttl) {
|
|
||||||
this.cache.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FileUUIDManager {
|
class FileUUIDManager {
|
||||||
private cache: TimeBasedCache<string, FileUUIDData>;
|
private cache: TimeBasedCache<string, FileUUIDData>;
|
||||||
|
|
||||||
constructor(ttl: number) {
|
constructor(ttl: number) {
|
||||||
this.cache = new TimeBasedCache<string, FileUUIDData>(ttl);
|
this.cache = new TimeBasedCache<string, FileUUIDData>(5000, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public encode(data: FileUUIDData, endString: string = "", customUUID?: string): string {
|
public encode(data: FileUUIDData, endString: string = "", customUUID?: string): string {
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.3.4';
|
export const napCatVersion = '4.3.7';
|
||||||
|
@@ -462,7 +462,7 @@ export class NTQQFileApi {
|
|||||||
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
||||||
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.logError('获取rkey失败 Fallback Old Mode', e);
|
this.context.logger.logDebug('获取rkey失败 Fallback Old Mode', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,6 +15,10 @@ export class RkeyManager {
|
|||||||
private_rkey: '',
|
private_rkey: '',
|
||||||
expired_time: 0,
|
expired_time: 0,
|
||||||
};
|
};
|
||||||
|
private failureCount: number = 0;
|
||||||
|
private lastFailureTimestamp: number = 0;
|
||||||
|
private readonly FAILURE_LIMIT: number = 8;
|
||||||
|
private readonly ONE_DAY: number = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
constructor(serverUrl: string[], logger: LogWrapper) {
|
constructor(serverUrl: string[], logger: LogWrapper) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -22,11 +26,21 @@ export class RkeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getRkey() {
|
async getRkey() {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
if (now - this.lastFailureTimestamp > this.ONE_DAY) {
|
||||||
|
this.failureCount = 0; // 重置失败计数器
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.failureCount >= this.FAILURE_LIMIT) {
|
||||||
|
this.logger.logError(`[Rkey] 服务存在异常, 图片使用FallBack机制`);
|
||||||
|
throw new Error('获取rkey失败次数过多,请稍后再试');
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isExpired()) {
|
if (this.isExpired()) {
|
||||||
try {
|
try {
|
||||||
await this.refreshRkey();
|
await this.refreshRkey();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
throw new Error(`${e}`);//外抛
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.rkeyData;
|
return this.rkeyData;
|
||||||
@@ -34,7 +48,6 @@ export class RkeyManager {
|
|||||||
|
|
||||||
isExpired(): boolean {
|
isExpired(): boolean {
|
||||||
const now = new Date().getTime() / 1000;
|
const now = new Date().getTime() / 1000;
|
||||||
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`);
|
|
||||||
return now > this.rkeyData.expired_time;
|
return now > this.rkeyData.expired_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,14 +61,17 @@ export class RkeyManager {
|
|||||||
private_rkey: temp.private_rkey.slice(6),
|
private_rkey: temp.private_rkey.slice(6),
|
||||||
expired_time: temp.expired_time
|
expired_time: temp.expired_time
|
||||||
};
|
};
|
||||||
|
this.failureCount = 0;
|
||||||
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.logError(`[Rkey] Get Rkey ${url} Error `, e);
|
this.logger.logError(`[Rkey] 异常服务 ${url} 异常 / `, e);
|
||||||
|
this.failureCount++;
|
||||||
|
this.lastFailureTimestamp = new Date().getTime();
|
||||||
//是否为最后一个url
|
//是否为最后一个url
|
||||||
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
||||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -18,7 +18,7 @@ export interface BuddyCategoryType {
|
|||||||
export interface CoreInfo {
|
export interface CoreInfo {
|
||||||
uid: string;
|
uid: string;
|
||||||
uin: string;
|
uin: string;
|
||||||
nick: string;
|
nick?: string;
|
||||||
remark: string;
|
remark: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
import '@/universal/napcat';
|
@@ -20,7 +20,7 @@ import {
|
|||||||
GroupNotify,
|
GroupNotify,
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
import faceConfig from '@/core/external/face_config.json';
|
import faceConfig from '@/core/external/face_config.json';
|
||||||
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, OB11MessageForward, } from '@/onebot';
|
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, OB11MessageForward, OB11MessageImage, OB11MessageVideo, } from '@/onebot';
|
||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { EventType } from '@/onebot/event/OneBotEvent';
|
import { EventType } from '@/onebot/event/OneBotEvent';
|
||||||
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
||||||
@@ -906,16 +906,16 @@ export class OneBotMsgApi {
|
|||||||
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
|
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
|
||||||
const sizePromises = elements.map(async element => {
|
const sizePromises = elements.map(async element => {
|
||||||
switch (element.elementType) {
|
switch (element.elementType) {
|
||||||
case ElementType.PTT:
|
case ElementType.PTT:
|
||||||
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
||||||
case ElementType.FILE:
|
case ElementType.FILE:
|
||||||
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
||||||
case ElementType.VIDEO:
|
case ElementType.VIDEO:
|
||||||
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
||||||
case ElementType.PIC:
|
case ElementType.PIC:
|
||||||
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const sizes = await Promise.all(sizePromises);
|
const sizes = await Promise.all(sizePromises);
|
||||||
@@ -956,40 +956,66 @@ export class OneBotMsgApi {
|
|||||||
|
|
||||||
private async handleOb11FileLikeMessage(
|
private async handleOb11FileLikeMessage(
|
||||||
{ data: inputdata }: OB11MessageFileBase,
|
{ data: inputdata }: OB11MessageFileBase,
|
||||||
{ deleteAfterSentFiles }: SendMessageContext,
|
{ deleteAfterSentFiles }: SendMessageContext
|
||||||
) {
|
) {
|
||||||
const realUri = inputdata.url ?? inputdata.file ?? inputdata.path ?? '';
|
let realUri = [inputdata.url, inputdata.file, inputdata.path].find(uri => uri && uri.trim()) ?? '';
|
||||||
if (realUri.length === 0) {
|
if (!realUri) {
|
||||||
this.core.context.logger.logError('文件消息缺少参数', inputdata);
|
this.core.context.logger.logError('文件消息缺少参数', inputdata);
|
||||||
throw Error('文件消息缺少参数');
|
throw new Error('文件消息缺少参数');
|
||||||
}
|
|
||||||
const {
|
|
||||||
path,
|
|
||||||
fileName,
|
|
||||||
errMsg,
|
|
||||||
success,
|
|
||||||
} = (await uriToLocalFile(this.core.NapCatTempPath, realUri));
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
this.core.context.logger.logError('文件下载失败', errMsg);
|
|
||||||
throw Error('文件下载失败' + errMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAfterSentFiles.push(path);
|
const downloadFile = async (uri: string) => {
|
||||||
|
const { path, fileName, errMsg, success } = await uriToLocalFile(this.core.NapCatTempPath, uri);
|
||||||
return { path, fileName: inputdata.name ?? fileName };
|
if (!success) {
|
||||||
|
this.core.context.logger.logError('文件下载失败', errMsg);
|
||||||
|
throw new Error('文件下载失败: ' + errMsg);
|
||||||
|
}
|
||||||
|
return { path, fileName };
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const { path, fileName } = await downloadFile(realUri);
|
||||||
|
deleteAfterSentFiles.push(path);
|
||||||
|
return { path, fileName: inputdata.name ?? fileName };
|
||||||
|
} catch {
|
||||||
|
realUri = await this.handleObfuckName(realUri);
|
||||||
|
const { path, fileName } = await downloadFile(realUri);
|
||||||
|
deleteAfterSentFiles.push(path);
|
||||||
|
return { path, fileName: inputdata.name ?? fileName };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async handleObfuckName(name: string) {
|
||||||
|
const contextMsgFile = FileNapCatOneBotUUID.decode(name);
|
||||||
|
if (contextMsgFile && contextMsgFile.msgId && contextMsgFile.elementId) {
|
||||||
|
const { peer, msgId, elementId } = contextMsgFile;
|
||||||
|
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList.find(msg => msg.msgId === msgId);
|
||||||
|
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
|
||||||
|
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||||
|
if (!mixElementInner) throw new Error('element not found');
|
||||||
|
let url = '';
|
||||||
|
if (mixElement?.picElement && rawMessage) {
|
||||||
|
const tempData =
|
||||||
|
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageImage | undefined;
|
||||||
|
url = tempData?.data.url ?? '';
|
||||||
|
}
|
||||||
|
if (mixElement?.videoElement && rawMessage) {
|
||||||
|
const tempData =
|
||||||
|
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageVideo | undefined;
|
||||||
|
url = tempData?.data.url ?? '';
|
||||||
|
}
|
||||||
|
return url !== '' ? url : await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
||||||
|
}
|
||||||
|
throw new Error('文件名解析失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 130:
|
case 130:
|
||||||
return 'leave';
|
return 'leave';
|
||||||
case 131:
|
case 131:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
case 3:
|
case 3:
|
||||||
return 'kick_me';
|
return 'kick_me';
|
||||||
default:
|
default:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -139,13 +139,14 @@ export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const mergeNetworkDefaultConfig = {
|
export const mergeNetworkDefaultConfig = {
|
||||||
|
httpSseServers: httpSseServerDefaultConfigs,
|
||||||
httpServers: httpServerDefaultConfigs,
|
httpServers: httpServerDefaultConfigs,
|
||||||
httpClients: httpClientDefaultConfigs,
|
httpClients: httpClientDefaultConfigs,
|
||||||
websocketServers: websocketServerDefaultConfigs,
|
websocketServers: websocketServerDefaultConfigs,
|
||||||
websocketClients: websocketClientDefaultConfigs,
|
websocketClients: websocketClientDefaultConfigs,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type NetworkConfigAdapter = HttpServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig;
|
export type NetworkConfigAdapter = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig;
|
||||||
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig;
|
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig;
|
||||||
|
|
||||||
export function mergeOneBotConfigs(
|
export function mergeOneBotConfigs(
|
||||||
|
@@ -23,7 +23,7 @@ export class OB11Construct {
|
|||||||
...rawFriend.baseInfo,
|
...rawFriend.baseInfo,
|
||||||
...rawFriend.coreInfo,
|
...rawFriend.coreInfo,
|
||||||
user_id: parseInt(rawFriend.coreInfo.uin),
|
user_id: parseInt(rawFriend.coreInfo.uin),
|
||||||
nickname: rawFriend.coreInfo.nick,
|
nickname: rawFriend.coreInfo.nick ?? "",
|
||||||
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
||||||
sex: this.sex(rawFriend.baseInfo.sex),
|
sex: this.sex(rawFriend.baseInfo.sex),
|
||||||
level: 0,
|
level: 0,
|
||||||
|
6
src/universal/LiteLoader.d.ts
vendored
Normal file
6
src/universal/LiteLoader.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
declare global {
|
||||||
|
namespace globalThis {
|
||||||
|
var LiteLoader: Symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {}
|
@@ -1,7 +1,6 @@
|
|||||||
import { NCoreInitShell } from "@/shell/base";
|
import { NCoreInitShell } from "@/shell/base";
|
||||||
|
|
||||||
export * from "@/framework/napcat";
|
export * from "@/framework/napcat";
|
||||||
export * from "@/shell/base";
|
export * from "@/shell/base";
|
||||||
if ((global as any).LiteLoader == undefined) {
|
if (global.LiteLoader == undefined) {
|
||||||
NCoreInitShell();
|
NCoreInitShell();
|
||||||
}
|
}
|
Reference in New Issue
Block a user