mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
901828f5a6 | ||
![]() |
2a4b0cbc09 | ||
![]() |
c5434efd56 | ||
![]() |
b73f283095 | ||
![]() |
24ef54f01c | ||
![]() |
bff3b85337 | ||
![]() |
811d9a7237 | ||
![]() |
a764cb8dc2 | ||
![]() |
9204b9b286 | ||
![]() |
da94faa9bb | ||
![]() |
4b53e9a895 | ||
![]() |
f5db96187b | ||
![]() |
857b191b03 | ||
![]() |
09014d1ab5 | ||
![]() |
7557b71869 | ||
![]() |
9c4751794f | ||
![]() |
d07187bd5d | ||
![]() |
2c6a6ba440 | ||
![]() |
4592bf7817 | ||
![]() |
afd6d450a0 |
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.3.5",
|
||||
"version": "4.4.1",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -11,85 +11,66 @@
|
||||
<t-divider align="right">
|
||||
<t-button @click="addConfig()">
|
||||
<template #icon><add-icon /></template>
|
||||
添加配置</t-button
|
||||
>
|
||||
添加配置</t-button>
|
||||
</t-divider>
|
||||
</div>
|
||||
<div v-if="loadPage" ref="setting" class="setting">
|
||||
<t-tabs ref="tabsRef" :style="{ width: tabsWidth + 'px' }" default-value="all" @change="selectType">
|
||||
<t-tab-panel value="all" label="全部"></t-tab-panel>
|
||||
<t-tab-panel value="httpServers" label="HTTP 服务器"></t-tab-panel>
|
||||
<t-tab-panel value="httpSseServers" label="HTTP SSE 服务器"></t-tab-panel>
|
||||
<t-tab-panel value="httpClients" label="HTTP 客户端"></t-tab-panel>
|
||||
<t-tab-panel value="websocketServers" label="WebSocket 服务器"></t-tab-panel>
|
||||
<t-tab-panel value="websocketClients" label="WebSocket 客户端"></t-tab-panel>
|
||||
|
||||
</t-tabs>
|
||||
</div>
|
||||
<t-loading attach="#alice" :loading="!loadPage" :showOverlay="false">
|
||||
<div id="alice" v-if="!loadPage" style="height: 80vh;position: relative" ></div>
|
||||
<div id="alice" v-if="!loadPage" style="height: 80vh;position: relative"></div>
|
||||
</t-loading>
|
||||
<div v-if="loadPage" class="card-box" :style="{ width: tabsWidth + 'px' }">
|
||||
<div class="setting-box" :style="{ maxHeight: cardHeight + 'px' }" v-if="cardConfig.length > 0">
|
||||
<div v-for="(item, index) in cardConfig" :key="index">
|
||||
<t-card
|
||||
:title="item.name"
|
||||
:description="item.type"
|
||||
:style="{ width: cardWidth + 'px' }"
|
||||
:header-bordered="true"
|
||||
class="setting-card"
|
||||
>
|
||||
<t-card :title="item.name" :description="item.type" :style="{ width: cardWidth + 'px' }"
|
||||
:header-bordered="true" class="setting-card">
|
||||
<template #actions>
|
||||
<t-space>
|
||||
<edit2-icon size="20px" @click="editConfig(item)"></edit2-icon>
|
||||
<t-popconfirm content="确认删除" @confirm="delConfig(item)">
|
||||
<t-popconfirm content="确认删除" @confirm="delConfig(item)">
|
||||
<delete-icon size="20px"></delete-icon>
|
||||
</t-popconfirm>
|
||||
</t-space>
|
||||
</template>
|
||||
<div class="setting-content">
|
||||
<t-card
|
||||
class="card-address"
|
||||
:style="{
|
||||
borderLeft:
|
||||
'7px solid ' + (item.enable ? 'var(--td-success-color)' : 'var(--td-error-color)'),
|
||||
}"
|
||||
>
|
||||
<t-card class="card-address" :style="{
|
||||
borderLeft:
|
||||
'7px solid ' + (item.enable ? 'var(--td-success-color)' : 'var(--td-error-color)'),
|
||||
}">
|
||||
<div class="local-box" v-if="item.host && item.port">
|
||||
<server-filled-icon class="local-icon" size="20px" @click="toggleProperty(item, 'enable')"></server-filled-icon>
|
||||
<server-filled-icon class="local-icon" size="20px"
|
||||
@click="toggleProperty(item, 'enable')"></server-filled-icon>
|
||||
<strong class="local">{{ item.host }}:{{ item.port }}</strong>
|
||||
<copy-icon
|
||||
class="copy-icon"
|
||||
size="20px"
|
||||
@click="copyText(item.host + ':' + item.port)"
|
||||
></copy-icon>
|
||||
<copy-icon class="copy-icon" size="20px"
|
||||
@click="copyText(item.host + ':' + item.port)"></copy-icon>
|
||||
</div>
|
||||
<div class="local-box" v-if="item.url">
|
||||
<server-filled-icon class="local-icon" size="20px" @click="toggleProperty(item, 'enable')"></server-filled-icon>
|
||||
<server-filled-icon class="local-icon" size="20px"
|
||||
@click="toggleProperty(item, 'enable')"></server-filled-icon>
|
||||
<strong class="local">{{ item.url }}</strong>
|
||||
<copy-icon class="copy-icon" size="20px" @click="copyText(item.url)"></copy-icon>
|
||||
</div>
|
||||
</t-card>
|
||||
<t-collapse :default-value="[0]" expand-mutex style="margin-top: 10px" class="info-coll">
|
||||
<t-collapse-panel header="基础信息">
|
||||
<t-descriptions
|
||||
size="small"
|
||||
:layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info"
|
||||
>
|
||||
<t-descriptions size="small" :layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info">
|
||||
<t-descriptions-item v-if="item.token" label="连接密钥">
|
||||
<div v-if="mediumScreen.matches || largeScreen.matches" class="token-view">
|
||||
<span>{{ showToken ? item.token : '******' }}</span>
|
||||
<browse-icon
|
||||
class="browse-icon"
|
||||
v-if="showToken"
|
||||
size="18px"
|
||||
@click="showToken = false"
|
||||
></browse-icon>
|
||||
<browse-off-icon
|
||||
class="browse-icon"
|
||||
v-else
|
||||
size="18px"
|
||||
@click="showToken = true"
|
||||
></browse-off-icon>
|
||||
<browse-icon class="browse-icon" v-if="showToken" size="18px"
|
||||
@click="showToken = false"></browse-icon>
|
||||
<browse-off-icon class="browse-icon" v-else size="18px"
|
||||
@click="showToken = true"></browse-off-icon>
|
||||
</div>
|
||||
<div v-else>
|
||||
<t-popup :showArrow="true" trigger="click">
|
||||
@@ -106,60 +87,36 @@
|
||||
</t-descriptions>
|
||||
</t-collapse-panel>
|
||||
<t-collapse-panel header="状态信息">
|
||||
<t-descriptions
|
||||
size="small"
|
||||
:layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info"
|
||||
>
|
||||
<t-descriptions size="small" :layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info">
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('debug')" label="调试日志">
|
||||
<t-tag
|
||||
:class="item.debug ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'debug')"
|
||||
>
|
||||
{{ item.debug ? '开启' : '关闭' }}</t-tag
|
||||
>
|
||||
<t-tag :class="item.debug ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'debug')">
|
||||
{{ item.debug ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item
|
||||
v-if="item.hasOwnProperty('enableWebsocket')"
|
||||
label="Websocket 功能"
|
||||
>
|
||||
<t-tag
|
||||
:class="item.enableWebsocket ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'enableWebsocket')"
|
||||
>
|
||||
{{ item.enableWebsocket ? '启用' : '禁用' }}</t-tag
|
||||
>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableWebsocket')"
|
||||
label="Websocket 功能">
|
||||
<t-tag :class="item.enableWebsocket ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'enableWebsocket')">
|
||||
{{ item.enableWebsocket ? '启用' : '禁用' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item
|
||||
v-if="item.hasOwnProperty('enableCors')"
|
||||
label="跨域放行"
|
||||
>
|
||||
<t-tag :class="item.enableCors ? 'tag-item-on' : 'tag-item-off'" @click="toggleProperty(item, 'enableCors')">
|
||||
{{ item.enableCors ? '开启' : '关闭' }}</t-tag
|
||||
>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableCors')" label="跨域放行">
|
||||
<t-tag :class="item.enableCors ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'enableCors')">
|
||||
{{ item.enableCors ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item
|
||||
v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="上报自身消息"
|
||||
>
|
||||
<t-tag
|
||||
:class="item.reportSelfMessage ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'reportSelfMessage')"
|
||||
>
|
||||
{{ item.reportSelfMessage ? '开启' : '关闭' }}</t-tag
|
||||
>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="上报自身消息">
|
||||
<t-tag :class="item.reportSelfMessage ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'reportSelfMessage')">
|
||||
{{ item.reportSelfMessage ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item
|
||||
v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="强制推送事件"
|
||||
>
|
||||
<t-tag
|
||||
class="tag-item"
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="强制推送事件">
|
||||
<t-tag class="tag-item"
|
||||
:class="item.enableForcePushEvent ? 'tag-item-on' : 'tag-item-off'"
|
||||
@click="toggleProperty(item, 'enableForcePushEvent')"
|
||||
>
|
||||
{{ item.enableForcePushEvent ? '开启' : '关闭' }}</t-tag
|
||||
>
|
||||
@click="toggleProperty(item, 'enableForcePushEvent')">
|
||||
{{ item.enableForcePushEvent ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
</t-descriptions>
|
||||
</t-collapse-panel>
|
||||
@@ -173,42 +130,27 @@
|
||||
<t-empty class="card-none" title="暂无网络配置"> </t-empty>
|
||||
</t-card>
|
||||
</div>
|
||||
<t-dialog
|
||||
v-model:visible="visibleBody"
|
||||
:header="dialogTitle"
|
||||
:destroy-on-close="true"
|
||||
:show-in-attached-element="true"
|
||||
:on-confirm="saveConfig"
|
||||
class=".t-dialog__ctx .t-dialog__position"
|
||||
>
|
||||
<t-dialog v-model:visible="visibleBody" :header="dialogTitle" :destroy-on-close="true"
|
||||
:show-in-attached-element="true" :on-confirm="saveConfig" class=".t-dialog__ctx .t-dialog__position">
|
||||
<div slot="body" class="dialog-body">
|
||||
<t-form ref="form" :data="newTab" labelAlign="left" :model="newTab">
|
||||
<t-form-item
|
||||
style="text-align: left"
|
||||
:rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]"
|
||||
label="名称"
|
||||
name="name"
|
||||
>
|
||||
<t-form-item style="text-align: left" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]"
|
||||
label="名称" name="name">
|
||||
<t-input v-model="newTab.name" />
|
||||
</t-form-item>
|
||||
<t-form-item
|
||||
style="text-align: left"
|
||||
:rules="[{ required: true, message: '请选择类型', trigger: 'change' }]"
|
||||
label="类型"
|
||||
name="type"
|
||||
>
|
||||
<t-form-item style="text-align: left" :rules="[{ required: true, message: '请选择类型', trigger: 'change' }]"
|
||||
label="类型" name="type">
|
||||
<t-select v-model="newTab.type" @change="onloadDefault">
|
||||
<t-option value="httpServers">HTTP 服务器</t-option>
|
||||
<t-option value="httpSseServers">HTTP SSE 服务器</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>
|
||||
<div>
|
||||
<component
|
||||
:is="resolveDynamicComponent(getComponent(newTab.type as ComponentKey))"
|
||||
:config="newTab.data"
|
||||
/>
|
||||
<component :is="resolveDynamicComponent(getComponent(newTab.type as ComponentKey))"
|
||||
:config="newTab.data" />
|
||||
</div>
|
||||
</t-form>
|
||||
</div>
|
||||
@@ -226,12 +168,10 @@ import {
|
||||
BrowseIcon,
|
||||
Wifi1Icon,
|
||||
} from 'tdesign-icons-vue-next';
|
||||
import { onMounted, onUnmounted, ref, resolveDynamicComponent, watch } from 'vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
import {
|
||||
mergeNetworkDefaultConfig,
|
||||
mergeOneBotConfigs,
|
||||
NetworkConfig,
|
||||
loadConfig as loadConfigOnebot,
|
||||
NetworkAdapterConfig,
|
||||
NetworkConfigKey,
|
||||
OneBotConfig,
|
||||
} from '../../../src/onebot/config/config';
|
||||
import HttpServerComponent from '@/pages/network/HttpServerComponent.vue';
|
||||
@@ -240,6 +180,9 @@ import WebsocketServerComponent from '@/pages/network/WebsocketServerComponent.v
|
||||
import WebsocketClientComponent from '@/pages/network/WebsocketClientComponent.vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
import { onMounted, onUnmounted, ref, watch, resolveDynamicComponent } from 'vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
import HttpSseServerComponent from './network/HttpSseServerComponent.vue';
|
||||
|
||||
const showToken = ref<boolean>(false);
|
||||
const infoOneCol = ref<boolean>(true);
|
||||
@@ -256,16 +199,17 @@ const visibleBody = ref<boolean>(false);
|
||||
const newTab = ref<{ name: string; data: any; type: string }>({ name: '', data: {}, type: '' });
|
||||
const dialogTitle = ref<string>('');
|
||||
|
||||
type ComponentKey = keyof typeof mergeNetworkDefaultConfig;
|
||||
|
||||
type ComponentKey = Exclude<NetworkConfigKey, 'plugins'>
|
||||
const componentMap: Record<
|
||||
ComponentKey,
|
||||
| typeof HttpServerComponent
|
||||
| typeof HttpClientComponent
|
||||
| typeof WebsocketServerComponent
|
||||
| typeof WebsocketClientComponent
|
||||
| typeof HttpSseServerComponent
|
||||
> = {
|
||||
httpServers: HttpServerComponent,
|
||||
httpSseServers: HttpSseServerComponent,
|
||||
httpClients: HttpClientComponent,
|
||||
websocketServers: WebsocketServerComponent,
|
||||
websocketClients: WebsocketClientComponent,
|
||||
@@ -276,9 +220,10 @@ const operateType = ref<string>('');
|
||||
//配置项索引
|
||||
const configIndex = ref<number>(0);
|
||||
//保存时所用数据
|
||||
const networkConfig: NetworkConfig & { [key: string]: any } = {
|
||||
const networkConfig: { [key: string]: any } = {
|
||||
websocketClients: [],
|
||||
websocketServers: [],
|
||||
httpSseServers: [],
|
||||
httpClients: [],
|
||||
httpServers: [],
|
||||
};
|
||||
@@ -289,6 +234,7 @@ const WebConfg = ref(
|
||||
['all', []],
|
||||
['httpServers', []],
|
||||
['httpClients', []],
|
||||
['httpSseServers', []],
|
||||
['websocketServers', []],
|
||||
['websocketClients', []],
|
||||
])
|
||||
@@ -296,6 +242,7 @@ const WebConfg = ref(
|
||||
const typeCh: Record<ComponentKey, string> = {
|
||||
httpServers: 'HTTP 服务器',
|
||||
httpClients: 'HTTP 客户端',
|
||||
httpSseServers: 'HTTP SSE 服务器',
|
||||
websocketServers: 'WebSocket 服务器',
|
||||
websocketClients: 'WebSocket 客户端',
|
||||
};
|
||||
@@ -315,15 +262,12 @@ const addConfig = () => {
|
||||
};
|
||||
|
||||
const editConfig = (item: any) => {
|
||||
dialogTitle.value = '修改配置';
|
||||
const type = getKeyByValue(typeCh, item.type);
|
||||
if (type) {
|
||||
newTab.value = { name: item.name, data: item, type: type };
|
||||
}
|
||||
dialogTitle.value = '编辑配置';
|
||||
newTab.value = { name: item.name, data: { ...item }, type: getKeyByValue(typeCh, item.type) || '' };
|
||||
operateType.value = 'edit';
|
||||
configIndex.value = networkConfig[newTab.value.type].findIndex((obj: any) => obj.name === item.name);
|
||||
visibleBody.value = true;
|
||||
};
|
||||
|
||||
const toggleProperty = async (item: any, tagData: string) => {
|
||||
const type = getKeyByValue(typeCh, item.type);
|
||||
const newData = { ...item };
|
||||
@@ -349,11 +293,11 @@ const delConfig = (item: any) => {
|
||||
};
|
||||
|
||||
const selectType = (key: ComponentKey) => {
|
||||
cardConfig.value = WebConfg.value.get(key);
|
||||
cardConfig.value = WebConfg.value.get(key) || [];
|
||||
};
|
||||
|
||||
const onloadDefault = (key: ComponentKey) => {
|
||||
newTab.value.data = structuredClone(mergeNetworkDefaultConfig[key]);
|
||||
newTab.value.data = {};
|
||||
};
|
||||
//检测重名
|
||||
const checkName = (name: string) => {
|
||||
@@ -383,7 +327,7 @@ const saveConfig = async () => {
|
||||
}
|
||||
const userConfig = await getOB11Config();
|
||||
if (!userConfig) return;
|
||||
userConfig.network = networkConfig;
|
||||
userConfig.network = networkConfig as any;
|
||||
const success = await setOB11Config(userConfig);
|
||||
if (success) {
|
||||
operateType.value = '';
|
||||
@@ -416,12 +360,12 @@ const setOB11Config = async (config: OneBotConfig): Promise<boolean> => {
|
||||
};
|
||||
|
||||
//获取卡片数据
|
||||
const getAllData = (data: NetworkConfig) => {
|
||||
const getAllData = (data: { [key: string]: Array<NetworkAdapterConfig> }) => {
|
||||
cardConfig.value = [];
|
||||
WebConfg.value.set('all', []);
|
||||
for (const key in data) {
|
||||
const configs = data[key as keyof NetworkConfig];
|
||||
if (key in mergeNetworkDefaultConfig) {
|
||||
const configs = data[key as keyof NetworkAdapterConfig];
|
||||
if (key in networkConfig) {
|
||||
networkConfig[key] = [...configs];
|
||||
const newConfigsArray = configs.map((config: any) => ({
|
||||
...config,
|
||||
@@ -442,13 +386,12 @@ const loadConfig = async () => {
|
||||
try {
|
||||
const userConfig = await getOB11Config();
|
||||
if (!userConfig) return;
|
||||
const mergedConfig = mergeOneBotConfigs(userConfig);
|
||||
const mergedConfig = loadConfigOnebot(userConfig);
|
||||
getAllData(mergedConfig.network);
|
||||
} catch (error) {
|
||||
console.error('Error loading config:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const copyText = async (text: string) => {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
@@ -474,9 +417,9 @@ const handleResize = () => {
|
||||
cardWidth.value = tabsWidth.value;
|
||||
}
|
||||
loadPage.value = true;
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
cardHeight.value = window.innerHeight - (headerBox.value?.offsetHeight ?? 0) - (setting.value?.offsetHeight ?? 0) - 21;
|
||||
},300)
|
||||
}, 300)
|
||||
};
|
||||
emitter.on('sendWidth', (width) => {
|
||||
if (typeof width === 'string') {
|
||||
@@ -486,30 +429,30 @@ emitter.on('sendWidth', (width) => {
|
||||
});
|
||||
watch(menuWidth, (newValue, oldValue) => {
|
||||
loadPage.value = false;
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
handleResize();
|
||||
},300)
|
||||
}, 300)
|
||||
});
|
||||
onMounted(() => {
|
||||
loadConfig();
|
||||
const cachedWidth = localStorage.getItem('menuWidth');
|
||||
if (cachedWidth) {
|
||||
menuWidth.value = parseInt(cachedWidth);
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
handleResize();
|
||||
},300)
|
||||
}, 300)
|
||||
}
|
||||
window.addEventListener('resize', ()=>{
|
||||
setTimeout(()=>{
|
||||
window.addEventListener('resize', () => {
|
||||
setTimeout(() => {
|
||||
handleResize();
|
||||
},300)
|
||||
}, 300)
|
||||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', ()=>{
|
||||
setTimeout(()=>{
|
||||
window.removeEventListener('resize', () => {
|
||||
setTimeout(() => {
|
||||
handleResize();
|
||||
},300)
|
||||
}, 300)
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -550,9 +493,11 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.local-icon {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.local {
|
||||
flex: 6;
|
||||
margin: 0 10px 0 10px;
|
||||
@@ -579,22 +524,26 @@ onUnmounted(() => {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tag-item-on{
|
||||
.tag-item-on {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
background-image: linear-gradient(to top, #0ba360 0%, #3cba92 100%) !important;
|
||||
}
|
||||
.tag-item-off{
|
||||
|
||||
.tag-item-off {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
background-image: linear-gradient(to top, rgba(255, 8, 68, 0.93) 0%, #D54941 100%) !important;
|
||||
}
|
||||
|
||||
.browse-icon {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
:global(.t-dialog__ctx .t-dialog__position) {
|
||||
padding: 48px 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.setting-box {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
@@ -644,7 +593,7 @@ onUnmounted(() => {
|
||||
padding: 0 var(--td-comp-paddingLR-l) !important;
|
||||
}
|
||||
|
||||
.setting-base-info tr > td:last-child {
|
||||
.setting-base-info tr>td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
@@ -27,23 +27,35 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import { HttpClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const defaultConfig: HttpClientConfig = {
|
||||
name: 'http-client',
|
||||
enable: false,
|
||||
url: 'http://localhost:8080',
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
debug: false
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
config: HttpClientConfig;
|
||||
}>();
|
||||
|
||||
const config = ref(Object.assign({}, defaultConfig, props.config));
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
() => config.value.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
config.value.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
@@ -33,23 +33,37 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import { HttpServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const defaultConfig: HttpServerConfig = {
|
||||
name: 'http-server',
|
||||
enable: false,
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
enableCors: true,
|
||||
enableWebsocket: true,
|
||||
messagePostFormat: 'array',
|
||||
token: '',
|
||||
debug: false
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
config: HttpServerConfig;
|
||||
}>();
|
||||
|
||||
const config = ref(Object.assign({}, defaultConfig, props.config));
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
() => config.value.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
config.value.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
73
napcat.webui/src/pages/network/HttpSseServerComponent.vue
Normal file
73
napcat.webui/src/pages/network/HttpSseServerComponent.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div>
|
||||
<t-form labelAlign="left">
|
||||
<t-form-item label="启用">
|
||||
<t-switch v-model="config.enable" />
|
||||
</t-form-item>
|
||||
<t-form-item label="端口">
|
||||
<t-input v-model.number="config.port" type="number" />
|
||||
</t-form-item>
|
||||
<t-form-item label="主机">
|
||||
<t-input v-model="config.host" type="text" />
|
||||
</t-form-item>
|
||||
<t-form-item label="报告自身消息">
|
||||
<t-switch v-model="config.reportSelfMessage" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用 CORS">
|
||||
<t-switch v-model="config.enableCors" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用 WS">
|
||||
<t-switch v-model="config.enableWebsocket" />
|
||||
</t-form-item>
|
||||
<t-form-item label="消息格式">
|
||||
<t-select v-model="config.messagePostFormat" :options="messageFormatOptions" />
|
||||
</t-form-item>
|
||||
<t-form-item label="Token">
|
||||
<t-input v-model="config.token" type="text" />
|
||||
</t-form-item>
|
||||
<t-form-item label="调试模式">
|
||||
<t-switch v-model="config.debug" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { HttpSseServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const defaultConfig: HttpSseServerConfig = {
|
||||
name: 'http-sse-server',
|
||||
enable: false,
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
enableCors: true,
|
||||
enableWebsocket: true,
|
||||
messagePostFormat: 'array',
|
||||
token: '',
|
||||
debug: false,
|
||||
reportSelfMessage: false
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
config: HttpSseServerConfig;
|
||||
}>();
|
||||
|
||||
const config = ref(Object.assign({}, defaultConfig, props.config));
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => config.value.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
config.value.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -30,23 +30,37 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import { WebsocketClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const defaultConfig: WebsocketClientConfig = {
|
||||
name: 'websocket-client',
|
||||
enable: false,
|
||||
url: 'ws://localhost:8082',
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
reconnectInterval: 5000,
|
||||
token: '',
|
||||
debug: false,
|
||||
heartInterval: 30000
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
config: WebsocketClientConfig;
|
||||
}>();
|
||||
|
||||
const config = ref(Object.assign({}, defaultConfig, props.config));
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
() => config.value.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
config.value.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
@@ -36,23 +36,38 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import { WebsocketServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const defaultConfig: WebsocketServerConfig = {
|
||||
name: 'websocket-server',
|
||||
enable: false,
|
||||
host: '0.0.0.0',
|
||||
port: 3001,
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
enableForcePushEvent: true,
|
||||
debug: false,
|
||||
heartInterval: 30000
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
config: WebsocketServerConfig;
|
||||
}>();
|
||||
|
||||
const config = ref(Object.assign({}, defaultConfig, props.config));
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
() => config.value.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
config.value.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.3.5",
|
||||
"version": "4.4.1",
|
||||
"scripts": {
|
||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
@@ -43,7 +43,7 @@
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"file-type": "^19.0.0",
|
||||
"file-type": "^20.0.0",
|
||||
"globals": "^15.12.0",
|
||||
"image-size": "^1.1.1",
|
||||
"typescript": "^5.3.3",
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '4.3.5';
|
||||
export const napCatVersion = '4.4.1';
|
||||
|
@@ -160,10 +160,12 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
||||
export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
|
||||
faceId: number;
|
||||
isLargeFace: boolean;
|
||||
resultId?: string;
|
||||
|
||||
constructor(element: SendFaceElement) {
|
||||
super(element);
|
||||
this.faceId = element.faceElement.faceIndex;
|
||||
this.resultId = element.faceElement.resultId;
|
||||
this.isLargeFace = element.faceElement.faceType === FaceType.AniSticke;
|
||||
}
|
||||
|
||||
@@ -176,10 +178,10 @@ export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
|
||||
aniStickerPackId: "1",
|
||||
aniStickerId: "8",
|
||||
faceId: this.faceId,
|
||||
field4: 1,
|
||||
field6: "",
|
||||
sourceType: 1,
|
||||
resultId: this.resultId,
|
||||
preview: "",
|
||||
field9: 1
|
||||
randomType: 1
|
||||
}),
|
||||
businessType: 1
|
||||
}
|
||||
|
@@ -342,11 +342,11 @@ export const QBigFaceExtra = {
|
||||
AniStickerPackId: ProtoField(1, ScalarType.STRING, true),
|
||||
AniStickerId: ProtoField(2, ScalarType.STRING, true),
|
||||
faceId: ProtoField(3, ScalarType.INT32, true),
|
||||
Field4: ProtoField(4, ScalarType.INT32, true),
|
||||
sourceType: ProtoField(4, ScalarType.INT32, true),
|
||||
AniStickerType: ProtoField(5, ScalarType.INT32, true),
|
||||
field6: ProtoField(6, ScalarType.STRING, true),
|
||||
resultId: ProtoField(6, ScalarType.STRING, true),
|
||||
preview: ProtoField(7, ScalarType.STRING, true),
|
||||
field9: ProtoField(9, ScalarType.INT32, true),
|
||||
randomType: ProtoField(9, ScalarType.INT32, true),
|
||||
};
|
||||
|
||||
export const QSmallFaceExtra = {
|
||||
|
@@ -40,6 +40,7 @@ export interface FaceElement {
|
||||
resultId?: string;
|
||||
surpriseId?: string;
|
||||
randomType?: number;
|
||||
chainCount?: number;
|
||||
}
|
||||
export interface GrayTipRovokeElement {
|
||||
operatorRole: string;
|
||||
@@ -348,4 +349,4 @@ export type SendShareLocationElement = SendElementBase<ElementType.SHARELOCATION
|
||||
|
||||
export type SendMessageElement = SendTextElement | SendPttElement |
|
||||
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
|
||||
SendVideoElement | SendArkElement | SendMarkdownElement | SendShareLocationElement;
|
||||
SendVideoElement | SendArkElement | SendMarkdownElement | SendShareLocationElement;
|
||||
|
@@ -18,7 +18,7 @@ export interface BuddyCategoryType {
|
||||
export interface CoreInfo {
|
||||
uid: string;
|
||||
uin: string;
|
||||
nick: string;
|
||||
nick?: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1 @@
|
||||
import '@/universal/napcat';
|
@@ -2,6 +2,7 @@ import { ActionName, BaseCheckResult } from './router';
|
||||
import Ajv, { ErrorObject, ValidateFunction } from 'ajv';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { NapCatOneBot11Adapter, OB11Return } from '@/onebot';
|
||||
import { NetworkAdapterConfig } from '../config/config';
|
||||
|
||||
export class OB11Response {
|
||||
private static createResponse<T>(data: T, status: string, retcode: number, message: string = '', echo: any = null): OB11Return<T> {
|
||||
@@ -55,13 +56,13 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
public async handle(payload: PayloadType, adaptername: string): Promise<OB11Return<ReturnDataType | null>> {
|
||||
public async handle(payload: PayloadType, adaptername: string, config: NetworkAdapterConfig): Promise<OB11Return<ReturnDataType | null>> {
|
||||
const result = await this.check(payload);
|
||||
if (!result.valid) {
|
||||
return OB11Response.error(result.message, 400);
|
||||
}
|
||||
try {
|
||||
const resData = await this._handle(payload, adaptername);
|
||||
const resData = await this._handle(payload, adaptername, config);
|
||||
return OB11Response.ok(resData);
|
||||
} catch (e: any) {
|
||||
this.core.context.logger.logError('发生错误', e);
|
||||
@@ -69,13 +70,13 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
||||
}
|
||||
}
|
||||
|
||||
public async websocketHandle(payload: PayloadType, echo: any, adaptername: string): Promise<OB11Return<ReturnDataType | null>> {
|
||||
public async websocketHandle(payload: PayloadType, echo: any, adaptername: string, config: NetworkAdapterConfig): Promise<OB11Return<ReturnDataType | null>> {
|
||||
const result = await this.check(payload);
|
||||
if (!result.valid) {
|
||||
return OB11Response.error(result.message, 1400, echo);
|
||||
}
|
||||
try {
|
||||
const resData = await this._handle(payload, adaptername);
|
||||
const resData = await this._handle(payload, adaptername, config);
|
||||
return OB11Response.ok(resData, echo);
|
||||
} catch (e: any) {
|
||||
this.core.context.logger.logError('发生错误', e);
|
||||
@@ -83,5 +84,5 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
||||
}
|
||||
}
|
||||
|
||||
abstract _handle(payload: PayloadType, adaptername: string): Promise<ReturnDataType>;
|
||||
abstract _handle(payload: PayloadType, adaptername: string, config: NetworkAdapterConfig): Promise<ReturnDataType>;
|
||||
}
|
||||
|
@@ -3,8 +3,9 @@ import { OB11Message } from '@/onebot';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { ChatType } from '@/core/types';
|
||||
import { MessageUnique } from '@/common/message-unique';
|
||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
|
||||
interface Response {
|
||||
messages: OB11Message[];
|
||||
@@ -23,7 +24,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
|
||||
actionName = ActionName.GetFriendMsgHistory;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
||||
async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig): Promise<Response> {
|
||||
//处理参数
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
|
||||
@@ -42,10 +43,9 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
|
||||
await Promise.all(msgList.map(async msg => {
|
||||
msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
|
||||
}));
|
||||
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
|
||||
//烘焙消息
|
||||
const ob11MsgList = (await Promise.all(
|
||||
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array')))
|
||||
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat)))
|
||||
).filter(msg => msg !== undefined);
|
||||
return { 'messages': ob11MsgList };
|
||||
}
|
||||
|
@@ -3,8 +3,8 @@ import { OB11Message } from '@/onebot';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { ChatType, Peer } from '@/core/types';
|
||||
import { MessageUnique } from '@/common/message-unique';
|
||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
|
||||
interface Response {
|
||||
messages: OB11Message[];
|
||||
@@ -25,7 +25,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
|
||||
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
||||
async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig): Promise<Response> {
|
||||
//处理参数
|
||||
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
||||
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
|
||||
@@ -41,11 +41,9 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
|
||||
await Promise.all(msgList.map(async msg => {
|
||||
msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
|
||||
}));
|
||||
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
|
||||
//烘焙消息
|
||||
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
|
||||
const ob11MsgList = (await Promise.all(
|
||||
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, msgFormat)))
|
||||
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat)))
|
||||
).filter(msg => msg !== undefined);
|
||||
return { 'messages': ob11MsgList };
|
||||
}
|
||||
|
@@ -3,8 +3,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { MessageUnique } from '@/common/message-unique';
|
||||
import crypto from 'crypto';
|
||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
|
||||
const SchemaData = Type.Object({
|
||||
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||
@@ -27,9 +27,7 @@ export class GetGroupEssence extends OneBotAction<Payload, any> {
|
||||
};
|
||||
}
|
||||
|
||||
async _handle(payload: Payload, adapter: string) {
|
||||
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
|
||||
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
|
||||
async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
|
||||
const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list);
|
||||
if (!msglist) {
|
||||
throw new Error('获取失败');
|
||||
@@ -50,7 +48,7 @@ export class GetGroupEssence extends OneBotAction<Payload, any> {
|
||||
operator_nick: msg.add_digest_nick,
|
||||
message_id: message_id,
|
||||
operator_time: msg.add_digest_time,
|
||||
content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, msgFormat))?.message
|
||||
content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, config.messagePostFormat))?.message
|
||||
};
|
||||
}
|
||||
const msgTempData = JSON.stringify({
|
||||
|
@@ -3,8 +3,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { MessageUnique } from '@/common/message-unique';
|
||||
import { RawMessage } from '@/core';
|
||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
|
||||
export type ReturnDataType = OB11Message
|
||||
|
||||
@@ -18,10 +18,8 @@ class GetMsg extends OneBotAction<Payload, OB11Message> {
|
||||
actionName = ActionName.GetMsg;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload, adapter: string) {
|
||||
async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
|
||||
// log("history msg ids", Object.keys(msgHistory));
|
||||
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
|
||||
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
|
||||
if (!payload.message_id) {
|
||||
throw Error('参数message_id不能为空');
|
||||
}
|
||||
@@ -38,7 +36,7 @@ class GetMsg extends OneBotAction<Payload, OB11Message> {
|
||||
} else {
|
||||
msg = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgIdWithPeer?.MsgId || payload.message_id.toString()])).msgList[0];
|
||||
}
|
||||
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg, msgFormat);
|
||||
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat);
|
||||
if (!retMsg) throw Error('消息为空');
|
||||
try {
|
||||
retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgId)!;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const SchemaData = Type.Object({
|
||||
@@ -14,16 +14,14 @@ export default class GetRecentContact extends OneBotAction<Payload, any> {
|
||||
actionName = ActionName.GetRecentContact;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload, adapter: string) {
|
||||
async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
|
||||
const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+payload.count);
|
||||
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
|
||||
//烘焙消息
|
||||
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
|
||||
return await Promise.all(ret.info.changedList.map(async (t) => {
|
||||
const FastMsg = await this.core.apis.MsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
|
||||
if (FastMsg.msgList.length > 0) {
|
||||
//扩展ret.info.changedList
|
||||
const lastestMsg = await this.obContext.apis.MsgApi.parseMessage(FastMsg.msgList[0], msgFormat);
|
||||
const lastestMsg = await this.obContext.apis.MsgApi.parseMessage(FastMsg.msgList[0], config.messagePostFormat);
|
||||
return {
|
||||
lastestMsg: lastestMsg,
|
||||
peerUin: t.peerUin,
|
||||
|
@@ -190,7 +190,10 @@ export class OneBotMsgApi {
|
||||
return {
|
||||
type: OB11MessageDataType.face,
|
||||
data: {
|
||||
id: element.faceIndex.toString()
|
||||
id: element.faceIndex.toString(),
|
||||
raw: element,
|
||||
resultId: element.resultId,
|
||||
chainCount: element.chainCount,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -464,7 +467,7 @@ export class OneBotMsgApi {
|
||||
undefined;
|
||||
},
|
||||
|
||||
[OB11MessageDataType.face]: async ({ data: { id } }) => {
|
||||
[OB11MessageDataType.face]: async ({ data: { id, resultId, chainCount } }) => {
|
||||
const parsedFaceId = +id;
|
||||
// 从face_config.json中获取表情名称
|
||||
const sysFaces = faceConfig.sysface;
|
||||
@@ -491,6 +494,8 @@ export class OneBotMsgApi {
|
||||
stickerType: face.AniStickerType,
|
||||
packId: face.AniStickerPackId,
|
||||
sourceType: 1,
|
||||
resultId: resultId?.toString(),
|
||||
chainCount,
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -906,16 +911,16 @@ export class OneBotMsgApi {
|
||||
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
|
||||
const sizePromises = elements.map(async element => {
|
||||
switch (element.elementType) {
|
||||
case ElementType.PTT:
|
||||
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
||||
case ElementType.FILE:
|
||||
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
||||
case ElementType.VIDEO:
|
||||
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
||||
case ElementType.PIC:
|
||||
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
||||
default:
|
||||
return 0;
|
||||
case ElementType.PTT:
|
||||
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
||||
case ElementType.FILE:
|
||||
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
||||
case ElementType.VIDEO:
|
||||
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
||||
case ElementType.PIC:
|
||||
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
const sizes = await Promise.all(sizePromises);
|
||||
@@ -1008,14 +1013,14 @@ export class OneBotMsgApi {
|
||||
}
|
||||
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
||||
switch (type) {
|
||||
case 130:
|
||||
return 'leave';
|
||||
case 131:
|
||||
return 'kick';
|
||||
case 3:
|
||||
return 'kick_me';
|
||||
default:
|
||||
return 'kick';
|
||||
case 130:
|
||||
return 'leave';
|
||||
case 131:
|
||||
return 'kick';
|
||||
case 3:
|
||||
return 'kick_me';
|
||||
default:
|
||||
return 'kick';
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,254 +1,108 @@
|
||||
interface v1Config {
|
||||
http: {
|
||||
enable: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
secret: string;
|
||||
enableHeart: boolean;
|
||||
enablePost: boolean;
|
||||
postUrls: string[];
|
||||
};
|
||||
ws: {
|
||||
enable: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
reverseWs: {
|
||||
enable: boolean;
|
||||
urls: string[];
|
||||
};
|
||||
debug: boolean;
|
||||
heartInterval: number;
|
||||
messagePostFormat: string;
|
||||
enableLocalFile2Url: boolean;
|
||||
musicSignUrl: string;
|
||||
reportSelfMessage: boolean;
|
||||
token: string;
|
||||
}
|
||||
export interface AdapterConfigInner {
|
||||
name: string;
|
||||
enable: boolean;
|
||||
import { Type, Static } from '@sinclair/typebox';
|
||||
import Ajv from 'ajv';
|
||||
|
||||
}
|
||||
export type AdapterConfigWrap = AdapterConfigInner & Partial<NetworkConfigAdapter>;
|
||||
|
||||
export interface AdapterConfig extends AdapterConfigInner {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const createDefaultAdapterConfig = <T extends AdapterConfig>(config: T): T => config;
|
||||
|
||||
export interface PluginConfig extends AdapterConfig {
|
||||
name: string;
|
||||
enable: boolean;
|
||||
messagePostFormat: string;
|
||||
reportSelfMessage: boolean;
|
||||
debug: boolean;
|
||||
}
|
||||
|
||||
export const httpServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'http-server',
|
||||
enable: false as boolean,
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
enableCors: true,
|
||||
enableWebsocket: true,
|
||||
messagePostFormat: 'array',
|
||||
token: '',
|
||||
debug: false,
|
||||
});
|
||||
export type HttpServerConfig = typeof httpServerDefaultConfigs;
|
||||
|
||||
export const httpSseServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
...httpServerDefaultConfigs,
|
||||
name: 'http-sse-server',
|
||||
reportSelfMessage: false,
|
||||
});
|
||||
export type HttpSseServerConfig = typeof httpSseServerDefaultConfigs;
|
||||
|
||||
export const httpClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'http-client',
|
||||
enable: false as boolean,
|
||||
url: 'http://localhost:8080',
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
debug: false,
|
||||
});
|
||||
export type HttpClientConfig = typeof httpClientDefaultConfigs;
|
||||
|
||||
export const websocketServerDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'websocket-server',
|
||||
enable: false as boolean,
|
||||
host: '0.0.0.0',
|
||||
port: 3001,
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
token: '',
|
||||
enableForcePushEvent: true,
|
||||
debug: false,
|
||||
heartInterval: 30000,
|
||||
});
|
||||
export type WebsocketServerConfig = typeof websocketServerDefaultConfigs;
|
||||
|
||||
export const websocketClientDefaultConfigs = createDefaultAdapterConfig({
|
||||
name: 'websocket-client',
|
||||
enable: false as boolean,
|
||||
url: 'ws://localhost:8082',
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
reconnectInterval: 5000,
|
||||
token: '',
|
||||
debug: false,
|
||||
heartInterval: 30000,
|
||||
});
|
||||
export type WebsocketClientConfig = typeof websocketClientDefaultConfigs;
|
||||
|
||||
export interface NetworkConfig {
|
||||
httpServers: Array<HttpServerConfig>;
|
||||
httpSseServers: Array<HttpSseServerConfig>;
|
||||
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;
|
||||
parseMultMsg: boolean;
|
||||
}
|
||||
|
||||
const createDefaultConfig = <T>(config: T): T => config;
|
||||
|
||||
export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
|
||||
network: {
|
||||
httpServers: [],
|
||||
httpSseServers: [],
|
||||
httpClients: [],
|
||||
websocketServers: [],
|
||||
websocketClients: [],
|
||||
},
|
||||
musicSignUrl: '',
|
||||
enableLocalFile2Url: false,
|
||||
parseMultMsg: true
|
||||
const HttpServerConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'http-server' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
port: Type.Number({ default: 3000 }),
|
||||
host: Type.String({ default: '0.0.0.0' }),
|
||||
enableCors: Type.Boolean({ default: true }),
|
||||
enableWebsocket: Type.Boolean({ default: true }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
token: Type.String({ default: '' }),
|
||||
debug: Type.Boolean({ default: false })
|
||||
});
|
||||
|
||||
export const mergeNetworkDefaultConfig = {
|
||||
httpServers: httpServerDefaultConfigs,
|
||||
httpClients: httpClientDefaultConfigs,
|
||||
websocketServers: websocketServerDefaultConfigs,
|
||||
websocketClients: websocketClientDefaultConfigs,
|
||||
} as const;
|
||||
const HttpSseServerConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'http-sse-server' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
port: Type.Number({ default: 3000 }),
|
||||
host: Type.String({ default: '0.0.0.0' }),
|
||||
enableCors: Type.Boolean({ default: true }),
|
||||
enableWebsocket: Type.Boolean({ default: true }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
token: Type.String({ default: '' }),
|
||||
debug: Type.Boolean({ default: false }),
|
||||
reportSelfMessage: Type.Boolean({ default: false })
|
||||
});
|
||||
|
||||
export type NetworkConfigAdapter = HttpServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig;
|
||||
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig;
|
||||
const HttpClientConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'http-client' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
url: Type.String({ default: 'http://localhost:8080' }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
reportSelfMessage: Type.Boolean({ default: false }),
|
||||
token: Type.String({ default: '' }),
|
||||
debug: Type.Boolean({ default: false })
|
||||
});
|
||||
|
||||
export function mergeOneBotConfigs(
|
||||
userConfig: Partial<OneBotConfig>,
|
||||
defaultConfig: OneBotConfig = defaultOneBotConfigs
|
||||
): OneBotConfig {
|
||||
const mergedConfig = { ...defaultConfig };
|
||||
const WebsocketServerConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'websocket-server' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
host: Type.String({ default: '0.0.0.0' }),
|
||||
port: Type.Number({ default: 3001 }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
reportSelfMessage: Type.Boolean({ default: false }),
|
||||
token: Type.String({ default: '' }),
|
||||
enableForcePushEvent: Type.Boolean({ default: true }),
|
||||
debug: Type.Boolean({ default: false }),
|
||||
heartInterval: Type.Number({ default: 30000 })
|
||||
});
|
||||
|
||||
if (userConfig.network) {
|
||||
mergedConfig.network = { ...defaultConfig.network };
|
||||
for (const key in userConfig.network) {
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userConfig.musicSignUrl !== undefined) {
|
||||
mergedConfig.musicSignUrl = userConfig.musicSignUrl;
|
||||
}
|
||||
if (userConfig.enableLocalFile2Url !== undefined) {
|
||||
mergedConfig.enableLocalFile2Url = userConfig.enableLocalFile2Url;
|
||||
}
|
||||
if (userConfig.parseMultMsg !== undefined) {
|
||||
mergedConfig.parseMultMsg = userConfig.parseMultMsg;
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
const WebsocketClientConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'websocket-client' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
url: Type.String({ default: 'ws://localhost:8082' }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
reportSelfMessage: Type.Boolean({ default: false }),
|
||||
reconnectInterval: Type.Number({ default: 5000 }),
|
||||
token: Type.String({ default: '' }),
|
||||
debug: Type.Boolean({ default: false }),
|
||||
heartInterval: Type.Number({ default: 30000 })
|
||||
});
|
||||
|
||||
function checkIsOneBotConfigV1(v1Config: Partial<v1Config>): boolean {
|
||||
return v1Config.http !== undefined || v1Config.ws !== undefined || v1Config.reverseWs !== undefined;
|
||||
}
|
||||
const PluginConfigSchema = Type.Object({
|
||||
name: Type.String({ default: 'plugin' }),
|
||||
enable: Type.Boolean({ default: false }),
|
||||
messagePostFormat: Type.String({ default: 'array' }),
|
||||
reportSelfMessage: Type.Boolean({ default: false }),
|
||||
debug: Type.Boolean({ default: false }),
|
||||
});
|
||||
|
||||
export function migrateOneBotConfigsV1(config: Partial<v1Config>): OneBotConfig {
|
||||
if (!checkIsOneBotConfigV1(config)) {
|
||||
return config as OneBotConfig;
|
||||
const NetworkConfigSchema = Type.Object({
|
||||
httpServers: Type.Array(HttpServerConfigSchema, { default: [] }),
|
||||
httpSseServers: Type.Array(HttpSseServerConfigSchema, { default: [] }),
|
||||
httpClients: Type.Array(HttpClientConfigSchema, { default: [] }),
|
||||
websocketServers: Type.Array(WebsocketServerConfigSchema, { default: [] }),
|
||||
websocketClients: Type.Array(WebsocketClientConfigSchema, { default: [] }),
|
||||
plugins: Type.Array(PluginConfigSchema, { default: [] })
|
||||
}, { default: {} });
|
||||
|
||||
const OneBotConfigSchema = Type.Object({
|
||||
network: NetworkConfigSchema,
|
||||
musicSignUrl: Type.String({ default: '' }),
|
||||
enableLocalFile2Url: Type.Boolean({ default: false }),
|
||||
parseMultMsg: Type.Boolean({ default: true })
|
||||
});
|
||||
|
||||
export type OneBotConfig = Static<typeof OneBotConfigSchema>;
|
||||
export type HttpServerConfig = Static<typeof HttpServerConfigSchema>;
|
||||
export type HttpSseServerConfig = Static<typeof HttpSseServerConfigSchema>;
|
||||
export type HttpClientConfig = Static<typeof HttpClientConfigSchema>;
|
||||
export type WebsocketServerConfig = Static<typeof WebsocketServerConfigSchema>;
|
||||
export type WebsocketClientConfig = Static<typeof WebsocketClientConfigSchema>;
|
||||
export type PluginConfig = Static<typeof PluginConfigSchema>;
|
||||
|
||||
export type NetworkAdapterConfig = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig;
|
||||
export type NetworkConfigKey = keyof OneBotConfig['network'];
|
||||
|
||||
|
||||
export function loadConfig(config: Partial<OneBotConfig>): OneBotConfig {
|
||||
const ajv = new Ajv({ useDefaults: true });
|
||||
const validate = ajv.compile(OneBotConfigSchema);
|
||||
const valid = validate(config);
|
||||
if (!valid) {
|
||||
throw new Error(ajv.errorsText(validate.errors));
|
||||
}
|
||||
const mergedConfig = { ...defaultOneBotConfigs };
|
||||
if (config.http) {
|
||||
mergedConfig.network.httpServers = [
|
||||
mergeConfigs(httpServerDefaultConfigs, {
|
||||
name: 'http-server',
|
||||
enable: config.http.enable,
|
||||
port: config.http.port,
|
||||
host: config.http.host,
|
||||
token: config.http.secret,
|
||||
debug: config.debug,
|
||||
messagePostFormat: config.messagePostFormat,
|
||||
}),
|
||||
];
|
||||
}
|
||||
if (config.ws) {
|
||||
mergedConfig.network.websocketServers = [
|
||||
mergeConfigs(websocketServerDefaultConfigs, {
|
||||
name: 'websocket-server',
|
||||
enable: config.ws.enable,
|
||||
port: config.ws.port,
|
||||
host: config.ws.host,
|
||||
token: config.token,
|
||||
debug: config.debug,
|
||||
messagePostFormat: config.messagePostFormat,
|
||||
reportSelfMessage: config.reportSelfMessage,
|
||||
}),
|
||||
];
|
||||
}
|
||||
if (config.reverseWs) {
|
||||
mergedConfig.network.websocketClients = config.reverseWs.urls.map((url) =>
|
||||
mergeConfigs(websocketClientDefaultConfigs, {
|
||||
name: 'websocket-client-' + config.reverseWs?.urls.indexOf(url).toString(),
|
||||
enable: config.reverseWs?.enable,
|
||||
url: url,
|
||||
token: config.token,
|
||||
debug: config.debug,
|
||||
messagePostFormat: config.messagePostFormat,
|
||||
reportSelfMessage: config.reportSelfMessage,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (config.heartInterval) {
|
||||
mergedConfig.network.websocketServers[0].heartInterval = config.heartInterval;
|
||||
}
|
||||
if (config.musicSignUrl) {
|
||||
mergedConfig.musicSignUrl = config.musicSignUrl;
|
||||
}
|
||||
if (config.enableLocalFile2Url) {
|
||||
mergedConfig.enableLocalFile2Url = config.enableLocalFile2Url;
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
export function getConfigBoolKey(
|
||||
configs: Array<NetworkConfigAdapter>,
|
||||
prediction: (config: NetworkConfigAdapter) => boolean
|
||||
): { positive: Array<string>, negative: Array<string> } {
|
||||
const result: { positive: string[], negative: string[] } = { positive: [], negative: [] };
|
||||
configs.forEach(config => {
|
||||
if (prediction(config)) {
|
||||
result.positive.push(config.name);
|
||||
} else {
|
||||
result.negative.push(config.name);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return config as OneBotConfig;
|
||||
}
|
@@ -23,7 +23,7 @@ export class OB11Construct {
|
||||
...rawFriend.baseInfo,
|
||||
...rawFriend.coreInfo,
|
||||
user_id: parseInt(rawFriend.coreInfo.uin),
|
||||
nickname: rawFriend.coreInfo.nick,
|
||||
nickname: rawFriend.coreInfo.nick ?? "",
|
||||
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
||||
sex: this.sex(rawFriend.baseInfo.sex),
|
||||
level: 0,
|
||||
|
@@ -44,10 +44,8 @@ import { LRUCache } from '@/common/lru-cache';
|
||||
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
||||
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
||||
import {
|
||||
AdapterConfigWrap,
|
||||
mergeOneBotConfigs,
|
||||
migrateOneBotConfigsV1,
|
||||
NetworkConfigAdapter,
|
||||
NetworkAdapterConfig,
|
||||
loadConfig,
|
||||
OneBotConfig,
|
||||
} from './config/config';
|
||||
import { OB11Message } from './types';
|
||||
@@ -71,8 +69,8 @@ export class NapCatOneBot11Adapter {
|
||||
this.core = core;
|
||||
this.context = context;
|
||||
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath);
|
||||
this.configLoader.save(migrateOneBotConfigsV1(this.configLoader.configData));
|
||||
this.configLoader.save(mergeOneBotConfigs(this.configLoader.configData));
|
||||
this.configLoader.save(this.configLoader.configData);
|
||||
this.configLoader.save(loadConfig(this.configLoader.configData));
|
||||
this.apis = {
|
||||
GroupApi: new OneBotGroupApi(this, core),
|
||||
UserApi: new OneBotUserApi(this, core),
|
||||
@@ -129,8 +127,8 @@ export class NapCatOneBot11Adapter {
|
||||
);
|
||||
}
|
||||
}
|
||||
for(const key of ob11Config.network.httpSseServers){
|
||||
if(key.enable) {
|
||||
for (const key of ob11Config.network.httpSseServers) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(
|
||||
new OB11ActiveHttpSSEAdapter(key.name, key, this.core, this, this.actions)
|
||||
);
|
||||
@@ -181,7 +179,7 @@ export class NapCatOneBot11Adapter {
|
||||
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
|
||||
const prev = this.configLoader.configData;
|
||||
// 保证默认配置
|
||||
newConfig = mergeOneBotConfigs(newConfig);
|
||||
newConfig = loadConfig(newConfig);
|
||||
|
||||
this.configLoader.save(newConfig);
|
||||
//this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);
|
||||
@@ -210,13 +208,14 @@ export class NapCatOneBot11Adapter {
|
||||
|
||||
await this.handleConfigChange(prev.network.httpServers, now.network.httpServers, OB11PassiveHttpAdapter);
|
||||
await this.handleConfigChange(prev.network.httpClients, now.network.httpClients, OB11ActiveHttpAdapter);
|
||||
await this.handleConfigChange(prev.network.httpSseServers, now.network.httpSseServers, OB11ActiveHttpSSEAdapter);
|
||||
await this.handleConfigChange(prev.network.websocketServers, now.network.websocketServers, OB11PassiveWebSocketAdapter);
|
||||
await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11ActiveWebSocketAdapter);
|
||||
}
|
||||
|
||||
private async handleConfigChange<CT extends NetworkConfigAdapter>(
|
||||
prevConfig: NetworkConfigAdapter[],
|
||||
nowConfig: NetworkConfigAdapter[],
|
||||
private async handleConfigChange<CT extends NetworkAdapterConfig>(
|
||||
prevConfig: NetworkAdapterConfig[],
|
||||
nowConfig: NetworkAdapterConfig[],
|
||||
adapterClass: new (
|
||||
...args: ConstructorParameters<typeof IOB11NetworkAdapter<CT>>
|
||||
) => IOB11NetworkAdapter<CT>
|
||||
@@ -478,7 +477,7 @@ export class NapCatOneBot11Adapter {
|
||||
]);
|
||||
}
|
||||
|
||||
private async handleMsg(message: RawMessage, network: Array<AdapterConfigWrap>) {
|
||||
private async handleMsg(message: RawMessage, network: Array<NetworkAdapterConfig>) {
|
||||
// 过滤无效消息
|
||||
if (message.msgType === NTMsgType.KMSGTYPENULL) {
|
||||
return;
|
||||
@@ -507,7 +506,7 @@ export class NapCatOneBot11Adapter {
|
||||
ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
|
||||
}
|
||||
|
||||
private createMsgMap(network: Array<AdapterConfigWrap>, ob11Msg: any, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
||||
private createMsgMap(network: Array<NetworkAdapterConfig>, ob11Msg: any, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
||||
const msgMap: Map<string, OB11Message> = new Map();
|
||||
network.filter(e => e.enable).forEach(e => {
|
||||
if (isSelfMsg || message.chatType !== ChatType.KCHATTYPEGROUP) {
|
||||
@@ -524,7 +523,7 @@ export class NapCatOneBot11Adapter {
|
||||
return msgMap;
|
||||
}
|
||||
|
||||
private handleDebugNetwork(network: Array<AdapterConfigWrap>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
||||
private handleDebugNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
||||
const debugNetwork = network.filter(e => e.enable && e.debug);
|
||||
if (debugNetwork.length > 0) {
|
||||
debugNetwork.forEach(adapter => {
|
||||
@@ -538,7 +537,7 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
private handleNotReportSelfNetwork(network: Array<AdapterConfigWrap>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
||||
private handleNotReportSelfNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
||||
if (isSelfMsg) {
|
||||
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
|
||||
notReportSelfNetwork.forEach(adapter => {
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { NetworkConfigAdapter } from "@/onebot/config/config";
|
||||
import { NetworkAdapterConfig } from "@/onebot/config/config";
|
||||
import { LogWrapper } from "@/common/log";
|
||||
import { NapCatCore } from "@/core";
|
||||
import { NapCatOneBot11Adapter } from "@/onebot";
|
||||
import { ActionMap } from "@/onebot/action";
|
||||
import { OB11EmitEventContent, OB11NetworkReloadType } from "@/onebot/network/index";
|
||||
|
||||
export abstract class IOB11NetworkAdapter<CT extends NetworkConfigAdapter> {
|
||||
export abstract class IOB11NetworkAdapter<CT extends NetworkAdapterConfig> {
|
||||
name: string;
|
||||
isEnable: boolean = false;
|
||||
config: CT;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { OneBotEvent } from '@/onebot/event/OneBotEvent';
|
||||
import { OB11Message } from '@/onebot';
|
||||
import { NetworkConfigAdapter } from '@/onebot/config/config';
|
||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||
import { IOB11NetworkAdapter } from "@/onebot/network/adapter";
|
||||
|
||||
export type OB11EmitEventContent = OneBotEvent | OB11Message;
|
||||
@@ -13,7 +13,7 @@ export enum OB11NetworkReloadType {
|
||||
}
|
||||
|
||||
export class OB11NetworkManager {
|
||||
adapters: Map<string, IOB11NetworkAdapter<NetworkConfigAdapter>> = new Map();
|
||||
adapters: Map<string, IOB11NetworkAdapter<NetworkAdapterConfig>> = new Map();
|
||||
|
||||
async openAllAdapters() {
|
||||
return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.open()));
|
||||
@@ -49,22 +49,22 @@ export class OB11NetworkManager {
|
||||
}));
|
||||
}
|
||||
|
||||
registerAdapter<CT extends NetworkConfigAdapter>(adapter: IOB11NetworkAdapter<CT>) {
|
||||
registerAdapter<CT extends NetworkAdapterConfig>(adapter: IOB11NetworkAdapter<CT>) {
|
||||
this.adapters.set(adapter.name, adapter);
|
||||
}
|
||||
|
||||
async registerAdapterAndOpen<CT extends NetworkConfigAdapter>(adapter: IOB11NetworkAdapter<CT>) {
|
||||
async registerAdapterAndOpen<CT extends NetworkAdapterConfig>(adapter: IOB11NetworkAdapter<CT>) {
|
||||
this.registerAdapter(adapter);
|
||||
await adapter.open();
|
||||
}
|
||||
|
||||
async closeSomeAdapters<CT extends NetworkConfigAdapter>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
|
||||
async closeSomeAdapters<CT extends NetworkAdapterConfig>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
|
||||
for (const adapter of adaptersToClose) {
|
||||
this.adapters.delete(adapter.name);
|
||||
await adapter.close();
|
||||
}
|
||||
}
|
||||
async closeSomeAdaterWhenOpen<CT extends NetworkConfigAdapter>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
|
||||
async closeSomeAdaterWhenOpen<CT extends NetworkAdapterConfig>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
|
||||
for (const adapter of adaptersToClose) {
|
||||
this.adapters.delete(adapter.name);
|
||||
if (adapter.isEnable) {
|
||||
@@ -77,7 +77,7 @@ export class OB11NetworkManager {
|
||||
return this.adapters.get(name);
|
||||
}
|
||||
|
||||
async closeAdapterByPredicate(closeFilter: (adapter: IOB11NetworkAdapter<NetworkConfigAdapter>) => boolean) {
|
||||
async closeAdapterByPredicate(closeFilter: (adapter: IOB11NetworkAdapter<NetworkAdapterConfig>) => boolean) {
|
||||
const adaptersToClose = Array.from(this.adapters.values()).filter(closeFilter);
|
||||
await this.closeSomeAdapters(adaptersToClose);
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ export class OB11PluginAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
|
||||
onEvent<T extends OB11EmitEventContent>(event: T) {
|
||||
if (event.post_type === 'message') {
|
||||
plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message,this.actions).then().catch();
|
||||
plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message, this.actions, this).then().catch();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -164,6 +164,8 @@ export interface OB11MessageFace {
|
||||
type: OB11MessageDataType.face;
|
||||
data: {
|
||||
id: string;
|
||||
resultId?: string;
|
||||
chainCount?: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,4 +278,4 @@ export interface OB11PostContext {
|
||||
message_type?: 'private' | 'group';
|
||||
user_id?: string;
|
||||
group_id?: string;
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { NapCatOneBot11Adapter, OB11Message } from "@/onebot";
|
||||
import { NapCatCore } from "@/core";
|
||||
import { ActionMap } from "@/onebot/action";
|
||||
import { OB11PluginAdapter } from "@/onebot/network/plugin";
|
||||
|
||||
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCtx: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap) => {
|
||||
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCtx: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap, instance: OB11PluginAdapter) => {
|
||||
if (message.raw_message === 'ping') {
|
||||
const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter);
|
||||
const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter, instance.config);
|
||||
console.log(ret);
|
||||
}
|
||||
};
|
||||
|
6
src/universal/LiteLoader.d.ts
vendored
Normal file
6
src/universal/LiteLoader.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
declare global {
|
||||
namespace globalThis {
|
||||
var LiteLoader: symbol;
|
||||
}
|
||||
}
|
||||
export {};
|
@@ -1,7 +1,6 @@
|
||||
import { NCoreInitShell } from "@/shell/base";
|
||||
|
||||
export * from "@/framework/napcat";
|
||||
export * from "@/shell/base";
|
||||
if ((global as any).LiteLoader == undefined) {
|
||||
if (global.LiteLoader == undefined) {
|
||||
NCoreInitShell();
|
||||
}
|
Reference in New Issue
Block a user