refactor: webui network

This commit is contained in:
pk5ls20
2024-11-16 05:43:44 +08:00
parent fa87f7c8c3
commit c432799580
11 changed files with 456 additions and 414 deletions

View File

@@ -1,3 +1,5 @@
import { OneBotConfig } from '../../../src/onebot/config/config';
export class QQLoginManager { export class QQLoginManager {
private retCredential: string; private retCredential: string;
private readonly apiPrefix: string; private readonly apiPrefix: string;
@@ -9,7 +11,7 @@ export class QQLoginManager {
} }
// TODO: // TODO:
public async GetOB11Config(): Promise<any> { public async GetOB11Config(): Promise<OneBotConfig> {
try { try {
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, { const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, {
method: 'POST', method: 'POST',
@@ -21,16 +23,16 @@ export class QQLoginManager {
if (ConfigResponse.status == 200) { if (ConfigResponse.status == 200) {
const ConfigResponseJson = await ConfigResponse.json(); const ConfigResponseJson = await ConfigResponse.json();
if (ConfigResponseJson.code == 0) { if (ConfigResponseJson.code == 0) {
return ConfigResponseJson?.data; return ConfigResponseJson?.data as OneBotConfig;
} }
} }
} catch (error) { } catch (error) {
console.error('Error getting OB11 config:', error); console.error('Error getting OB11 config:', error);
} }
return {}; return {} as OneBotConfig;
} }
public async SetOB11Config(config: any): Promise<boolean> { public async SetOB11Config(config: OneBotConfig): Promise<boolean> {
try { try {
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, { const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, {
method: 'POST', method: 'POST',

View File

@@ -1,70 +1,104 @@
<template> <template>
<t-space> <t-space>
<t-tabs v-model="value" :addable="true" theme="card" @add="showAddTabDialog" @remove="removeTab"> <t-tabs v-model="activeTab" :addable="true" theme="card" @add="showAddTabDialog" @remove="removeTab">
<t-tab-panel <t-tab-panel
v-for="data in panelData" v-for="(config, idx) in clientPanelData"
:key="data.value" :key="idx"
:label="data.label" :label="config.name"
:removable="data.removable" :removable="true"
:value="data.value" :value="idx"
> >
<component :is="data.component" :config="data.config" /> <component :is="resolveDynamicComponent(getComponent(config.key))" :config="config.data" />
<t-button @click="saveConfig">保存</t-button>
</t-tab-panel> </t-tab-panel>
</t-tabs> </t-tabs>
<t-dialog
v-model:visible="isDialogVisible"
header="添加新选项卡"
@close="isDialogVisible = false"
@confirm="addTab"
>
<t-form ref="form" :model="newTab">
<t-form-item :rules="[{ required: true, message: '请输入名称' }]" label="名称" name="name">
<t-input v-model="newTab.name" />
</t-form-item>
<t-form-item :rules="[{ required: true, message: '请选择类型' }]" label="类型" name="type">
<t-select v-model="newTab.type">
<t-option value="httpServers">HTTP 服务器</t-option>
<t-option value="httpClients">HTTP 客户端</t-option>
<t-option value="websocketServers">WebSocket 服务器</t-option>
<t-option value="websocketClients">WebSocket 客户端</t-option>
</t-select>
</t-form-item>
</t-form>
</t-dialog>
</t-space> </t-space>
<t-dialog
v-model:visible="isDialogVisible"
header="添加新选项卡"
@close="isDialogVisible = false"
@confirm="addTab"
>
<t-form ref="form" :model="newTab">
<t-form-item :rules="[{ required: true, message: '请输入名称' }]" label="名称" name="name">
<t-input v-model="newTab.name" />
</t-form-item>
<t-form-item :rules="[{ required: true, message: '请选择类型' }]" label="类型" name="type">
<t-select v-model="newTab.type">
<t-option value="httpServers">HTTP 服务器</t-option>
<t-option value="httpClients">HTTP 客户端</t-option>
<t-option value="websocketServers">WebSocket 服务器</t-option>
<t-option value="websocketClients">WebSocket 客户端</t-option>
</t-select>
</t-form-item>
</t-form>
</t-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue'; import { ref, resolveDynamicComponent, nextTick, Ref, onMounted, reactive, Reactive } from 'vue';
import { defaultOnebotConfig, mergeOnebotConfigs } from '../../../src/onebot/config/config'; import {
httpServerDefaultConfigs,
httpClientDefaultConfigs,
websocketServerDefaultConfigs,
websocketClientDefaultConfigs,
HttpClientConfig,
HttpServerConfig,
WebsocketClientConfig,
WebsocketServerConfig,
NetworkConfig,
OneBotConfig,
defaultOneBotConfigs,
mergeOneBotConfigs,
} from '../../../src/onebot/config/config';
import { QQLoginManager } from '@/backend/shell'; import { QQLoginManager } from '@/backend/shell';
import HttpServerComponent from './network/HttpServerComponent.vue'; import HttpServerComponent from '@/pages/network/HttpServerComponent.vue';
import HttpClientComponent from './network/HttpClientComponent.vue'; import HttpClientComponent from '@/pages/network/HttpClientComponent.vue';
import WebsocketServerComponent from './network/WebsocketServerComponent.vue'; import WebsocketServerComponent from '@/pages/network/WebsocketServerComponent.vue';
import WebsocketClientComponent from './network/WebsocketClientComponent.vue'; import WebsocketClientComponent from '@/pages/network/WebsocketClientComponent.vue';
interface PanelData { type ConfigKey = 'httpServers' | 'httpClients' | 'websocketServers' | 'websocketClients';
value: string;
label: string;
removable: boolean;
component: any;
config: { name: string };
}
let id = 0; type ConfigUnion = HttpClientConfig | HttpServerConfig | WebsocketServerConfig | WebsocketClientConfig;
const value = ref<string>('first');
const panelData = ref<PanelData[]>([]);
const isDialogVisible = ref<boolean>(false);
const newTab = ref<{ name: string; type: string }>({ name: '', type: '' });
const componentMap: Record<string, any> = { const defaultConfigs: Record<ConfigKey, ConfigUnion> = {
httpServers: shallowRef(HttpServerComponent), httpServers: httpServerDefaultConfigs,
httpClients: shallowRef(HttpClientComponent), httpClients: httpClientDefaultConfigs,
websocketServers: shallowRef(WebsocketServerComponent), websocketServers: websocketServerDefaultConfigs,
websocketClients: shallowRef(WebsocketClientComponent), websocketClients: websocketClientDefaultConfigs,
}; };
const getOB11Config = async (): Promise<any | undefined> => { const componentMap: Record<
ConfigKey,
| typeof HttpServerComponent
| typeof HttpClientComponent
| typeof WebsocketServerComponent
| typeof WebsocketClientComponent
> = {
httpServers: HttpServerComponent,
httpClients: HttpClientComponent,
websocketServers: WebsocketServerComponent,
websocketClients: WebsocketClientComponent,
};
interface ClientPanel {
name: string;
key: ConfigKey;
data: Ref<ConfigUnion>;
}
type ComponentKey = keyof typeof componentMap;
const activeTab = ref<number>(0);
const isDialogVisible = ref(false);
const newTab = ref<{ name: string; type: ComponentKey }>({ name: '', type: 'httpServers' });
const clientPanelData: Reactive<Array<ClientPanel>> = reactive([]);
const getComponent = (type: ComponentKey) => {
return componentMap[type];
};
const getOB11Config = async (): Promise<OneBotConfig | undefined> => {
const storedCredential = localStorage.getItem('auth'); const storedCredential = localStorage.getItem('auth');
if (!storedCredential) { if (!storedCredential) {
console.error('No stored credential found'); console.error('No stored credential found');
@@ -74,7 +108,7 @@ const getOB11Config = async (): Promise<any | undefined> => {
return await loginManager.GetOB11Config(); return await loginManager.GetOB11Config();
}; };
const setOB11Config = async (config: any): Promise<boolean> => { const setOB11Config = async (config: OneBotConfig): Promise<boolean> => {
const storedCredential = localStorage.getItem('auth'); const storedCredential = localStorage.getItem('auth');
if (!storedCredential) { if (!storedCredential) {
console.error('No stored credential found'); console.error('No stored credential found');
@@ -84,100 +118,74 @@ const setOB11Config = async (config: any): Promise<boolean> => {
return await loginManager.SetOB11Config(config); return await loginManager.SetOB11Config(config);
}; };
const log = (message: string, data: any) => { const addToPanel = <T extends ConfigUnion>(configs: T[], key: ConfigKey) => {
console.log(message, data); configs.forEach((config) => clientPanelData.push({ name: config.name, data: config, key: key }));
}; };
const createPanel = (type: string, name: string, id: number): PanelData => { const addConfigDataToPanel = (data: NetworkConfig) => {
return { Object.entries(data).forEach(([key, configs]) => {
value: `${type}-${id}`, if (key in defaultConfigs) {
label: name, addToPanel(configs as ConfigUnion[], key as ConfigKey);
removable: true, }
component: componentMap[type],
config: { name: name },
};
};
const generatePanels = (networkConfig: any): PanelData[] => {
const panels: PanelData[] = [];
Object.keys(networkConfig).forEach((key) => {
networkConfig[key].forEach((config: any, index: number) => {
const component = componentMap[key];
if (!component) {
console.error(`No component found for key: ${key}`);
return;
}
panels.push(createPanel(key, config.name, index));
});
}); });
return panels; };
const parsePanelData = (): NetworkConfig => {
return {
websocketClients: clientPanelData
.filter((panel) => panel.key === 'websocketClients')
.map((panel) => panel.data as WebsocketClientConfig),
websocketServers: clientPanelData
.filter((panel) => panel.key === 'websocketServers')
.map((panel) => panel.data as WebsocketServerConfig),
httpClients: clientPanelData
.filter((panel) => panel.key === 'httpClients')
.map((panel) => panel.data as HttpClientConfig),
httpServers: clientPanelData
.filter((panel) => panel.key === 'httpServers')
.map((panel) => panel.data as HttpServerConfig),
};
}; };
const loadConfig = async () => { const loadConfig = async () => {
try { try {
const userConfig = await getOB11Config(); const userConfig = await getOB11Config();
if (!userConfig) return; if (!userConfig) return;
const mergedConfig = mergeOnebotConfigs(defaultOnebotConfig, userConfig); const mergedConfig = mergeOneBotConfigs(defaultOneBotConfigs, userConfig);
const networkConfig = mergedConfig.network; addConfigDataToPanel(mergedConfig.network);
log('networkConfig:', networkConfig);
const panels = generatePanels(networkConfig);
log('panels:', panels);
panelData.value = panels;
if (panels.length > 0) {
value.value = panels[0].value;
}
} catch (error) { } catch (error) {
console.error('Error loading config:', error); console.error('Error loading config:', error);
} }
}; };
// It's better to "saveConfig" instead of using deep watch
const saveConfig = async () => {
const config = parsePanelData();
const userConfig = await getOB11Config();
if (!userConfig) return;
userConfig.network = config;
await setOB11Config(userConfig);
};
const showAddTabDialog = () => { const showAddTabDialog = () => {
newTab.value = { name: '', type: '' }; newTab.value = { name: '', type: 'httpServers' };
isDialogVisible.value = true; isDialogVisible.value = true;
}; };
const addTab = async () => { const addTab = async () => {
const { name, type } = newTab.value; const { name, type } = newTab.value;
if (!name || !type) return; const defaultConfig = structuredClone(defaultConfigs[type]);
const newPanel = createPanel(type, name, id); clientPanelData.push({ name, data: defaultConfig, key: type });
panelData.value.push(newPanel);
id += 1;
isDialogVisible.value = false; isDialogVisible.value = false;
await nextTick(); // 确保 DOM 更新完成 await nextTick();
value.value = newPanel.value; // 强制重新渲染选项卡 activeTab.value = clientPanelData.length - 1;
}; };
const closeDialog = () => { const removeTab = (payload: { value: string; index: number; e: PointerEvent }) => {
isDialogVisible.value = false; clientPanelData.splice(payload.index, 1);
activeTab.value = Math.max(0, activeTab.value - 1);
}; };
const removeTab = ({ value: val, index }: { value: string; index: number }) => {
if (index < 0) return false;
panelData.value.splice(index, 1);
if (panelData.value.length === 0) return;
if (value.value === val) {
value.value = panelData.value[Math.max(index - 1, 0)].value;
}
};
const syncConfig = async () => {
const networkConfig: Record<string, any[]> = {};
panelData.value.forEach((panel) => {
const key = panel.value.split('-')[0];
if (!networkConfig[key]) {
networkConfig[key] = [];
}
networkConfig[key].push(panel.config);
});
const userConfig = await getOB11Config();
if (!userConfig) return;
const mergedConfig = mergeOnebotConfigs(defaultOnebotConfig, userConfig);
mergedConfig.network = networkConfig;
await setOB11Config(mergedConfig);
};
watch(panelData, syncConfig, { deep: true });
onMounted(() => { onMounted(() => {
loadConfig(); loadConfig();
}); });

View File

@@ -22,21 +22,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { defineProps } from 'vue';
import { HttpClientConfig } from '../../../../src/onebot/config/config';
interface HttpClientConfig { defineProps<{
url: string; config: HttpClientConfig;
messagePostFormat: string; }>();
reportSelfMessage: boolean;
token: string;
debug: boolean;
}
const config = ref<HttpClientConfig>({
url: '',
messagePostFormat: '',
reportSelfMessage: false,
token: '',
debug: false,
});
</script> </script>

View File

@@ -31,27 +31,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { defineProps } from 'vue';
import { HttpServerConfig } from '../../../../src/onebot/config/config';
interface HttpServerConfig { defineProps<{
port: number; config: HttpServerConfig;
host: string; }>();
enableCors: boolean;
enableWebsocket: boolean;
messagePostFormat: string;
reportSelfMessage: boolean;
token: string;
debug: boolean;
}
const config = ref<HttpServerConfig>({
port: 8080,
host: '',
enableCors: false,
enableWebsocket: false,
messagePostFormat: '',
reportSelfMessage: false,
token: '',
debug: false,
});
</script> </script>

View File

@@ -25,23 +25,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { defineProps } from 'vue';
import { WebsocketClientConfig } from '../../../../src/onebot/config/config';
interface WsClientConfig { defineProps<{
url: string; config: WebsocketClientConfig;
messagePostFormat: string; }>();
reportSelfMessage: boolean;
token: string;
debug: boolean;
heartInterval: number;
}
const config = ref<WsClientConfig>({
url: '',
messagePostFormat: '',
reportSelfMessage: false,
token: '',
debug: false,
heartInterval: 0,
});
</script> </script>

View File

@@ -31,27 +31,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { defineProps } from 'vue';
import { WebsocketServerConfig } from '../../../../src/onebot/config/config';
interface WsServerConfig { defineProps<{
host: string; config: WebsocketServerConfig;
port: number; }>();
messagePostFormat: string;
reportSelfMessage: boolean;
token: string;
enablePushEvent: boolean;
debug: boolean;
heartInterval: number;
}
const config = ref<WsServerConfig>({
host: '',
port: 8080,
messagePostFormat: '',
reportSelfMessage: false,
token: '',
enablePushEvent: false,
debug: false,
heartInterval: 0,
});
</script> </script>

View File

@@ -6,7 +6,7 @@ export interface AdapterConfig {
const createDefaultAdapterConfig = <T extends AdapterConfig>(config: T): T => config; const createDefaultAdapterConfig = <T extends AdapterConfig>(config: T): T => config;
const httpServerDefaultConfigs = createDefaultAdapterConfig({ export const httpServerDefaultConfigs = createDefaultAdapterConfig({
name: 'http-server', name: 'http-server',
enable: false, enable: false,
port: 3000, port: 3000,
@@ -20,7 +20,7 @@ const httpServerDefaultConfigs = createDefaultAdapterConfig({
}); });
export type HttpServerConfig = typeof httpServerDefaultConfigs; export type HttpServerConfig = typeof httpServerDefaultConfigs;
const httpClientDefaultConfigs = createDefaultAdapterConfig({ export const httpClientDefaultConfigs = createDefaultAdapterConfig({
name: 'http-client', name: 'http-client',
enable: false, enable: false,
url: 'http://localhost:8080', url: 'http://localhost:8080',
@@ -31,7 +31,7 @@ const httpClientDefaultConfigs = createDefaultAdapterConfig({
}); });
export type HttpClientConfig = typeof httpClientDefaultConfigs; export type HttpClientConfig = typeof httpClientDefaultConfigs;
const websocketServerDefaultConfigs = createDefaultAdapterConfig({ export const websocketServerDefaultConfigs = createDefaultAdapterConfig({
name: 'websocket-server', name: 'websocket-server',
enable: false, enable: false,
host: '0.0.0.0', host: '0.0.0.0',
@@ -45,7 +45,7 @@ const websocketServerDefaultConfigs = createDefaultAdapterConfig({
}); });
export type WebsocketServerConfig = typeof websocketServerDefaultConfigs; export type WebsocketServerConfig = typeof websocketServerDefaultConfigs;
const websocketClientDefaultConfigs = createDefaultAdapterConfig({ export const websocketClientDefaultConfigs = createDefaultAdapterConfig({
name: 'websocket-client', name: 'websocket-client',
enable: false, enable: false,
url: 'ws://localhost:8082', url: 'ws://localhost:8082',
@@ -58,34 +58,35 @@ const websocketClientDefaultConfigs = createDefaultAdapterConfig({
export type WebsocketClientConfig = typeof websocketClientDefaultConfigs; export type WebsocketClientConfig = typeof websocketClientDefaultConfigs;
export interface NetworkConfig { export interface NetworkConfig {
httpServers: Array<HttpServerConfig>, httpServers: Array<HttpServerConfig>;
httpClients: Array<HttpClientConfig>, httpClients: Array<HttpClientConfig>;
websocketServers: Array<WebsocketServerConfig>, websocketServers: Array<WebsocketServerConfig>;
websocketClients: Array<WebsocketClientConfig>, websocketClients: Array<WebsocketClientConfig>;
}; }
export function mergeConfigs<T extends AdapterConfig>(defaultConfig: T, userConfig: Partial<T>): T { export function mergeConfigs<T extends AdapterConfig>(defaultConfig: T, userConfig: Partial<T>): T {
return { ...defaultConfig, ...userConfig }; return { ...defaultConfig, ...userConfig };
} }
export interface OnebotConfig { export interface OneBotConfig {
network: NetworkConfig;//网络配置 network: NetworkConfig; //网络配置
musicSignUrl: string;//音乐签名地址 musicSignUrl: string; //音乐签名地址
enableLocalFile2Url: boolean enableLocalFile2Url: boolean;
} }
const createDefaultConfig = <T>(config: T): T => config; const createDefaultConfig = <T>(config: T): T => config;
export const defaultOnebotConfig = createDefaultConfig<OnebotConfig>({ export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
network: { network: {
httpServers: [], httpServers: [],
httpClients: [], httpClients: [],
websocketServers: [], websocketServers: [],
websocketClients: [], websocketClients: [],
}, },
musicSignUrl: "", musicSignUrl: '',
enableLocalFile2Url: false enableLocalFile2Url: false,
}); });
export const mergeNetworkDefaultConfig = { export const mergeNetworkDefaultConfig = {
httpServers: httpServerDefaultConfigs, httpServers: httpServerDefaultConfigs,
httpClients: httpClientDefaultConfigs, httpClients: httpClientDefaultConfigs,
@@ -95,7 +96,8 @@ export const mergeNetworkDefaultConfig = {
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig; type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig;
export function mergeOnebotConfigs(defaultConfig: OnebotConfig, userConfig: Partial<OnebotConfig>): OnebotConfig { // TODO: wrong type hint in userConfig (aka old userConfig)
export function mergeOneBotConfigs(defaultConfig: OneBotConfig, userConfig: Partial<OneBotConfig>): OneBotConfig {
const mergedConfig = { ...defaultConfig }; const mergedConfig = { ...defaultConfig };
if (userConfig.network) { if (userConfig.network) {
@@ -104,7 +106,9 @@ export function mergeOnebotConfigs(defaultConfig: OnebotConfig, userConfig: Part
const userNetworkConfig = userConfig.network[key as keyof NetworkConfig]; const userNetworkConfig = userConfig.network[key as keyof NetworkConfig];
const defaultNetworkConfig = mergeNetworkDefaultConfig[key as NetworkConfigKeys]; const defaultNetworkConfig = mergeNetworkDefaultConfig[key as NetworkConfigKeys];
if (Array.isArray(userNetworkConfig)) { if (Array.isArray(userNetworkConfig)) {
mergedConfig.network[key as keyof NetworkConfig] = userNetworkConfig.map<any>(e => mergeConfigs(defaultNetworkConfig, e)); mergedConfig.network[key as keyof NetworkConfig] = userNetworkConfig.map<any>((e) =>
mergeConfigs(defaultNetworkConfig, e)
);
} }
} }
} }

View File

@@ -1,8 +1,8 @@
import { ConfigBase } from '@/common/config-base'; import { ConfigBase } from '@/common/config-base';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
import { OnebotConfig } from './config'; import { OneBotConfig } from './config';
export class OB11ConfigLoader extends ConfigBase<OnebotConfig> { export class OB11ConfigLoader extends ConfigBase<OneBotConfig> {
constructor(core: NapCatCore, configPath: string) { constructor(core: NapCatCore, configPath: string) {
super('onebot11', core, configPath, false); super('onebot11', core, configPath, false);
} }

View File

@@ -45,7 +45,7 @@ import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecal
import { LRUCache } from '@/common/lru-cache'; import { LRUCache } from '@/common/lru-cache';
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener'; import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
import { BotOfflineEvent } from './event/notice/BotOfflineEvent'; import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
import { defaultOnebotConfig, mergeOnebotConfigs, OnebotConfig } from './config/config'; import { defaultOneBotConfigs, mergeOneBotConfigs, OneBotConfig } from './config/config';
import { OB11Message } from './types'; import { OB11Message } from './types';
//OneBot实现类 //OneBot实现类
@@ -63,8 +63,8 @@ export class NapCatOneBot11Adapter {
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) { constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
this.core = core; this.core = core;
this.context = context; this.context = context;
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath,); this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath);
this.configLoader.save(mergeOnebotConfigs(defaultOnebotConfig, this.configLoader.configData)); this.configLoader.save(mergeOneBotConfigs(defaultOneBotConfigs, this.configLoader.configData));
this.apis = { this.apis = {
GroupApi: new OneBotGroupApi(this, core), GroupApi: new OneBotGroupApi(this, core),
UserApi: new OneBotUserApi(this, core), UserApi: new OneBotUserApi(this, core),
@@ -75,7 +75,7 @@ export class NapCatOneBot11Adapter {
this.actions = createActionMap(this, core); this.actions = createActionMap(this, core);
this.networkManager = new OB11NetworkManager(); this.networkManager = new OB11NetworkManager();
} }
async creatOneBotLog(ob11Config: OnebotConfig) { async creatOneBotLog(ob11Config: OneBotConfig) {
let log = `[network] 配置加载\n`; let log = `[network] 配置加载\n`;
for (const key of ob11Config.network.httpServers) { for (const key of ob11Config.network.httpServers) {
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`; log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
@@ -95,10 +95,12 @@ export class NapCatOneBot11Adapter {
const selfInfo = this.core.selfInfo; const selfInfo = this.core.selfInfo;
const ob11Config = this.configLoader.configData; const ob11Config = this.configLoader.configData;
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid).then(user => { this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid)
selfInfo.nick = user.nick; .then((user) => {
this.context.logger.setLogSelfInfo(selfInfo); selfInfo.nick = user.nick;
}).catch(this.context.logger.logError.bind(this.context.logger)); this.context.logger.setLogSelfInfo(selfInfo);
})
.catch(this.context.logger.logError.bind(this.context.logger));
const serviceInfo = await this.creatOneBotLog(ob11Config); const serviceInfo = await this.creatOneBotLog(ob11Config);
this.context.logger.log(`[Notice] [OneBot11] ${serviceInfo}`); this.context.logger.log(`[Notice] [OneBot11] ${serviceInfo}`);
@@ -106,30 +108,46 @@ export class NapCatOneBot11Adapter {
// //创建NetWork服务 // //创建NetWork服务
for (const key of ob11Config.network.httpServers) { for (const key of ob11Config.network.httpServers) {
if (key.enable) { if (key.enable) {
this.networkManager.registerAdapter(new OB11PassiveHttpAdapter( this.networkManager.registerAdapter(
key.name, key.port, key.token, this.core, this.actions, new OB11PassiveHttpAdapter(key.name, key.port, key.token, this.core, this.actions)
)); );
} }
} }
for (const key of ob11Config.network.httpClients) { for (const key of ob11Config.network.httpClients) {
if (key.enable) { if (key.enable) {
this.networkManager.registerAdapter(new OB11ActiveHttpAdapter( this.networkManager.registerAdapter(
key.name, key.url, key.token, this.core, this, new OB11ActiveHttpAdapter(key.name, key.url, key.token, this.core, this)
)); );
} }
} }
for (const key of ob11Config.network.websocketServers) { for (const key of ob11Config.network.websocketServers) {
if (key.enable) { if (key.enable) {
this.networkManager.registerAdapter(new OB11PassiveWebSocketAdapter( this.networkManager.registerAdapter(
key.name, key.host, key.port, key.heartInterval, key.token, this.core, this.actions, new OB11PassiveWebSocketAdapter(
)); key.name,
key.host,
key.port,
key.heartInterval,
key.token,
this.core,
this.actions
)
);
} }
} }
for (const key of ob11Config.network.websocketClients) { for (const key of ob11Config.network.websocketClients) {
if (key.enable) { if (key.enable) {
this.networkManager.registerAdapter(new OB11ActiveWebSocketAdapter( this.networkManager.registerAdapter(
key.name, key.url, 5000, key.heartInterval, key.token, this.core, this.actions, new OB11ActiveWebSocketAdapter(
)); key.name,
key.url,
5000,
key.heartInterval,
key.token,
this.core,
this.actions
)
);
} }
} }
await this.networkManager.openAllAdapters(); await this.networkManager.openAllAdapters();
@@ -150,7 +168,9 @@ export class NapCatOneBot11Adapter {
initRecentContactListener() { initRecentContactListener() {
const recentContactListener = new NodeIKernelRecentContactListener(); const recentContactListener = new NodeIKernelRecentContactListener();
recentContactListener.onRecentContactNotification = function (msgList: any[] /* arg0: { msgListUnreadCnt: string }, arg1: number */) { recentContactListener.onRecentContactNotification = function (
msgList: any[] /* arg0: { msgListUnreadCnt: string }, arg1: number */
) {
msgList.forEach((msg) => { msgList.forEach((msg) => {
if (msg.chatType == ChatType.KCHATTYPEGROUP) { if (msg.chatType == ChatType.KCHATTYPEGROUP) {
// log("recent contact", msgList, arg0, arg1); // log("recent contact", msgList, arg0, arg1);
@@ -201,7 +221,6 @@ export class NapCatOneBot11Adapter {
// } // }
// } // }
// // check difference in passive websocket (Ws) // // check difference in passive websocket (Ws)
// if (prev.ws.enable !== now.ws.enable) { // if (prev.ws.enable !== now.ws.enable) {
// if (now.ws.enable) { // if (now.ws.enable) {
@@ -242,32 +261,38 @@ export class NapCatOneBot11Adapter {
// } // }
private findDifference<T>(prev: T[], now: T[]): { added: T[], removed: T[] } { private findDifference<T>(prev: T[], now: T[]): { added: T[]; removed: T[] } {
const added = now.filter(item => !prev.includes(item)); const added = now.filter((item) => !prev.includes(item));
const removed = prev.filter(item => !now.includes(item)); const removed = prev.filter((item) => !now.includes(item));
return { added, removed }; return { added, removed };
} }
private initMsgListener() { private initMsgListener() {
const msgListener = new NodeIKernelMsgListener(); const msgListener = new NodeIKernelMsgListener();
msgListener.onRecvSysMsg = (msg) => { msgListener.onRecvSysMsg = (msg) => {
this.apis.MsgApi.parseSysMessage(msg).then((event) => { this.apis.MsgApi.parseSysMessage(msg)
if (event) this.networkManager.emitEvent(event); .then((event) => {
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructSysMessage error: ', e, '\n Parse Hex:', Buffer.from(msg).toString('hex'))); if (event) this.networkManager.emitEvent(event);
})
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)(
'constructSysMessage error: ',
e,
'\n Parse Hex:',
Buffer.from(msg).toString('hex')
)
);
}; };
msgListener.onInputStatusPush = async data => { msgListener.onInputStatusPush = async (data) => {
const uin = await this.core.apis.UserApi.getUinByUidV2(data.fromUin); const uin = await this.core.apis.UserApi.getUinByUidV2(data.fromUin);
this.context.logger.log(`[Notice] [输入状态] ${uin} ${data.statusText}`); this.context.logger.log(`[Notice] [输入状态] ${uin} ${data.statusText}`);
await this.networkManager.emitEvent(new OB11InputStatusEvent( await this.networkManager.emitEvent(
this.core, new OB11InputStatusEvent(this.core, parseInt(uin), data.eventType, data.statusText)
parseInt(uin), );
data.eventType,
data.statusText,
));
}; };
msgListener.onRecvMsg = async msg => { msgListener.onRecvMsg = async (msg) => {
for (const m of msg) { for (const m of msg) {
if (this.bootTime > parseInt(m.msgTime)) { if (this.bootTime > parseInt(m.msgTime)) {
this.context.logger.logDebug(`消息时间${m.msgTime}早于启动时间${this.bootTime},忽略上报`); this.context.logger.logDebug(`消息时间${m.msgTime}早于启动时间${this.bootTime},忽略上报`);
@@ -279,50 +304,54 @@ export class NapCatOneBot11Adapter {
peerUid: m.peerUid, peerUid: m.peerUid,
guildId: '', guildId: '',
}, },
m.msgId, m.msgId
);
await this.emitMsg(m).catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)
); );
await this.emitMsg(m)
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
} }
}; };
const msgIdSend = new LRUCache<string, number>(100); const msgIdSend = new LRUCache<string, number>(100);
const recallMsgs = new LRUCache<string, boolean>(100); const recallMsgs = new LRUCache<string, boolean>(100);
msgListener.onAddSendMsg = async msg => { msgListener.onAddSendMsg = async (msg) => {
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) { if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
msgIdSend.put(msg.msgId, 0); msgIdSend.put(msg.msgId, 0);
} }
}; };
msgListener.onMsgInfoListUpdate = async msgList => { msgListener.onMsgInfoListUpdate = async (msgList) => {
this.emitRecallMsg(msgList, recallMsgs) this.emitRecallMsg(msgList, recallMsgs).catch((e) =>
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)); this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)
for (const msg of msgList.filter(e => e.senderUin == this.core.selfInfo.uin)) { );
for (const msg of msgList.filter((e) => e.senderUin == this.core.selfInfo.uin)) {
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && msgIdSend.get(msg.msgId) == 0) { if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && msgIdSend.get(msg.msgId) == 0) {
msgIdSend.put(msg.msgId, 1); msgIdSend.put(msg.msgId, 1);
// 完成后再post // 完成后再post
msg.id = MessageUnique.createUniqueMsgId({ msg.id = MessageUnique.createUniqueMsgId(
chatType: msg.chatType, {
peerUid: msg.peerUid, chatType: msg.chatType,
guildId: '', peerUid: msg.peerUid,
}, msg.msgId); guildId: '',
},
msg.msgId
);
this.emitMsg(msg); this.emitMsg(msg);
} }
} }
}; };
msgListener.onKickedOffLine = async (kick) => { msgListener.onKickedOffLine = async (kick) => {
const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc); const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
this.networkManager.emitEvent(event) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理Bot掉线失败', e)); .emitEvent(event)
.catch((e) => this.context.logger.logError.bind(this.context.logger)('处理Bot掉线失败', e));
}; };
this.context.session.getMsgService().addKernelMsgListener( this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
proxiedListenerOf(msgListener, this.context.logger),
);
} }
private initBuddyListener() { private initBuddyListener() {
const buddyListener = new NodeIKernelBuddyListener(); const buddyListener = new NodeIKernelBuddyListener();
buddyListener.onBuddyReqChange = async reqs => { buddyListener.onBuddyReqChange = async (reqs) => {
this.core.apis.FriendApi.clearBuddyReqUnreadCnt(); this.core.apis.FriendApi.clearBuddyReqUnreadCnt();
for (let i = 0; i < reqs.unreadNums; i++) { for (let i = 0; i < reqs.unreadNums; i++) {
const req = reqs.buddyReqs[i]; const req = reqs.buddyReqs[i];
@@ -331,21 +360,23 @@ export class NapCatOneBot11Adapter {
} }
try { try {
const requesterUin = await this.core.apis.UserApi.getUinByUidV2(req.friendUid); const requesterUin = await this.core.apis.UserApi.getUinByUidV2(req.friendUid);
await this.networkManager.emitEvent(new OB11FriendRequestEvent( await this.networkManager.emitEvent(
this.core, new OB11FriendRequestEvent(
+requesterUin, this.core,
req.extWords, +requesterUin,
req.friendUid + '|' + req.reqTime, req.extWords,
)); req.friendUid + '|' + req.reqTime
)
);
} catch (e) { } catch (e) {
this.context.logger.logDebug('获取加好友者QQ号失败', e); this.context.logger.logDebug('获取加好友者QQ号失败', e);
} }
} }
}; };
this.context.session.getBuddyService().addKernelBuddyListener( this.context.session
proxiedListenerOf(buddyListener, this.context.logger), .getBuddyService()
); .addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
} }
private initGroupListener() { private initGroupListener() {
@@ -354,11 +385,13 @@ export class NapCatOneBot11Adapter {
groupListener.onGroupNotifiesUpdated = async (_, notifies) => { groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
//console.log('ob11 onGroupNotifiesUpdated', notifies[0]); //console.log('ob11 onGroupNotifiesUpdated', notifies[0]);
await this.core.apis.GroupApi.clearGroupNotifiesUnreadCount(false); await this.core.apis.GroupApi.clearGroupNotifiesUnreadCount(false);
if (![ if (
GroupNotifyMsgType.SET_ADMIN, ![
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED, GroupNotifyMsgType.SET_ADMIN,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN, GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
].includes(notifies[0]?.type)) { GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
].includes(notifies[0]?.type)
) {
for (const notify of notifies) { for (const notify of notifies) {
const notifyTime = parseInt(notify.seq) / 1000 / 1000; const notifyTime = parseInt(notify.seq) / 1000 / 1000;
// log(`群通知时间${notifyTime}`, `启动时间${this.bootTime}`); // log(`群通知时间${notifyTime}`, `启动时间${this.bootTime}`);
@@ -369,12 +402,17 @@ export class NapCatOneBot11Adapter {
const flag = notify.group.groupCode + '|' + notify.seq + '|' + notify.type; const flag = notify.group.groupCode + '|' + notify.seq + '|' + notify.type;
this.context.logger.logDebug('收到群通知', notify); this.context.logger.logDebug('收到群通知', notify);
if ([ if (
GroupNotifyMsgType.SET_ADMIN, [
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED, GroupNotifyMsgType.SET_ADMIN,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN, GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
].includes(notify.type)) { GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
const member1 = await this.core.apis.GroupApi.getGroupMember(notify.group.groupCode, notify.user1.uid); ].includes(notify.type)
) {
const member1 = await this.core.apis.GroupApi.getGroupMember(
notify.group.groupCode,
notify.user1.uid
);
this.context.logger.logDebug('有管理员变动通知'); this.context.logger.logDebug('有管理员变动通知');
// refreshGroupMembers(notify.group.groupCode).then(); // refreshGroupMembers(notify.group.groupCode).then();
this.context.logger.logDebug('开始获取变动的管理员'); this.context.logger.logDebug('开始获取变动的管理员');
@@ -387,16 +425,28 @@ export class NapCatOneBot11Adapter {
[ [
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED, GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN, GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
].includes(notify.type) ? 'unset' : 'set', ].includes(notify.type)
? 'unset'
: 'set'
); );
this.networkManager.emitEvent(groupAdminNoticeEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)); .emitEvent(groupAdminNoticeEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)
);
} else { } else {
this.context.logger.logDebug('获取群通知的成员信息失败', notify, this.core.apis.GroupApi.getGroup(notify.group.groupCode)); this.context.logger.logDebug(
'获取群通知的成员信息失败',
notify,
this.core.apis.GroupApi.getGroup(notify.group.groupCode)
);
} }
} else if (notify.type == GroupNotifyMsgType.MEMBER_LEAVE_NOTIFY_ADMIN || notify.type == GroupNotifyMsgType.KICK_MEMBER_NOTIFY_ADMIN) { } else if (
notify.type == GroupNotifyMsgType.MEMBER_LEAVE_NOTIFY_ADMIN ||
notify.type == GroupNotifyMsgType.KICK_MEMBER_NOTIFY_ADMIN
) {
this.context.logger.logDebug('有成员退出通知', notify); this.context.logger.logDebug('有成员退出通知', notify);
const member1Uin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)); const member1Uin = await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid);
let operatorId = member1Uin; let operatorId = member1Uin;
let subType: GroupDecreaseSubType = 'leave'; let subType: GroupDecreaseSubType = 'leave';
if (notify.user2.uid) { if (notify.user2.uid) {
@@ -412,17 +462,21 @@ export class NapCatOneBot11Adapter {
parseInt(notify.group.groupCode), parseInt(notify.group.groupCode),
parseInt(member1Uin), parseInt(member1Uin),
parseInt(operatorId), parseInt(operatorId),
subType, subType
); );
this.networkManager.emitEvent(groupDecreaseEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群成员退出失败', e)); .emitEvent(groupDecreaseEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理群成员退出失败', e)
);
// notify.status == 1 表示未处理 2表示处理完成 // notify.status == 1 表示未处理 2表示处理完成
} else if ([ } else if (
GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS, [GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS].includes(notify.type) &&
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) { notify.status == GroupNotifyMsgStatus.KUNHANDLE
) {
this.context.logger.logDebug('有加群请求'); this.context.logger.logDebug('有加群请求');
try { try {
let requestUin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)); let requestUin = await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid);
if (isNaN(parseInt(requestUin))) { if (isNaN(parseInt(requestUin))) {
requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin; requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin;
} }
@@ -432,14 +486,24 @@ export class NapCatOneBot11Adapter {
parseInt(requestUin), parseInt(requestUin),
'add', 'add',
notify.postscript, notify.postscript,
flag, flag
); );
this.networkManager.emitEvent(groupRequestEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理加群请求失败', e)); .emitEvent(groupRequestEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理加群请求失败', e)
);
} catch (e) { } catch (e) {
this.context.logger.logError.bind(this.context.logger)('获取加群人QQ号失败 Uid:', notify.user1.uid, e); this.context.logger.logError.bind(this.context.logger)(
'获取加群人QQ号失败 Uid:',
notify.user1.uid,
e
);
} }
} else if (notify.type == GroupNotifyMsgType.INVITED_BY_MEMBER && notify.status == GroupNotifyMsgStatus.KUNHANDLE) { } else if (
notify.type == GroupNotifyMsgType.INVITED_BY_MEMBER &&
notify.status == GroupNotifyMsgStatus.KUNHANDLE
) {
this.context.logger.logDebug(`收到邀请我加群通知:${notify}`); this.context.logger.logDebug(`收到邀请我加群通知:${notify}`);
const groupInviteEvent = new OB11GroupRequestEvent( const groupInviteEvent = new OB11GroupRequestEvent(
this.core, this.core,
@@ -447,11 +511,17 @@ export class NapCatOneBot11Adapter {
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user2.uid)), parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user2.uid)),
'invite', 'invite',
notify.postscript, notify.postscript,
flag, flag
); );
this.networkManager.emitEvent(groupInviteEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e)); .emitEvent(groupInviteEvent)
} else if (notify.type == GroupNotifyMsgType.INVITED_NEED_ADMINI_STRATOR_PASS && notify.status == GroupNotifyMsgStatus.KUNHANDLE) { .catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e)
);
} else if (
notify.type == GroupNotifyMsgType.INVITED_NEED_ADMINI_STRATOR_PASS &&
notify.status == GroupNotifyMsgStatus.KUNHANDLE
) {
this.context.logger.logDebug(`收到群员邀请加群通知:${notify}`); this.context.logger.logDebug(`收到群员邀请加群通知:${notify}`);
const groupInviteEvent = new OB11GroupRequestEvent( const groupInviteEvent = new OB11GroupRequestEvent(
this.core, this.core,
@@ -459,10 +529,13 @@ export class NapCatOneBot11Adapter {
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)), parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)),
'add', 'add',
notify.postscript, notify.postscript,
flag, flag
); );
this.networkManager.emitEvent(groupInviteEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e)); .emitEvent(groupInviteEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e)
);
} }
} }
} }
@@ -481,88 +554,102 @@ export class NapCatOneBot11Adapter {
this.core, this.core,
parseInt(groupCode), parseInt(groupCode),
parseInt(member.uin), parseInt(member.uin),
member.role === GroupMemberRole.admin ? 'set' : 'unset', member.role === GroupMemberRole.admin ? 'set' : 'unset'
); );
this.networkManager.emitEvent(groupAdminNoticeEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)); .emitEvent(groupAdminNoticeEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)
);
existMember.isChangeRole = false; existMember.isChangeRole = false;
this.context.logger.logDebug.bind(this.context.logger)('群管理员变动处理完毕'); this.context.logger.logDebug.bind(this.context.logger)('群管理员变动处理完毕');
}); });
} }
}; };
this.context.session.getGroupService().addKernelGroupListener( this.context.session
proxiedListenerOf(groupListener, this.context.logger), .getGroupService()
); .addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
} }
private async emitMsg(message: RawMessage) { private async emitMsg(message: RawMessage) {
const network = Object.values(this.configLoader.configData.network) as Array<typeof this.configLoader.configData.network[keyof typeof this.configLoader.configData.network]>; const network = Object.values(this.configLoader.configData.network) as Array<
(typeof this.configLoader.configData.network)[keyof typeof this.configLoader.configData.network]
>;
this.context.logger.logDebug('收到新消息 RawMessage', message); this.context.logger.logDebug('收到新消息 RawMessage', message);
this.apis.MsgApi.parseMessageV2(message).then((ob11Msg) => { this.apis.MsgApi.parseMessageV2(message)
if (!ob11Msg) return; .then((ob11Msg) => {
const isSelfMsg = ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin || ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin; if (!ob11Msg) return;
this.context.logger.logDebug('转化为 OB11Message', ob11Msg); const isSelfMsg =
const msgMap: Map<string, OB11Message> = new Map(); ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin ||
const enable_client: string[] = []; ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
network.flat().filter(e => e.enable).map(e => { this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
enable_client.push(e.name); const msgMap: Map<string, OB11Message> = new Map();
if (e.messagePostFormat == 'string') { const enable_client: string[] = [];
msgMap.set(e.name, structuredClone(ob11Msg.stringMsg)); network
} else { .flat()
msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg)); .filter((e) => e.enable)
} .map((e) => {
if (isSelfMsg) { enable_client.push(e.name);
ob11Msg.stringMsg.target_id = parseInt(message.peerUin); if (e.messagePostFormat == 'string') {
ob11Msg.arrayMsg.target_id = parseInt(message.peerUin); msgMap.set(e.name, structuredClone(ob11Msg.stringMsg));
} } else {
}); msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg));
const debug_network = network.flat().filter(e => e.enable && e.debug);
if (debug_network.length > 0) {
for (const adapter of debug_network) {
if (adapter.name) {
const msg = msgMap.get(adapter.name);
if (msg) {
msg.raw = message;
} }
if (isSelfMsg) {
ob11Msg.stringMsg.target_id = parseInt(message.peerUin);
ob11Msg.arrayMsg.target_id = parseInt(message.peerUin);
}
});
const debug_network = network.flat().filter((e) => e.enable && e.debug);
if (debug_network.length > 0) {
for (const adapter of debug_network) {
if (adapter.name) {
const msg = msgMap.get(adapter.name);
if (msg) {
msg.raw = message;
}
}
} }
} else if (ob11Msg.stringMsg.message.length === 0 || ob11Msg.arrayMsg.message.length == 0) {
return;
} }
} else if (ob11Msg.stringMsg.message.length === 0 || ob11Msg.arrayMsg.message.length == 0) { const notreportSelf_network = network.flat().filter((e) => e.enable && !e.reportSelfMessage);
return; if (isSelfMsg) {
for (const adapter of notreportSelf_network) {
} msgMap.delete(adapter.name);
const notreportSelf_network = network.flat().filter(e => e.enable && !e.reportSelfMessage); }
if (isSelfMsg) {
for (const adapter of notreportSelf_network) {
msgMap.delete(adapter.name);
} }
}
this.networkManager.emitEventByNames(msgMap); this.networkManager.emitEventByNames(msgMap);
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e)); })
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e));
this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => { this.apis.GroupApi.parseGroupEvent(message)
if (groupEvent) { .then((groupEvent) => {
// log("post group event", groupEvent); if (groupEvent) {
this.networkManager.emitEvent(groupEvent); // log("post group event", groupEvent);
} this.networkManager.emitEvent(groupEvent);
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructGroupEvent error: ', e)); }
})
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructGroupEvent error: ', e));
this.apis.MsgApi.parsePrivateMsgEvent(message).then(privateEvent => { this.apis.MsgApi.parsePrivateMsgEvent(message)
if (privateEvent) { .then((privateEvent) => {
// log("post private event", privateEvent); if (privateEvent) {
this.networkManager.emitEvent(privateEvent); // log("post private event", privateEvent);
} this.networkManager.emitEvent(privateEvent);
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructPrivateEvent error: ', e)); }
})
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructPrivateEvent error: ', e));
} }
private async emitRecallMsg(msgList: RawMessage[], cache: LRUCache<string, boolean>) { private async emitRecallMsg(msgList: RawMessage[], cache: LRUCache<string, boolean>) {
for (const message of msgList) { for (const message of msgList) {
// log("message update", message.sendStatus, message.msgId, message.msgSeq) // log("message update", message.sendStatus, message.msgId, message.msgSeq)
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' }; const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
if (message.recallTime != '0' && !cache.get(message.msgId)) { //work:这个判断方法不太好,应该使用灰色消息元素来判断? if (message.recallTime != '0' && !cache.get(message.msgId)) {
//work:这个判断方法不太好,应该使用灰色消息元素来判断?
cache.put(message.msgId, true); cache.put(message.msgId, true);
// 撤回消息上报 // 撤回消息上报
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId); let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
@@ -573,10 +660,13 @@ export class NapCatOneBot11Adapter {
const friendRecallEvent = new OB11FriendRecallNoticeEvent( const friendRecallEvent = new OB11FriendRecallNoticeEvent(
this.core, this.core,
+message.senderUin, +message.senderUin,
oriMessageId, oriMessageId
); );
this.networkManager.emitEvent(friendRecallEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理好友消息撤回失败', e)); .emitEvent(friendRecallEvent)
.catch((e) =>
this.context.logger.logError.bind(this.context.logger)('处理好友消息撤回失败', e)
);
} else if (message.chatType == ChatType.KCHATTYPEGROUP) { } else if (message.chatType == ChatType.KCHATTYPEGROUP) {
let operatorId = message.senderUin; let operatorId = message.senderUin;
for (const element of message.elements) { for (const element of message.elements) {
@@ -592,8 +682,9 @@ export class NapCatOneBot11Adapter {
+operatorId, +operatorId,
oriMessageId oriMessageId
); );
this.networkManager.emitEvent(groupRecallEvent) this.networkManager
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e)); .emitEvent(groupRecallEvent)
.catch((e) => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e));
} }
} }
} }

View File

@@ -1,12 +1,11 @@
import { RequestHandler } from 'express'; import { RequestHandler } from 'express';
import { WebUiDataRuntime } from '../helper/Data'; import { WebUiDataRuntime } from '../helper/Data';
import { existsSync, readFileSync } from 'node:fs'; import { existsSync, readFileSync } from 'node:fs';
import { OnebotConfig } from '@/onebot/config/config'; import { OneBotConfig } from '@/onebot/config/config';
import { resolve } from 'node:path'; import { resolve } from 'node:path';
import { webUiPathWrapper } from '@/webui'; import { webUiPathWrapper } from '@/webui';
const isEmpty = (data: any) => const isEmpty = (data: any) => data === undefined || data === null || data === '';
data === undefined || data === null || data === '';
export const OB11GetConfigHandler: RequestHandler = async (req, res) => { export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
const isLogin = await WebUiDataRuntime.getQQLoginStatus(); const isLogin = await WebUiDataRuntime.getQQLoginStatus();
if (!isLogin) { if (!isLogin) {
@@ -19,15 +18,15 @@ export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
const uin = await WebUiDataRuntime.getQQLoginUin(); const uin = await WebUiDataRuntime.getQQLoginUin();
const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`); const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`);
//console.log(configFilePath); //console.log(configFilePath);
let data: OnebotConfig; let data: OneBotConfig;
try { try {
data = JSON.parse( data = JSON.parse(
existsSync(configFilePath) existsSync(configFilePath)
? readFileSync(configFilePath).toString() ? readFileSync(configFilePath).toString()
: readFileSync(resolve(webUiPathWrapper.configPath, './onebot11.json')).toString(), : readFileSync(resolve(webUiPathWrapper.configPath, './onebot11.json')).toString()
); );
} catch (e) { } catch (e) {
data = {} as OnebotConfig; data = {} as OneBotConfig;
res.send({ res.send({
code: -1, code: -1,
message: 'Config Get Error', message: 'Config Get Error',

View File

@@ -1,4 +1,4 @@
import { OnebotConfig } from '@/onebot/config/config'; import { OneBotConfig } from '@/onebot/config/config';
interface LoginRuntimeType { interface LoginRuntimeType {
LoginCurrentTime: number; LoginCurrentTime: number;
@@ -7,9 +7,9 @@ interface LoginRuntimeType {
QQQRCodeURL: string; QQQRCodeURL: string;
QQLoginUin: string; QQLoginUin: string;
NapCatHelper: { NapCatHelper: {
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean, message: string }>; onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>;
onOB11ConfigChanged: (ob11: OnebotConfig) => Promise<void>; onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>;
QQLoginList: string[] QQLoginList: string[];
}; };
} }
@@ -31,62 +31,62 @@ const LoginRuntime: LoginRuntimeType = {
}; };
export const WebUiDataRuntime = { export const WebUiDataRuntime = {
checkLoginRate: async function(RateLimit: number): Promise<boolean> { checkLoginRate: async function (RateLimit: number): Promise<boolean> {
LoginRuntime.LoginCurrentRate++; LoginRuntime.LoginCurrentRate++;
//console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime); //console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime);
if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) { if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) {
LoginRuntime.LoginCurrentRate = 0;//超出时间重置限速 LoginRuntime.LoginCurrentRate = 0; //超出时间重置限速
LoginRuntime.LoginCurrentTime = Date.now(); LoginRuntime.LoginCurrentTime = Date.now();
return true; return true;
} }
return LoginRuntime.LoginCurrentRate <= RateLimit; return LoginRuntime.LoginCurrentRate <= RateLimit;
}, },
getQQLoginStatus: async function(): Promise<boolean> { getQQLoginStatus: async function (): Promise<boolean> {
return LoginRuntime.QQLoginStatus; return LoginRuntime.QQLoginStatus;
}, },
setQQLoginStatus: async function(status: boolean): Promise<void> { setQQLoginStatus: async function (status: boolean): Promise<void> {
LoginRuntime.QQLoginStatus = status; LoginRuntime.QQLoginStatus = status;
}, },
setQQLoginQrcodeURL: async function(url: string): Promise<void> { setQQLoginQrcodeURL: async function (url: string): Promise<void> {
LoginRuntime.QQQRCodeURL = url; LoginRuntime.QQQRCodeURL = url;
}, },
getQQLoginQrcodeURL: async function(): Promise<string> { getQQLoginQrcodeURL: async function (): Promise<string> {
return LoginRuntime.QQQRCodeURL; return LoginRuntime.QQQRCodeURL;
}, },
setQQLoginUin: async function(uin: string): Promise<void> { setQQLoginUin: async function (uin: string): Promise<void> {
LoginRuntime.QQLoginUin = uin; LoginRuntime.QQLoginUin = uin;
}, },
getQQLoginUin: async function(): Promise<string> { getQQLoginUin: async function (): Promise<string> {
return LoginRuntime.QQLoginUin; return LoginRuntime.QQLoginUin;
}, },
getQQQuickLoginList: async function(): Promise<any[]> { getQQQuickLoginList: async function (): Promise<any[]> {
return LoginRuntime.NapCatHelper.QQLoginList; return LoginRuntime.NapCatHelper.QQLoginList;
}, },
setQQQuickLoginList: async function(list: string[]): Promise<void> { setQQQuickLoginList: async function (list: string[]): Promise<void> {
LoginRuntime.NapCatHelper.QQLoginList = list; LoginRuntime.NapCatHelper.QQLoginList = list;
}, },
setQuickLoginCall(func: (uin: string) => Promise<{ result: boolean, message: string }>): void { setQuickLoginCall(func: (uin: string) => Promise<{ result: boolean; message: string }>): void {
LoginRuntime.NapCatHelper.onQuickLoginRequested = func; LoginRuntime.NapCatHelper.onQuickLoginRequested = func;
}, },
requestQuickLogin: async function(uin: string): Promise<{ result: boolean, message: string }> { requestQuickLogin: async function (uin: string): Promise<{ result: boolean; message: string }> {
return await LoginRuntime.NapCatHelper.onQuickLoginRequested(uin); return await LoginRuntime.NapCatHelper.onQuickLoginRequested(uin);
}, },
setOnOB11ConfigChanged: async function(func: (ob11: OnebotConfig) => Promise<void>): Promise<void> { setOnOB11ConfigChanged: async function (func: (ob11: OneBotConfig) => Promise<void>): Promise<void> {
LoginRuntime.NapCatHelper.onOB11ConfigChanged = func; LoginRuntime.NapCatHelper.onOB11ConfigChanged = func;
}, },
setOB11Config: async function(ob11: OnebotConfig): Promise<void> { setOB11Config: async function (ob11: OneBotConfig): Promise<void> {
await LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11); await LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
}, },
}; };