mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
refactor: webui network
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { OneBotConfig } from '../../../src/onebot/config/config';
|
||||
|
||||
export class QQLoginManager {
|
||||
private retCredential: string;
|
||||
private readonly apiPrefix: string;
|
||||
@@ -9,7 +11,7 @@ export class QQLoginManager {
|
||||
}
|
||||
|
||||
// TODO:
|
||||
public async GetOB11Config(): Promise<any> {
|
||||
public async GetOB11Config(): Promise<OneBotConfig> {
|
||||
try {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, {
|
||||
method: 'POST',
|
||||
@@ -21,16 +23,16 @@ export class QQLoginManager {
|
||||
if (ConfigResponse.status == 200) {
|
||||
const ConfigResponseJson = await ConfigResponse.json();
|
||||
if (ConfigResponseJson.code == 0) {
|
||||
return ConfigResponseJson?.data;
|
||||
return ConfigResponseJson?.data as OneBotConfig;
|
||||
}
|
||||
}
|
||||
} catch (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 {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, {
|
||||
method: 'POST',
|
||||
|
@@ -1,70 +1,104 @@
|
||||
<template>
|
||||
<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
|
||||
v-for="data in panelData"
|
||||
:key="data.value"
|
||||
:label="data.label"
|
||||
:removable="data.removable"
|
||||
:value="data.value"
|
||||
v-for="(config, idx) in clientPanelData"
|
||||
:key="idx"
|
||||
:label="config.name"
|
||||
:removable="true"
|
||||
: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-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-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>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
|
||||
import { defaultOnebotConfig, mergeOnebotConfigs } from '../../../src/onebot/config/config';
|
||||
import { ref, resolveDynamicComponent, nextTick, Ref, onMounted, reactive, Reactive } from 'vue';
|
||||
import {
|
||||
httpServerDefaultConfigs,
|
||||
httpClientDefaultConfigs,
|
||||
websocketServerDefaultConfigs,
|
||||
websocketClientDefaultConfigs,
|
||||
HttpClientConfig,
|
||||
HttpServerConfig,
|
||||
WebsocketClientConfig,
|
||||
WebsocketServerConfig,
|
||||
NetworkConfig,
|
||||
OneBotConfig,
|
||||
defaultOneBotConfigs,
|
||||
mergeOneBotConfigs,
|
||||
} from '../../../src/onebot/config/config';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
import HttpServerComponent from './network/HttpServerComponent.vue';
|
||||
import HttpClientComponent from './network/HttpClientComponent.vue';
|
||||
import WebsocketServerComponent from './network/WebsocketServerComponent.vue';
|
||||
import WebsocketClientComponent from './network/WebsocketClientComponent.vue';
|
||||
import HttpServerComponent from '@/pages/network/HttpServerComponent.vue';
|
||||
import HttpClientComponent from '@/pages/network/HttpClientComponent.vue';
|
||||
import WebsocketServerComponent from '@/pages/network/WebsocketServerComponent.vue';
|
||||
import WebsocketClientComponent from '@/pages/network/WebsocketClientComponent.vue';
|
||||
|
||||
interface PanelData {
|
||||
value: string;
|
||||
label: string;
|
||||
removable: boolean;
|
||||
component: any;
|
||||
config: { name: string };
|
||||
}
|
||||
type ConfigKey = 'httpServers' | 'httpClients' | 'websocketServers' | 'websocketClients';
|
||||
|
||||
let id = 0;
|
||||
const value = ref<string>('first');
|
||||
const panelData = ref<PanelData[]>([]);
|
||||
const isDialogVisible = ref<boolean>(false);
|
||||
const newTab = ref<{ name: string; type: string }>({ name: '', type: '' });
|
||||
type ConfigUnion = HttpClientConfig | HttpServerConfig | WebsocketServerConfig | WebsocketClientConfig;
|
||||
|
||||
const componentMap: Record<string, any> = {
|
||||
httpServers: shallowRef(HttpServerComponent),
|
||||
httpClients: shallowRef(HttpClientComponent),
|
||||
websocketServers: shallowRef(WebsocketServerComponent),
|
||||
websocketClients: shallowRef(WebsocketClientComponent),
|
||||
const defaultConfigs: Record<ConfigKey, ConfigUnion> = {
|
||||
httpServers: httpServerDefaultConfigs,
|
||||
httpClients: httpClientDefaultConfigs,
|
||||
websocketServers: websocketServerDefaultConfigs,
|
||||
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');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
@@ -74,7 +108,7 @@ const getOB11Config = async (): Promise<any | undefined> => {
|
||||
return await loginManager.GetOB11Config();
|
||||
};
|
||||
|
||||
const setOB11Config = async (config: any): Promise<boolean> => {
|
||||
const setOB11Config = async (config: OneBotConfig): Promise<boolean> => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
@@ -84,100 +118,74 @@ const setOB11Config = async (config: any): Promise<boolean> => {
|
||||
return await loginManager.SetOB11Config(config);
|
||||
};
|
||||
|
||||
const log = (message: string, data: any) => {
|
||||
console.log(message, data);
|
||||
const addToPanel = <T extends ConfigUnion>(configs: T[], key: ConfigKey) => {
|
||||
configs.forEach((config) => clientPanelData.push({ name: config.name, data: config, key: key }));
|
||||
};
|
||||
|
||||
const createPanel = (type: string, name: string, id: number): PanelData => {
|
||||
return {
|
||||
value: `${type}-${id}`,
|
||||
label: name,
|
||||
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));
|
||||
});
|
||||
const addConfigDataToPanel = (data: NetworkConfig) => {
|
||||
Object.entries(data).forEach(([key, configs]) => {
|
||||
if (key in defaultConfigs) {
|
||||
addToPanel(configs as ConfigUnion[], key as ConfigKey);
|
||||
}
|
||||
});
|
||||
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 () => {
|
||||
try {
|
||||
const userConfig = await getOB11Config();
|
||||
if (!userConfig) return;
|
||||
const mergedConfig = mergeOnebotConfigs(defaultOnebotConfig, userConfig);
|
||||
const networkConfig = mergedConfig.network;
|
||||
log('networkConfig:', networkConfig);
|
||||
const panels = generatePanels(networkConfig);
|
||||
log('panels:', panels);
|
||||
panelData.value = panels;
|
||||
if (panels.length > 0) {
|
||||
value.value = panels[0].value;
|
||||
}
|
||||
const mergedConfig = mergeOneBotConfigs(defaultOneBotConfigs, userConfig);
|
||||
addConfigDataToPanel(mergedConfig.network);
|
||||
} catch (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 = () => {
|
||||
newTab.value = { name: '', type: '' };
|
||||
newTab.value = { name: '', type: 'httpServers' };
|
||||
isDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const addTab = async () => {
|
||||
const { name, type } = newTab.value;
|
||||
if (!name || !type) return;
|
||||
const newPanel = createPanel(type, name, id);
|
||||
panelData.value.push(newPanel);
|
||||
id += 1;
|
||||
const defaultConfig = structuredClone(defaultConfigs[type]);
|
||||
clientPanelData.push({ name, data: defaultConfig, key: type });
|
||||
isDialogVisible.value = false;
|
||||
await nextTick(); // 确保 DOM 更新完成
|
||||
value.value = newPanel.value; // 强制重新渲染选项卡
|
||||
await nextTick();
|
||||
activeTab.value = clientPanelData.length - 1;
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
isDialogVisible.value = false;
|
||||
const removeTab = (payload: { value: string; index: number; e: PointerEvent }) => {
|
||||
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(() => {
|
||||
loadConfig();
|
||||
});
|
||||
|
@@ -22,21 +22,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface HttpClientConfig {
|
||||
url: string;
|
||||
messagePostFormat: string;
|
||||
reportSelfMessage: boolean;
|
||||
token: string;
|
||||
debug: boolean;
|
||||
}
|
||||
|
||||
const config = ref<HttpClientConfig>({
|
||||
url: '',
|
||||
messagePostFormat: '',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
debug: false,
|
||||
});
|
||||
import { defineProps } from 'vue';
|
||||
import { HttpClientConfig } from '../../../../src/onebot/config/config';
|
||||
defineProps<{
|
||||
config: HttpClientConfig;
|
||||
}>();
|
||||
</script>
|
||||
|
@@ -31,27 +31,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface HttpServerConfig {
|
||||
port: number;
|
||||
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,
|
||||
});
|
||||
import { defineProps } from 'vue';
|
||||
import { HttpServerConfig } from '../../../../src/onebot/config/config';
|
||||
defineProps<{
|
||||
config: HttpServerConfig;
|
||||
}>();
|
||||
</script>
|
||||
|
@@ -25,23 +25,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface WsClientConfig {
|
||||
url: string;
|
||||
messagePostFormat: string;
|
||||
reportSelfMessage: boolean;
|
||||
token: string;
|
||||
debug: boolean;
|
||||
heartInterval: number;
|
||||
}
|
||||
|
||||
const config = ref<WsClientConfig>({
|
||||
url: '',
|
||||
messagePostFormat: '',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
debug: false,
|
||||
heartInterval: 0,
|
||||
});
|
||||
import { defineProps } from 'vue';
|
||||
import { WebsocketClientConfig } from '../../../../src/onebot/config/config';
|
||||
defineProps<{
|
||||
config: WebsocketClientConfig;
|
||||
}>();
|
||||
</script>
|
||||
|
@@ -31,27 +31,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface WsServerConfig {
|
||||
host: string;
|
||||
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,
|
||||
});
|
||||
import { defineProps } from 'vue';
|
||||
import { WebsocketServerConfig } from '../../../../src/onebot/config/config';
|
||||
defineProps<{
|
||||
config: WebsocketServerConfig;
|
||||
}>();
|
||||
</script>
|
||||
|
@@ -6,7 +6,7 @@ export interface AdapterConfig {
|
||||
|
||||
const createDefaultAdapterConfig = <T extends AdapterConfig>(config: T): T => config;
|
||||
|
||||
const httpServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
export const httpServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'http-server',
|
||||
enable: false,
|
||||
port: 3000,
|
||||
@@ -20,7 +20,7 @@ const httpServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
});
|
||||
export type HttpServerConfig = typeof httpServerDefaultConfigs;
|
||||
|
||||
const httpClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
export const httpClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'http-client',
|
||||
enable: false,
|
||||
url: 'http://localhost:8080',
|
||||
@@ -31,7 +31,7 @@ const httpClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
});
|
||||
export type HttpClientConfig = typeof httpClientDefaultConfigs;
|
||||
|
||||
const websocketServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
export const websocketServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'websocket-server',
|
||||
enable: false,
|
||||
host: '0.0.0.0',
|
||||
@@ -45,7 +45,7 @@ const websocketServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
});
|
||||
export type WebsocketServerConfig = typeof websocketServerDefaultConfigs;
|
||||
|
||||
const websocketClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
export const websocketClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'websocket-client',
|
||||
enable: false,
|
||||
url: 'ws://localhost:8082',
|
||||
@@ -58,34 +58,35 @@ const websocketClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
export type WebsocketClientConfig = typeof websocketClientDefaultConfigs;
|
||||
|
||||
export interface NetworkConfig {
|
||||
httpServers: Array<HttpServerConfig>,
|
||||
httpClients: Array<HttpClientConfig>,
|
||||
websocketServers: Array<WebsocketServerConfig>,
|
||||
websocketClients: Array<WebsocketClientConfig>,
|
||||
};
|
||||
httpServers: Array<HttpServerConfig>;
|
||||
httpClients: Array<HttpClientConfig>;
|
||||
websocketServers: Array<WebsocketServerConfig>;
|
||||
websocketClients: Array<WebsocketClientConfig>;
|
||||
}
|
||||
|
||||
export function mergeConfigs<T extends AdapterConfig>(defaultConfig: T, userConfig: Partial<T>): T {
|
||||
return { ...defaultConfig, ...userConfig };
|
||||
}
|
||||
|
||||
export interface OnebotConfig {
|
||||
network: NetworkConfig;//网络配置
|
||||
musicSignUrl: string;//音乐签名地址
|
||||
enableLocalFile2Url: boolean
|
||||
export interface OneBotConfig {
|
||||
network: NetworkConfig; //网络配置
|
||||
musicSignUrl: string; //音乐签名地址
|
||||
enableLocalFile2Url: boolean;
|
||||
}
|
||||
|
||||
const createDefaultConfig = <T>(config: T): T => config;
|
||||
|
||||
export const defaultOnebotConfig = createDefaultConfig<OnebotConfig>({
|
||||
export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
|
||||
network: {
|
||||
httpServers: [],
|
||||
httpClients: [],
|
||||
websocketServers: [],
|
||||
websocketClients: [],
|
||||
},
|
||||
musicSignUrl: "",
|
||||
enableLocalFile2Url: false
|
||||
musicSignUrl: '',
|
||||
enableLocalFile2Url: false,
|
||||
});
|
||||
|
||||
export const mergeNetworkDefaultConfig = {
|
||||
httpServers: httpServerDefaultConfigs,
|
||||
httpClients: httpClientDefaultConfigs,
|
||||
@@ -95,7 +96,8 @@ export const 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 };
|
||||
|
||||
if (userConfig.network) {
|
||||
@@ -104,7 +106,9 @@ export function mergeOnebotConfigs(defaultConfig: OnebotConfig, userConfig: Part
|
||||
const userNetworkConfig = userConfig.network[key as keyof NetworkConfig];
|
||||
const defaultNetworkConfig = mergeNetworkDefaultConfig[key as NetworkConfigKeys];
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { ConfigBase } from '@/common/config-base';
|
||||
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) {
|
||||
super('onebot11', core, configPath, false);
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecal
|
||||
import { LRUCache } from '@/common/lru-cache';
|
||||
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
||||
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
||||
import { defaultOnebotConfig, mergeOnebotConfigs, OnebotConfig } from './config/config';
|
||||
import { defaultOneBotConfigs, mergeOneBotConfigs, OneBotConfig } from './config/config';
|
||||
import { OB11Message } from './types';
|
||||
|
||||
//OneBot实现类
|
||||
@@ -63,8 +63,8 @@ export class NapCatOneBot11Adapter {
|
||||
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
||||
this.core = core;
|
||||
this.context = context;
|
||||
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath,);
|
||||
this.configLoader.save(mergeOnebotConfigs(defaultOnebotConfig, this.configLoader.configData));
|
||||
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath);
|
||||
this.configLoader.save(mergeOneBotConfigs(defaultOneBotConfigs, this.configLoader.configData));
|
||||
this.apis = {
|
||||
GroupApi: new OneBotGroupApi(this, core),
|
||||
UserApi: new OneBotUserApi(this, core),
|
||||
@@ -75,7 +75,7 @@ export class NapCatOneBot11Adapter {
|
||||
this.actions = createActionMap(this, core);
|
||||
this.networkManager = new OB11NetworkManager();
|
||||
}
|
||||
async creatOneBotLog(ob11Config: OnebotConfig) {
|
||||
async creatOneBotLog(ob11Config: OneBotConfig) {
|
||||
let log = `[network] 配置加载\n`;
|
||||
for (const key of ob11Config.network.httpServers) {
|
||||
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
|
||||
@@ -95,10 +95,12 @@ export class NapCatOneBot11Adapter {
|
||||
const selfInfo = this.core.selfInfo;
|
||||
const ob11Config = this.configLoader.configData;
|
||||
|
||||
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid).then(user => {
|
||||
selfInfo.nick = user.nick;
|
||||
this.context.logger.setLogSelfInfo(selfInfo);
|
||||
}).catch(this.context.logger.logError.bind(this.context.logger));
|
||||
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid)
|
||||
.then((user) => {
|
||||
selfInfo.nick = user.nick;
|
||||
this.context.logger.setLogSelfInfo(selfInfo);
|
||||
})
|
||||
.catch(this.context.logger.logError.bind(this.context.logger));
|
||||
|
||||
const serviceInfo = await this.creatOneBotLog(ob11Config);
|
||||
this.context.logger.log(`[Notice] [OneBot11] ${serviceInfo}`);
|
||||
@@ -106,30 +108,46 @@ export class NapCatOneBot11Adapter {
|
||||
// //创建NetWork服务
|
||||
for (const key of ob11Config.network.httpServers) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(new OB11PassiveHttpAdapter(
|
||||
key.name, key.port, key.token, this.core, this.actions,
|
||||
));
|
||||
this.networkManager.registerAdapter(
|
||||
new OB11PassiveHttpAdapter(key.name, key.port, key.token, this.core, this.actions)
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const key of ob11Config.network.httpClients) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(new OB11ActiveHttpAdapter(
|
||||
key.name, key.url, key.token, this.core, this,
|
||||
));
|
||||
this.networkManager.registerAdapter(
|
||||
new OB11ActiveHttpAdapter(key.name, key.url, key.token, this.core, this)
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const key of ob11Config.network.websocketServers) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(new OB11PassiveWebSocketAdapter(
|
||||
key.name, key.host, key.port, key.heartInterval, key.token, this.core, this.actions,
|
||||
));
|
||||
this.networkManager.registerAdapter(
|
||||
new OB11PassiveWebSocketAdapter(
|
||||
key.name,
|
||||
key.host,
|
||||
key.port,
|
||||
key.heartInterval,
|
||||
key.token,
|
||||
this.core,
|
||||
this.actions
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const key of ob11Config.network.websocketClients) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(new OB11ActiveWebSocketAdapter(
|
||||
key.name, key.url, 5000, key.heartInterval, key.token, this.core, this.actions,
|
||||
));
|
||||
this.networkManager.registerAdapter(
|
||||
new OB11ActiveWebSocketAdapter(
|
||||
key.name,
|
||||
key.url,
|
||||
5000,
|
||||
key.heartInterval,
|
||||
key.token,
|
||||
this.core,
|
||||
this.actions
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
await this.networkManager.openAllAdapters();
|
||||
@@ -150,7 +168,9 @@ export class NapCatOneBot11Adapter {
|
||||
|
||||
initRecentContactListener() {
|
||||
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) => {
|
||||
if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
// log("recent contact", msgList, arg0, arg1);
|
||||
@@ -201,7 +221,6 @@ export class NapCatOneBot11Adapter {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// // check difference in passive websocket (Ws)
|
||||
// if (prev.ws.enable !== 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[] } {
|
||||
const added = now.filter(item => !prev.includes(item));
|
||||
const removed = prev.filter(item => !now.includes(item));
|
||||
private findDifference<T>(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) => {
|
||||
this.apis.MsgApi.parseSysMessage(msg).then((event) => {
|
||||
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')));
|
||||
this.apis.MsgApi.parseSysMessage(msg)
|
||||
.then((event) => {
|
||||
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);
|
||||
this.context.logger.log(`[Notice] [输入状态] ${uin} ${data.statusText}`);
|
||||
await this.networkManager.emitEvent(new OB11InputStatusEvent(
|
||||
this.core,
|
||||
parseInt(uin),
|
||||
data.eventType,
|
||||
data.statusText,
|
||||
));
|
||||
await this.networkManager.emitEvent(
|
||||
new OB11InputStatusEvent(this.core, parseInt(uin), data.eventType, data.statusText)
|
||||
);
|
||||
};
|
||||
|
||||
msgListener.onRecvMsg = async msg => {
|
||||
msgListener.onRecvMsg = async (msg) => {
|
||||
for (const m of msg) {
|
||||
if (this.bootTime > parseInt(m.msgTime)) {
|
||||
this.context.logger.logDebug(`消息时间${m.msgTime}早于启动时间${this.bootTime},忽略上报`);
|
||||
@@ -279,50 +304,54 @@ export class NapCatOneBot11Adapter {
|
||||
peerUid: m.peerUid,
|
||||
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 recallMsgs = new LRUCache<string, boolean>(100);
|
||||
msgListener.onAddSendMsg = async msg => {
|
||||
msgListener.onAddSendMsg = async (msg) => {
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
|
||||
msgIdSend.put(msg.msgId, 0);
|
||||
}
|
||||
};
|
||||
msgListener.onMsgInfoListUpdate = async msgList => {
|
||||
this.emitRecallMsg(msgList, recallMsgs)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
|
||||
for (const msg of msgList.filter(e => e.senderUin == this.core.selfInfo.uin)) {
|
||||
msgListener.onMsgInfoListUpdate = async (msgList) => {
|
||||
this.emitRecallMsg(msgList, recallMsgs).catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)
|
||||
);
|
||||
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) {
|
||||
msgIdSend.put(msg.msgId, 1);
|
||||
// 完成后再post
|
||||
msg.id = MessageUnique.createUniqueMsgId({
|
||||
chatType: msg.chatType,
|
||||
peerUid: msg.peerUid,
|
||||
guildId: '',
|
||||
}, msg.msgId);
|
||||
msg.id = MessageUnique.createUniqueMsgId(
|
||||
{
|
||||
chatType: msg.chatType,
|
||||
peerUid: msg.peerUid,
|
||||
guildId: '',
|
||||
},
|
||||
msg.msgId
|
||||
);
|
||||
this.emitMsg(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
msgListener.onKickedOffLine = async (kick) => {
|
||||
const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
|
||||
this.networkManager.emitEvent(event)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理Bot掉线失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(event)
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('处理Bot掉线失败', e));
|
||||
};
|
||||
this.context.session.getMsgService().addKernelMsgListener(
|
||||
proxiedListenerOf(msgListener, this.context.logger),
|
||||
);
|
||||
this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
|
||||
}
|
||||
|
||||
private initBuddyListener() {
|
||||
const buddyListener = new NodeIKernelBuddyListener();
|
||||
|
||||
buddyListener.onBuddyReqChange = async reqs => {
|
||||
buddyListener.onBuddyReqChange = async (reqs) => {
|
||||
this.core.apis.FriendApi.clearBuddyReqUnreadCnt();
|
||||
for (let i = 0; i < reqs.unreadNums; i++) {
|
||||
const req = reqs.buddyReqs[i];
|
||||
@@ -331,21 +360,23 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
try {
|
||||
const requesterUin = await this.core.apis.UserApi.getUinByUidV2(req.friendUid);
|
||||
await this.networkManager.emitEvent(new OB11FriendRequestEvent(
|
||||
this.core,
|
||||
+requesterUin,
|
||||
req.extWords,
|
||||
req.friendUid + '|' + req.reqTime,
|
||||
));
|
||||
await this.networkManager.emitEvent(
|
||||
new OB11FriendRequestEvent(
|
||||
this.core,
|
||||
+requesterUin,
|
||||
req.extWords,
|
||||
req.friendUid + '|' + req.reqTime
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
this.context.logger.logDebug('获取加好友者QQ号失败', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.context.session.getBuddyService().addKernelBuddyListener(
|
||||
proxiedListenerOf(buddyListener, this.context.logger),
|
||||
);
|
||||
this.context.session
|
||||
.getBuddyService()
|
||||
.addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
|
||||
}
|
||||
|
||||
private initGroupListener() {
|
||||
@@ -354,11 +385,13 @@ export class NapCatOneBot11Adapter {
|
||||
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
|
||||
//console.log('ob11 onGroupNotifiesUpdated', notifies[0]);
|
||||
await this.core.apis.GroupApi.clearGroupNotifiesUnreadCount(false);
|
||||
if (![
|
||||
GroupNotifyMsgType.SET_ADMIN,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
|
||||
].includes(notifies[0]?.type)) {
|
||||
if (
|
||||
![
|
||||
GroupNotifyMsgType.SET_ADMIN,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
|
||||
].includes(notifies[0]?.type)
|
||||
) {
|
||||
for (const notify of notifies) {
|
||||
const notifyTime = parseInt(notify.seq) / 1000 / 1000;
|
||||
// log(`群通知时间${notifyTime}`, `启动时间${this.bootTime}`);
|
||||
@@ -369,12 +402,17 @@ export class NapCatOneBot11Adapter {
|
||||
const flag = notify.group.groupCode + '|' + notify.seq + '|' + notify.type;
|
||||
this.context.logger.logDebug('收到群通知', notify);
|
||||
|
||||
if ([
|
||||
GroupNotifyMsgType.SET_ADMIN,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
|
||||
].includes(notify.type)) {
|
||||
const member1 = await this.core.apis.GroupApi.getGroupMember(notify.group.groupCode, notify.user1.uid);
|
||||
if (
|
||||
[
|
||||
GroupNotifyMsgType.SET_ADMIN,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
|
||||
].includes(notify.type)
|
||||
) {
|
||||
const member1 = await this.core.apis.GroupApi.getGroupMember(
|
||||
notify.group.groupCode,
|
||||
notify.user1.uid
|
||||
);
|
||||
this.context.logger.logDebug('有管理员变动通知');
|
||||
// refreshGroupMembers(notify.group.groupCode).then();
|
||||
this.context.logger.logDebug('开始获取变动的管理员');
|
||||
@@ -387,16 +425,28 @@ export class NapCatOneBot11Adapter {
|
||||
[
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
|
||||
].includes(notify.type) ? 'unset' : 'set',
|
||||
].includes(notify.type)
|
||||
? 'unset'
|
||||
: 'set'
|
||||
);
|
||||
this.networkManager.emitEvent(groupAdminNoticeEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupAdminNoticeEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)
|
||||
);
|
||||
} 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);
|
||||
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 subType: GroupDecreaseSubType = 'leave';
|
||||
if (notify.user2.uid) {
|
||||
@@ -412,17 +462,21 @@ export class NapCatOneBot11Adapter {
|
||||
parseInt(notify.group.groupCode),
|
||||
parseInt(member1Uin),
|
||||
parseInt(operatorId),
|
||||
subType,
|
||||
subType
|
||||
);
|
||||
this.networkManager.emitEvent(groupDecreaseEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群成员退出失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupDecreaseEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理群成员退出失败', e)
|
||||
);
|
||||
// notify.status == 1 表示未处理 2表示处理完成
|
||||
} else if ([
|
||||
GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
|
||||
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
|
||||
} else if (
|
||||
[GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS].includes(notify.type) &&
|
||||
notify.status == GroupNotifyMsgStatus.KUNHANDLE
|
||||
) {
|
||||
this.context.logger.logDebug('有加群请求');
|
||||
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))) {
|
||||
requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin;
|
||||
}
|
||||
@@ -432,14 +486,24 @@ export class NapCatOneBot11Adapter {
|
||||
parseInt(requestUin),
|
||||
'add',
|
||||
notify.postscript,
|
||||
flag,
|
||||
flag
|
||||
);
|
||||
this.networkManager.emitEvent(groupRequestEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理加群请求失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupRequestEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理加群请求失败', 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}`);
|
||||
const groupInviteEvent = new OB11GroupRequestEvent(
|
||||
this.core,
|
||||
@@ -447,11 +511,17 @@ export class NapCatOneBot11Adapter {
|
||||
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user2.uid)),
|
||||
'invite',
|
||||
notify.postscript,
|
||||
flag,
|
||||
flag
|
||||
);
|
||||
this.networkManager.emitEvent(groupInviteEvent)
|
||||
.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.networkManager
|
||||
.emitEvent(groupInviteEvent)
|
||||
.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}`);
|
||||
const groupInviteEvent = new OB11GroupRequestEvent(
|
||||
this.core,
|
||||
@@ -459,10 +529,13 @@ export class NapCatOneBot11Adapter {
|
||||
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)),
|
||||
'add',
|
||||
notify.postscript,
|
||||
flag,
|
||||
flag
|
||||
);
|
||||
this.networkManager.emitEvent(groupInviteEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupInviteEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理邀请本人加群失败', e)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,88 +554,102 @@ export class NapCatOneBot11Adapter {
|
||||
this.core,
|
||||
parseInt(groupCode),
|
||||
parseInt(member.uin),
|
||||
member.role === GroupMemberRole.admin ? 'set' : 'unset',
|
||||
member.role === GroupMemberRole.admin ? 'set' : 'unset'
|
||||
);
|
||||
this.networkManager.emitEvent(groupAdminNoticeEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupAdminNoticeEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理群管理员变动失败', e)
|
||||
);
|
||||
existMember.isChangeRole = false;
|
||||
this.context.logger.logDebug.bind(this.context.logger)('群管理员变动处理完毕');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.context.session.getGroupService().addKernelGroupListener(
|
||||
proxiedListenerOf(groupListener, this.context.logger),
|
||||
);
|
||||
this.context.session
|
||||
.getGroupService()
|
||||
.addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
|
||||
}
|
||||
|
||||
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.apis.MsgApi.parseMessageV2(message).then((ob11Msg) => {
|
||||
if (!ob11Msg) return;
|
||||
const isSelfMsg = ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin || ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
|
||||
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
||||
const msgMap: Map<string, OB11Message> = new Map();
|
||||
const enable_client: string[] = [];
|
||||
network.flat().filter(e => e.enable).map(e => {
|
||||
enable_client.push(e.name);
|
||||
if (e.messagePostFormat == 'string') {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.stringMsg));
|
||||
} else {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg));
|
||||
}
|
||||
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;
|
||||
this.apis.MsgApi.parseMessageV2(message)
|
||||
.then((ob11Msg) => {
|
||||
if (!ob11Msg) return;
|
||||
const isSelfMsg =
|
||||
ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin ||
|
||||
ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
|
||||
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
||||
const msgMap: Map<string, OB11Message> = new Map();
|
||||
const enable_client: string[] = [];
|
||||
network
|
||||
.flat()
|
||||
.filter((e) => e.enable)
|
||||
.map((e) => {
|
||||
enable_client.push(e.name);
|
||||
if (e.messagePostFormat == 'string') {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.stringMsg));
|
||||
} else {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg));
|
||||
}
|
||||
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) {
|
||||
return;
|
||||
|
||||
}
|
||||
const notreportSelf_network = network.flat().filter(e => e.enable && !e.reportSelfMessage);
|
||||
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);
|
||||
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e));
|
||||
this.networkManager.emitEventByNames(msgMap);
|
||||
})
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e));
|
||||
|
||||
this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => {
|
||||
if (groupEvent) {
|
||||
// log("post group event", groupEvent);
|
||||
this.networkManager.emitEvent(groupEvent);
|
||||
}
|
||||
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructGroupEvent error: ', e));
|
||||
this.apis.GroupApi.parseGroupEvent(message)
|
||||
.then((groupEvent) => {
|
||||
if (groupEvent) {
|
||||
// log("post group event", groupEvent);
|
||||
this.networkManager.emitEvent(groupEvent);
|
||||
}
|
||||
})
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructGroupEvent error: ', e));
|
||||
|
||||
this.apis.MsgApi.parsePrivateMsgEvent(message).then(privateEvent => {
|
||||
if (privateEvent) {
|
||||
// log("post private event", privateEvent);
|
||||
this.networkManager.emitEvent(privateEvent);
|
||||
}
|
||||
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructPrivateEvent error: ', e));
|
||||
this.apis.MsgApi.parsePrivateMsgEvent(message)
|
||||
.then((privateEvent) => {
|
||||
if (privateEvent) {
|
||||
// log("post private event", privateEvent);
|
||||
this.networkManager.emitEvent(privateEvent);
|
||||
}
|
||||
})
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('constructPrivateEvent error: ', e));
|
||||
}
|
||||
private async emitRecallMsg(msgList: RawMessage[], cache: LRUCache<string, boolean>) {
|
||||
for (const message of msgList) {
|
||||
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
|
||||
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);
|
||||
// 撤回消息上报
|
||||
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
|
||||
@@ -573,10 +660,13 @@ export class NapCatOneBot11Adapter {
|
||||
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
|
||||
this.core,
|
||||
+message.senderUin,
|
||||
oriMessageId,
|
||||
oriMessageId
|
||||
);
|
||||
this.networkManager.emitEvent(friendRecallEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理好友消息撤回失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(friendRecallEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理好友消息撤回失败', e)
|
||||
);
|
||||
} else if (message.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
let operatorId = message.senderUin;
|
||||
for (const element of message.elements) {
|
||||
@@ -592,8 +682,9 @@ export class NapCatOneBot11Adapter {
|
||||
+operatorId,
|
||||
oriMessageId
|
||||
);
|
||||
this.networkManager.emitEvent(groupRecallEvent)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e));
|
||||
this.networkManager
|
||||
.emitEvent(groupRecallEvent)
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { RequestHandler } from 'express';
|
||||
import { WebUiDataRuntime } from '../helper/Data';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { OnebotConfig } from '@/onebot/config/config';
|
||||
import { OneBotConfig } from '@/onebot/config/config';
|
||||
import { resolve } from 'node:path';
|
||||
import { webUiPathWrapper } from '@/webui';
|
||||
|
||||
const isEmpty = (data: any) =>
|
||||
data === undefined || data === null || data === '';
|
||||
const isEmpty = (data: any) => data === undefined || data === null || data === '';
|
||||
export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
|
||||
const isLogin = await WebUiDataRuntime.getQQLoginStatus();
|
||||
if (!isLogin) {
|
||||
@@ -19,15 +18,15 @@ export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
|
||||
const uin = await WebUiDataRuntime.getQQLoginUin();
|
||||
const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`);
|
||||
//console.log(configFilePath);
|
||||
let data: OnebotConfig;
|
||||
let data: OneBotConfig;
|
||||
try {
|
||||
data = JSON.parse(
|
||||
existsSync(configFilePath)
|
||||
? readFileSync(configFilePath).toString()
|
||||
: readFileSync(resolve(webUiPathWrapper.configPath, './onebot11.json')).toString(),
|
||||
: readFileSync(resolve(webUiPathWrapper.configPath, './onebot11.json')).toString()
|
||||
);
|
||||
} catch (e) {
|
||||
data = {} as OnebotConfig;
|
||||
data = {} as OneBotConfig;
|
||||
res.send({
|
||||
code: -1,
|
||||
message: 'Config Get Error',
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { OnebotConfig } from '@/onebot/config/config';
|
||||
import { OneBotConfig } from '@/onebot/config/config';
|
||||
|
||||
interface LoginRuntimeType {
|
||||
LoginCurrentTime: number;
|
||||
@@ -7,9 +7,9 @@ interface LoginRuntimeType {
|
||||
QQQRCodeURL: string;
|
||||
QQLoginUin: string;
|
||||
NapCatHelper: {
|
||||
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean, message: string }>;
|
||||
onOB11ConfigChanged: (ob11: OnebotConfig) => Promise<void>;
|
||||
QQLoginList: string[]
|
||||
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>;
|
||||
onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>;
|
||||
QQLoginList: string[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,62 +31,62 @@ const LoginRuntime: LoginRuntimeType = {
|
||||
};
|
||||
|
||||
export const WebUiDataRuntime = {
|
||||
checkLoginRate: async function(RateLimit: number): Promise<boolean> {
|
||||
checkLoginRate: async function (RateLimit: number): Promise<boolean> {
|
||||
LoginRuntime.LoginCurrentRate++;
|
||||
//console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime);
|
||||
if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) {
|
||||
LoginRuntime.LoginCurrentRate = 0;//超出时间重置限速
|
||||
LoginRuntime.LoginCurrentRate = 0; //超出时间重置限速
|
||||
LoginRuntime.LoginCurrentTime = Date.now();
|
||||
return true;
|
||||
}
|
||||
return LoginRuntime.LoginCurrentRate <= RateLimit;
|
||||
},
|
||||
|
||||
getQQLoginStatus: async function(): Promise<boolean> {
|
||||
getQQLoginStatus: async function (): Promise<boolean> {
|
||||
return LoginRuntime.QQLoginStatus;
|
||||
},
|
||||
|
||||
setQQLoginStatus: async function(status: boolean): Promise<void> {
|
||||
setQQLoginStatus: async function (status: boolean): Promise<void> {
|
||||
LoginRuntime.QQLoginStatus = status;
|
||||
},
|
||||
|
||||
setQQLoginQrcodeURL: async function(url: string): Promise<void> {
|
||||
setQQLoginQrcodeURL: async function (url: string): Promise<void> {
|
||||
LoginRuntime.QQQRCodeURL = url;
|
||||
},
|
||||
|
||||
getQQLoginQrcodeURL: async function(): Promise<string> {
|
||||
getQQLoginQrcodeURL: async function (): Promise<string> {
|
||||
return LoginRuntime.QQQRCodeURL;
|
||||
},
|
||||
|
||||
setQQLoginUin: async function(uin: string): Promise<void> {
|
||||
setQQLoginUin: async function (uin: string): Promise<void> {
|
||||
LoginRuntime.QQLoginUin = uin;
|
||||
},
|
||||
|
||||
getQQLoginUin: async function(): Promise<string> {
|
||||
getQQLoginUin: async function (): Promise<string> {
|
||||
return LoginRuntime.QQLoginUin;
|
||||
},
|
||||
|
||||
getQQQuickLoginList: async function(): Promise<any[]> {
|
||||
getQQQuickLoginList: async function (): Promise<any[]> {
|
||||
return LoginRuntime.NapCatHelper.QQLoginList;
|
||||
},
|
||||
|
||||
setQQQuickLoginList: async function(list: string[]): Promise<void> {
|
||||
setQQQuickLoginList: async function (list: string[]): Promise<void> {
|
||||
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;
|
||||
},
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
setOnOB11ConfigChanged: async function(func: (ob11: OnebotConfig) => Promise<void>): Promise<void> {
|
||||
setOnOB11ConfigChanged: async function (func: (ob11: OneBotConfig) => Promise<void>): Promise<void> {
|
||||
LoginRuntime.NapCatHelper.onOB11ConfigChanged = func;
|
||||
},
|
||||
|
||||
setOB11Config: async function(ob11: OnebotConfig): Promise<void> {
|
||||
setOB11Config: async function (ob11: OneBotConfig): Promise<void> {
|
||||
await LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
|
||||
},
|
||||
};
|
||||
|
Reference in New Issue
Block a user