Compare commits

...

32 Commits

Author SHA1 Message Date
手瓜一十雪
09583e5de5 fuck javascript 2024-12-16 22:09:37 +08:00
Mlikiowa
38b0b7cd00 release: v4.2.34 2024-12-16 13:17:43 +00:00
手瓜一十雪
8b9c7b0c27 Merge pull request #632 from q8018414/patch-1
Update AboutUs.vue
2024-12-16 21:16:39 +08:00
手瓜一十雪
1005619bf3 Merge pull request #630 from NapNeko/dependabot/npm_and_yarn/rollup/plugin-typescript-12.1.2
chore(deps-dev): bump @rollup/plugin-typescript from 11.1.6 to 12.1.2
2024-12-16 21:16:01 +08:00
手瓜一十雪
3e09cff9cb Merge branch 'main' into dependabot/npm_and_yarn/rollup/plugin-typescript-12.1.2 2024-12-16 21:15:52 +08:00
手瓜一十雪
c24384e454 Merge pull request #629 from NapNeko/dependabot/npm_and_yarn/rollup/plugin-node-resolve-16.0.0
chore(deps-dev): bump @rollup/plugin-node-resolve from 15.3.1 to 16.0.0
2024-12-16 21:15:23 +08:00
手瓜一十雪
f87a543406 fix: #631 2024-12-16 21:14:14 +08:00
手瓜一十雪
f752136283 fix: #631 2024-12-16 21:06:51 +08:00
my_key
7e71622a44 Update AboutUs.vue
新增用于显示New NapCat的tag,便于区分当前版本和最新版本
2024-12-16 20:09:40 +08:00
dependabot[bot]
da92afb379 chore(deps-dev): bump @rollup/plugin-typescript from 11.1.6 to 12.1.2
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 11.1.6 to 12.1.2.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/typescript/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/typescript-v12.1.2/packages/typescript)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-typescript"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 08:44:42 +00:00
dependabot[bot]
d3062de5f9 chore(deps-dev): bump @rollup/plugin-node-resolve from 15.3.1 to 16.0.0
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 15.3.1 to 16.0.0.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v16.0.0/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 08:43:46 +00:00
Mlikiowa
f1440b03a8 release: v4.2.33 2024-12-16 05:03:59 +00:00
手瓜一十雪
9a8b266cef Merge pull request #627 from bietiaop/main
feat: 查看登录QQ信息&获取快速登录列表详细信息&获取nc的包信息&优化了部分写法
2024-12-16 13:03:09 +08:00
手瓜一十雪
2a9bc57120 fix: #628 2024-12-16 13:00:07 +08:00
bietiaop
2ed83a0e30 feat: 查看登录QQ信息&获取快速登录列表详细信息&获取nc的包信息&优化了部分写法 2024-12-16 12:46:27 +08:00
Mlikiowa
116e8fd30a release: v4.2.32 2024-12-14 07:03:02 +00:00
手瓜一十雪
891f11173b fix 2024-12-14 15:01:47 +08:00
手瓜一十雪
dfc7996c17 Merge branch 'maybe-feat/type' 2024-12-14 15:00:18 +08:00
手瓜一十雪
dc0561d34f refactor: OB11ActiveHttpAdapter 2024-12-14 14:26:23 +08:00
手瓜一十雪
4fb0845d79 fix: #619 2024-12-14 13:46:25 +08:00
pk5ls20
0e0d4837b8 feat & fix: GetMiniAppArk 2024-12-14 06:56:23 +08:00
pk5ls20
a6adde7966 feat: attempt to enhance type inference 2024-12-14 05:56:49 +08:00
手瓜一十雪
7b693132f9 fix 2024-12-13 23:27:24 +08:00
手瓜一十雪
3c3114b6ab fix: 支持类型推导 2024-12-13 23:23:58 +08:00
Mlikiowa
5cdbf58f59 release: v4.2.31 2024-12-13 14:04:13 +00:00
手瓜一十雪
6f0a4131a2 fix: 异常 2024-12-13 22:03:51 +08:00
Mlikiowa
aa520e2f5d release: v4.2.30 2024-12-13 11:28:32 +00:00
手瓜一十雪
2c3b7e9ee8 fix: fuck! tencent 2024-12-13 19:28:04 +08:00
手瓜一十雪
b86a28092a fix: Login Check 2024-12-13 17:38:27 +08:00
手瓜一十雪
d59e5f2133 fix 2024-12-13 16:45:35 +08:00
手瓜一十雪
3fdd187102 fix: #610 2024-12-13 14:29:11 +08:00
Mlikiowa
3f085fd8ae release: v4.2.29 2024-12-13 04:47:13 +00:00
47 changed files with 442 additions and 359 deletions

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ", "name": "NapCatQQ",
"slug": "NapCat.Framework", "slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现", "description": "高性能的 OneBot 11 协议实现",
"version": "4.2.28", "version": "4.2.34",
"icon": "./logo.png", "icon": "./logo.png",
"authors": [ "authors": [
{ {

View File

@@ -1,5 +1,3 @@
import { request } from '@/utils/request.js';
import { EventSourcePolyfill } from 'event-source-polyfill'; import { EventSourcePolyfill } from 'event-source-polyfill';
type LogListItem = string; type LogListItem = string;
type LogListData = LogListItem[]; type LogListData = LogListItem[];
@@ -15,7 +13,7 @@ export class LogManager {
} }
public async GetLogList(): Promise<LogListData> { public async GetLogList(): Promise<LogListData> {
try { try {
const ConfigResponse = await request(`${this.apiPrefix}/Log/GetLogList`, { const ConfigResponse = await fetch(`${this.apiPrefix}/Log/GetLogList`, {
method: 'GET', method: 'GET',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -35,7 +33,7 @@ export class LogManager {
} }
public async GetLog(FileName: string): Promise<string> { public async GetLog(FileName: string): Promise<string> {
try { try {
const ConfigResponse = await request(`${this.apiPrefix}/Log/GetLog?id=${FileName}`, { const ConfigResponse = await fetch(`${this.apiPrefix}/Log/GetLog?id=${FileName}`, {
method: 'GET', method: 'GET',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,

View File

@@ -1,6 +1,5 @@
import { request } from '@/utils/request.js';
import { OneBotConfig } from '../../../src/onebot/config/config'; import { OneBotConfig } from '../../../src/onebot/config/config';
import { ResponseCode } from '../../../src/webui/src/const/status';
export class QQLoginManager { export class QQLoginManager {
private retCredential: string; private retCredential: string;
private readonly apiPrefix: string; private readonly apiPrefix: string;
@@ -14,7 +13,7 @@ export class QQLoginManager {
// TODO: // TODO:
public async GetOB11Config(): Promise<OneBotConfig> { public async GetOB11Config(): Promise<OneBotConfig> {
try { try {
const ConfigResponse = await request(`${this.apiPrefix}/OB11Config/GetConfig`, { const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -23,8 +22,8 @@ export class QQLoginManager {
}); });
if (ConfigResponse.status == 200) { if (ConfigResponse.status == 200) {
const ConfigResponseJson = await ConfigResponse.json(); const ConfigResponseJson = await ConfigResponse.json();
if (ConfigResponseJson.code == 0) { if (ConfigResponseJson.code == ResponseCode.Success) {
return ConfigResponseJson?.data as OneBotConfig; return ConfigResponseJson.data;
} }
} }
} catch (error) { } catch (error) {
@@ -35,7 +34,7 @@ export class QQLoginManager {
public async SetOB11Config(config: OneBotConfig): Promise<boolean> { public async SetOB11Config(config: OneBotConfig): Promise<boolean> {
try { try {
const ConfigResponse = await request(`${this.apiPrefix}/OB11Config/SetConfig`, { const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -57,7 +56,7 @@ export class QQLoginManager {
public async checkQQLoginStatus(): Promise<boolean> { public async checkQQLoginStatus(): Promise<boolean> {
try { try {
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, { const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -77,7 +76,7 @@ export class QQLoginManager {
} }
public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string; isLogin: string } | undefined> { public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string; isLogin: string } | undefined> {
try { try {
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, { const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -98,7 +97,7 @@ export class QQLoginManager {
public async checkWebUiLogined(): Promise<boolean> { public async checkWebUiLogined(): Promise<boolean> {
try { try {
const LoginResponse = await request(`${this.apiPrefix}/auth/check`, { const LoginResponse = await fetch(`${this.apiPrefix}/auth/check`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -119,7 +118,7 @@ export class QQLoginManager {
public async loginWithToken(token: string): Promise<string | null> { public async loginWithToken(token: string): Promise<string | null> {
try { try {
const loginResponse = await request(`${this.apiPrefix}/auth/login`, { const loginResponse = await fetch(`${this.apiPrefix}/auth/login`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -140,7 +139,7 @@ export class QQLoginManager {
public async getQQLoginQrcode(): Promise<string> { public async getQQLoginQrcode(): Promise<string> {
try { try {
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/GetQQLoginQrcode`, { const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQQLoginQrcode`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -161,7 +160,7 @@ export class QQLoginManager {
public async getQQQuickLoginList(): Promise<string[]> { public async getQQQuickLoginList(): Promise<string[]> {
try { try {
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/GetQuickLoginList`, { const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQuickLoginList`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,
@@ -182,7 +181,7 @@ export class QQLoginManager {
public async setQuickLogin(uin: string): Promise<{ result: boolean; errMsg: string }> { public async setQuickLogin(uin: string): Promise<{ result: boolean; errMsg: string }> {
try { try {
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/SetQuickLogin`, { const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/SetQuickLogin`, {
method: 'POST', method: 'POST',
headers: { headers: {
Authorization: 'Bearer ' + this.retCredential, Authorization: 'Bearer ' + this.retCredential,

View File

@@ -4,31 +4,17 @@
<h2 class="sotheby-font">QQ Login</h2> <h2 class="sotheby-font">QQ Login</h2>
<div class="login-methods"> <div class="login-methods">
<t-tooltip content="快速登录"> <t-tooltip content="快速登录">
<t-button <t-button id="quick-login" class="login-method" :class="{ active: loginMethod === 'quick' }"
id="quick-login" @click="loginMethod = 'quick'">Quick Login</t-button>
class="login-method"
:class="{ active: loginMethod === 'quick' }"
@click="loginMethod = 'quick'"
>Quick Login</t-button
>
</t-tooltip> </t-tooltip>
<t-tooltip content="二维码登录"> <t-tooltip content="二维码登录">
<t-button <t-button id="qrcode-login" class="login-method" :class="{ active: loginMethod === 'qrcode' }"
id="qrcode-login" @click="loginMethod = 'qrcode'">QR Code</t-button>
class="login-method"
:class="{ active: loginMethod === 'qrcode' }"
@click="loginMethod = 'qrcode'"
>QR Code</t-button
>
</t-tooltip> </t-tooltip>
</div> </div>
<div v-show="loginMethod === 'quick'" id="quick-login-dropdown" class="login-form"> <div v-show="loginMethod === 'quick'" id="quick-login-dropdown" class="login-form">
<t-select <t-select id="quick-login-select" v-model="selectedAccount" placeholder="Select Account"
id="quick-login-select" @change="selectAccount">
v-model="selectedAccount"
placeholder="Select Account"
@change="selectAccount"
>
<t-option v-for="account in quickLoginList" :key="account" :value="account">{{ account }}</t-option> <t-option v-for="account in quickLoginList" :key="account" :value="account">{{ account }}</t-option>
</t-select> </t-select>
</div> </div>
@@ -41,7 +27,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue'; import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
import * as QRCode from 'qrcode'; import * as QRCode from 'qrcode';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { MessagePlugin } from 'tdesign-vue-next'; import { MessagePlugin } from 'tdesign-vue-next';
@@ -55,6 +41,7 @@ const qrcodeCanvas = ref<HTMLCanvasElement | null>(null);
const qqLoginManager = new QQLoginManager(localStorage.getItem('auth') || ''); const qqLoginManager = new QQLoginManager(localStorage.getItem('auth') || '');
let heartBeatTimer: number | null = null; let heartBeatTimer: number | null = null;
let qrcodeUrl: string = ''; let qrcodeUrl: string = '';
const selectAccount = async (accountName: string): Promise<void> => { const selectAccount = async (accountName: string): Promise<void> => {
const { result, errMsg } = await qqLoginManager.setQuickLogin(accountName); const { result, errMsg } = await qqLoginManager.setQuickLogin(accountName);
if (result) { if (result) {
@@ -88,10 +75,6 @@ const HeartBeat = async (): Promise<void> => {
if (heartBeatTimer) { if (heartBeatTimer) {
clearInterval(heartBeatTimer); clearInterval(heartBeatTimer);
} }
// //判断是否已经调转
// if (router.currentRoute.value.path !== '/dashboard/basic-info') {
// return;
// }
await MessagePlugin.success('登录成功即将跳转'); await MessagePlugin.success('登录成功即将跳转');
await router.push({ path: '/dashboard/basic-info' }); await router.push({ path: '/dashboard/basic-info' });
} else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) { } else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) {
@@ -103,19 +86,38 @@ const HeartBeat = async (): Promise<void> => {
const InitPages = async (): Promise<void> => { const InitPages = async (): Promise<void> => {
quickLoginList.value = await qqLoginManager.getQQQuickLoginList(); quickLoginList.value = await qqLoginManager.getQQQuickLoginList();
qrcodeUrl = await qqLoginManager.getQQLoginQrcode(); qrcodeUrl = await qqLoginManager.getQQLoginQrcode();
await nextTick();
generateQrCode(qrcodeUrl, qrcodeCanvas.value); generateQrCode(qrcodeUrl, qrcodeCanvas.value);
heartBeatTimer = window.setInterval(HeartBeat, 3000);
}; };
onMounted(() => { onMounted(() => {
InitPages(); InitPages().then().catch((err) => {
console.error('InitPages Error:', err);
});
heartBeatTimer = window.setInterval(HeartBeat, 3000);
}); });
onBeforeUnmount(() => {
if (heartBeatTimer) {
clearInterval(heartBeatTimer);
}
});
watch(loginMethod, async (newMethod) => {
if (newMethod === 'qrcode') {
await nextTick();
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
}
});
</script> </script>
<style scoped> <style scoped>
.layout { .layout {
height: 100vh; height: 100vh;
} }
.login-container { .login-container {
padding: 20px; padding: 20px;
border-radius: 5px; border-radius: 5px;

View File

@@ -89,7 +89,11 @@
<t-tag class="tag-item pgk-color"> WebUi: {{ pkg.version }} </t-tag> <t-tag class="tag-item pgk-color"> WebUi: {{ pkg.version }} </t-tag>
<t-tag class="tag-item nc-color"> <t-tag class="tag-item nc-color">
NapCat: NapCat:
{{ githubReleasesData&&githubReleasesData[0] ?.tag_name ? githubReleasesData[0].tag_name : napCatVersion }} {{ napCatVersion }}
</t-tag>
<t-tag v-if="githubReleasesData&&githubReleasesData[0] ?.tag_name" class="tag-item nc-color">
New NapCat:
{{ githubReleasesData[0].tag_name }}
</t-tag> </t-tag>
<t-tag class="tag-item td-color"> TDesign: {{ pkg.dependencies['tdesign-vue-next'] }} </t-tag> <t-tag class="tag-item td-color"> TDesign: {{ pkg.dependencies['tdesign-vue-next'] }} </t-tag>
</span> </span>

View File

@@ -8,6 +8,7 @@ import QQLogin from '../components/QQLogin.vue';
import WebUiLogin from '../components/WebUiLogin.vue'; import WebUiLogin from '../components/WebUiLogin.vue';
import OtherConfig from '../pages/OtherConfig.vue'; import OtherConfig from '../pages/OtherConfig.vue';
import { MessagePlugin } from 'tdesign-vue-next'; import { MessagePlugin } from 'tdesign-vue-next';
import { QQLoginManager } from '@/backend/shell';
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
{ path: '/', redirect: '/webui' }, { path: '/', redirect: '/webui' },
@@ -32,17 +33,22 @@ const router = createRouter({
routes, routes,
}); });
router.beforeEach((to, from, next) => { router.beforeEach(async (to, from, next) => {
const isPublicRoute = ['/webui', '/qqlogin'].includes(to.path);
const token = localStorage.getItem('auth'); const token = localStorage.getItem('auth');
if (!token && to.path !== '/webui' && to.path !== '/qqlogin') {
MessagePlugin.error('Token 过期啦, 重新登录吧'); if (!isPublicRoute) {
localStorage.clear(); if (!token) {
setTimeout(() => { MessagePlugin.error('请先登录');
next('/webui'); return next('/webui');
}, 500);
} else {
next();
} }
const login = await new QQLoginManager(token).checkWebUiLogined();
if (!login) {
MessagePlugin.error('请先登录');
return next('/webui');
}
}
next();
}); });
export default router; export default router;

View File

@@ -1,14 +0,0 @@
import { MessagePlugin } from 'tdesign-vue-next';
import router from '@/router/index.js';
export const request = async (input: RequestInfo | URL, init?: RequestInit) => {
const res = await fetch(input, init);
const json = await res.json();
if (json.message.includes('Unauthorized')) {
MessagePlugin.error('Token 过期啦, 重新登录吧');
localStorage.clear();
router.push('/webui');
}
res.json = async () => json;
return res;
};

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "4.2.28", "version": "4.2.34",
"scripts": { "scripts": {
"build:universal": "npm run build:webui && vite build --mode universal || exit 1", "build:universal": "npm run build:webui && vite build --mode universal || exit 1",
"build:framework": "npm run build:webui && vite build --mode framework || exit 1", "build:framework": "npm run build:webui && vite build --mode framework || exit 1",
@@ -23,8 +23,8 @@
"@eslint/js": "^9.14.0", "@eslint/js": "^9.14.0",
"@log4js-node/log4js-api": "^1.0.2", "@log4js-node/log4js-api": "^1.0.2",
"@napneko/nap-proto-core": "^0.0.4", "@napneko/nap-proto-core": "^0.0.4",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^12.1.2",
"@rollup/plugin-typescript": "^11.1.6", "@rollup/plugin-node-resolve": "^16.0.0",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@sinclair/typebox": "^0.34.9", "@sinclair/typebox": "^0.34.9",
"@types/express": "^5.0.0", "@types/express": "^5.0.0",

View File

@@ -1 +1 @@
export const napCatVersion = '4.2.28'; export const napCatVersion = '4.2.34';

View File

@@ -3,6 +3,7 @@ export interface MiniAppReqCustomParams {
desc: string; desc: string;
picUrl: string; picUrl: string;
jumpUrl: string; jumpUrl: string;
webUrl?: string;
} }
export interface MiniAppReqTemplateParams { export interface MiniAppReqTemplateParams {

View File

@@ -30,7 +30,7 @@ class GetMiniAppAdaptShareInfo extends PacketTransformer<typeof proto.MiniAppAda
shareType: req.shareType, shareType: req.shareType,
versionId: req.versionId, versionId: req.versionId,
withShareTicket: req.withShareTicket, withShareTicket: req.withShareTicket,
webURL: "", webURL: req.webUrl ?? "",
appidRich: Buffer.alloc(0), appidRich: Buffer.alloc(0),
template: { template: {
templateId: "", templateId: "",

View File

@@ -4,6 +4,7 @@ import { GeneralCallResult } from '@/core/services/common';
import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '@/core/types/msg'; import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '@/core/types/msg';
export interface NodeIKernelMsgService { export interface NodeIKernelMsgService {
buildMultiForwardMsg(req: { srcMsgIds: Array<string>, srcContact: Peer }): Promise<GeneralCallResult & { rspInfo: { elements: unknown } }>;
generateMsgUniqueId(chatType: number, time: string): string; generateMsgUniqueId(chatType: number, time: string): string;

View File

@@ -1,5 +1,5 @@
//LiteLoader需要提供部分IPC接口以便于其他插件调用 //LiteLoader需要提供部分IPC接口以便于其他插件调用
const { ipcMain } = require('electron'); const { ipcMain, BrowserWindow } = require('electron');
const napcat = require('./napcat.cjs'); const napcat = require('./napcat.cjs');
const { shell } = require('electron'); const { shell } = require('electron');
ipcMain.handle('napcat_get_webtoken', async (event, arg) => { ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
@@ -14,3 +14,13 @@ ipcMain.handle('napcat_get_reactweb', async (event, arg) => {
let token = url.searchParams.get('token'); let token = url.searchParams.get('token');
return `https://napcat.152710.xyz/web_login?back=http://127.0.0.1:${port}&token=${token}`; return `https://napcat.152710.xyz/web_login?back=http://127.0.0.1:${port}&token=${token}`;
}); });
ipcMain.on('napcat_open_inner_url', (event, url) => {
const win = new BrowserWindow({
autoHideMenuBar: true,
});
win.loadURL(url);
win.webContents.setWindowOpenHandler(details => {
win.loadURL(details.url)
})
});

View File

@@ -6,6 +6,9 @@ const napcat = {
openExternalUrl: async (url) => { openExternalUrl: async (url) => {
ipcRenderer.send('open_external_url', url); ipcRenderer.send('open_external_url', url);
}, },
openInnerUrl: async (url) => {
ipcRenderer.send('napcat_open_inner_url', url);
},
getWebUiUrlReact: async () => { getWebUiUrlReact: async () => {
return ipcRenderer.invoke('napcat_get_reactweb'); return ipcRenderer.invoke('napcat_get_reactweb');
} }

View File

@@ -24,7 +24,7 @@ export const onSettingWindowCreated = async (view) => {
`; `;
view.querySelector('.nc_openwebui').addEventListener('click', () => { view.querySelector('.nc_openwebui').addEventListener('click', () => {
window.open(webui, '_blank'); window.napcat.openInnerUrl(webui);
}); });
view.querySelector('.nc_openwebui_ex').addEventListener('click', () => { view.querySelector('.nc_openwebui_ex').addEventListener('click', () => {
window.napcat.openExternalUrl(webui); window.napcat.openExternalUrl(webui);

View File

@@ -29,7 +29,7 @@ export class OB11Response {
} }
export abstract class OneBotAction<PayloadType, ReturnDataType> { export abstract class OneBotAction<PayloadType, ReturnDataType> {
actionName: ActionName = ActionName.Unknown; actionName: typeof ActionName[keyof typeof ActionName] = ActionName.Unknown;
core: NapCatCore; core: NapCatCore;
private validate: ValidateFunction<any> | undefined = undefined; private validate: ValidateFunction<any> | undefined = undefined;
payloadSchema: any = undefined; payloadSchema: any = undefined;

View File

@@ -11,7 +11,8 @@ const SchemaData = Type.Union([
desc: Type.String(), desc: Type.String(),
picUrl: Type.String(), picUrl: Type.String(),
jumpUrl: Type.String(), jumpUrl: Type.String(),
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()])) webUrl: Type.Optional(Type.String()),
rawArkData: Type.Optional(Type.Union([Type.String()]))
}), }),
Type.Object({ Type.Object({
title: Type.String(), title: Type.String(),
@@ -19,6 +20,7 @@ const SchemaData = Type.Union([
picUrl: Type.String(), picUrl: Type.String(),
jumpUrl: Type.String(), jumpUrl: Type.String(),
iconUrl: Type.String(), iconUrl: Type.String(),
webUrl: Type.Optional(Type.String()),
appId: Type.String(), appId: Type.String(),
scene: Type.Union([Type.Number(), Type.String()]), scene: Type.Union([Type.Number(), Type.String()]),
templateType: Type.Union([Type.Number(), Type.String()]), templateType: Type.Union([Type.Number(), Type.String()]),
@@ -28,7 +30,7 @@ const SchemaData = Type.Union([
versionId: Type.String(), versionId: Type.String(),
sdkId: Type.String(), sdkId: Type.String(),
withShareTicket: Type.Union([Type.Number(), Type.String()]), withShareTicket: Type.Union([Type.Number(), Type.String()]),
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()])) rawArkData: Type.Optional(Type.Union([Type.String()]))
}) })
]); ]);
type Payload = Static<typeof SchemaData>; type Payload = Static<typeof SchemaData>;
@@ -45,7 +47,8 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
title: payload.title, title: payload.title,
desc: payload.desc, desc: payload.desc,
picUrl: payload.picUrl, picUrl: payload.picUrl,
jumpUrl: payload.jumpUrl jumpUrl: payload.jumpUrl,
webUrl: payload.webUrl,
} as MiniAppReqCustomParams; } as MiniAppReqCustomParams;
if ('type' in payload) { if ('type' in payload) {
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template); reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
@@ -63,13 +66,13 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
verType: +verType, verType: +verType,
shareType: +shareType, shareType: +shareType,
versionId: versionId, versionId: versionId,
withShareTicket: +withShareTicket withShareTicket: +withShareTicket,
} }
); );
} }
const arkData = await this.core.apis.PacketApi.pkt.operation.GetMiniAppAdaptShareInfo(reqParam); const arkData = await this.core.apis.PacketApi.pkt.operation.GetMiniAppAdaptShareInfo(reqParam);
return { return {
data: payload.rawArkData ? arkData : MiniAppInfoHelper.RawToSend(arkData) data: payload.rawArkData === 'true' ? arkData : MiniAppInfoHelper.RawToSend(arkData)
}; };
} }
} }

View File

@@ -10,8 +10,7 @@ const SchemaData = Type.Object({
type Payload = Static<typeof SchemaData>; type Payload = Static<typeof SchemaData>;
export class OCRImage extends OneBotAction<Payload, any> { class OCRImageBase extends OneBotAction<Payload, any> {
actionName = ActionName.OCRImage;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
@@ -34,6 +33,10 @@ export class OCRImage extends OneBotAction<Payload, any> {
} }
} }
export class IOCRImage extends OCRImage { export class OCRImage extends OCRImageBase {
actionName = ActionName.OCRImage;
}
export class IOCRImage extends OCRImageBase {
actionName = ActionName.IOCRImage; actionName = ActionName.IOCRImage;
} }

View File

@@ -8,14 +8,18 @@ const SchemaData = Type.Object({
type Payload = Static<typeof SchemaData>; type Payload = Static<typeof SchemaData>;
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> { class SetGroupSignBase extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.SetGroupSign;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
return await this.core.apis.PacketApi.pkt.operation.GroupSign(+payload.group_id); return await this.core.apis.PacketApi.pkt.operation.GroupSign(+payload.group_id);
} }
} }
export class SendGroupSign extends SetGroupSign {
export class SetGroupSign extends SetGroupSignBase {
actionName = ActionName.SendGroupSign;
}
export class SendGroupSign extends SetGroupSignBase {
actionName = ActionName.SendGroupSign; actionName = ActionName.SendGroupSign;
} }

View File

@@ -29,13 +29,14 @@ class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
async _handle(payload: Payload) { async _handle(payload: Payload) {
const isNocache = this.parseBoolean(payload.no_cache ?? true); const isNocache = this.parseBoolean(payload.no_cache ?? true);
const uid = await this.getUid(payload.user_id); const uid = await this.getUid(payload.user_id);
const [member, info] = await Promise.all([ const groupMember = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString())?.get(uid);
let [member, info] = await Promise.all([
this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache), this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache),
this.core.apis.UserApi.getUserDetailInfo(uid), this.core.apis.UserApi.getUserDetailInfo(uid),
]); ]);
if (!member) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`); if (!member || !groupMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
if (info) { if (info) {
Object.assign(member, info); member = { ...groupMember, ...member, ...info };
} else { } else {
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`); this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`);
} }

View File

@@ -1,9 +1,9 @@
import SendMsg, { ContextMode } from '@/onebot/action/msg/SendMsg'; import {ContextMode, SendMsgBase} from '@/onebot/action/msg/SendMsg';
import { ActionName, BaseCheckResult } from '@/onebot/action/router'; import { ActionName, BaseCheckResult } from '@/onebot/action/router';
import { OB11PostSendMsg } from '@/onebot/types'; import { OB11PostSendMsg } from '@/onebot/types';
// 未检测参数 // 未检测参数
class SendGroupMsg extends SendMsg { class SendGroupMsg extends SendMsgBase {
actionName = ActionName.SendGroupMsg; actionName = ActionName.SendGroupMsg;
contextMode: ContextMode = ContextMode.Group; contextMode: ContextMode = ContextMode.Group;

View File

@@ -103,10 +103,7 @@ import { GetAiCharacters } from "@/onebot/action/extends/GetAiCharacters";
import { GetGuildList } from './guild/GetGuildList'; import { GetGuildList } from './guild/GetGuildList';
import { GetGuildProfile } from './guild/GetGuildProfile'; import { GetGuildProfile } from './guild/GetGuildProfile';
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
export type ActionMap = Map<string, OneBotAction<any, any>>;
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore): ActionMap {
const actionHandlers = [ const actionHandlers = [
new GetGroupInfoEx(obContext, core), new GetGroupInfoEx(obContext, core),
@@ -220,12 +217,30 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new SendGroupAiRecord(obContext, core), new SendGroupAiRecord(obContext, core),
new GetAiCharacters(obContext, core), new GetAiCharacters(obContext, core),
]; ];
const actionMap = new Map();
for (const action of actionHandlers) { type HandlerUnion = typeof actionHandlers[number];
actionMap.set(action.actionName, action); type MapType = {
actionMap.set(action.actionName + '_async', action); [H in HandlerUnion as H['actionName']]: H;
actionMap.set(action.actionName + '_rate_limited', action); } & {
[H in HandlerUnion as `${H['actionName']}_async`]: H;
} & {
[H in HandlerUnion as `${H['actionName']}_rate_limited`]: H;
};
const _map = new Map<keyof MapType, HandlerUnion>();
actionHandlers.forEach(h => {
_map.set(h.actionName as keyof MapType, h);
_map.set(`${h.actionName}_async` as keyof MapType, h);
_map.set(`${h.actionName}_rate_limited` as keyof MapType, h);
});
function get<K extends keyof MapType>(key: K): MapType[K];
function get<K extends keyof MapType>(key: K): null;
function get<K extends keyof MapType>(key: K): HandlerUnion | null | MapType[K] {
return _map.get(key as keyof MapType) ?? null;
} }
return actionMap; return { get };
} }
export type ActionMap = ReturnType<typeof createActionMap>

View File

@@ -88,8 +88,7 @@ function getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType
return 0; return 0;
} }
export class SendMsg extends OneBotAction<OB11PostSendMsg, ReturnDataType> { export class SendMsgBase extends OneBotAction<OB11PostSendMsg, ReturnDataType> {
actionName = ActionName.SendMsg;
contextMode = ContextMode.Normal; contextMode = ContextMode.Normal;
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> { protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
@@ -379,4 +378,6 @@ export class SendMsg extends OneBotAction<OB11PostSendMsg, ReturnDataType> {
} }
} }
export default SendMsg; export default class SendMsg extends SendMsgBase {
actionName = ActionName.SendMsg;
}

View File

@@ -1,9 +1,9 @@
import SendMsg, { ContextMode } from './SendMsg'; import {ContextMode, SendMsgBase} from './SendMsg';
import { ActionName, BaseCheckResult } from '@/onebot/action/router'; import { ActionName, BaseCheckResult } from '@/onebot/action/router';
import { OB11PostSendMsg } from '@/onebot/types'; import { OB11PostSendMsg } from '@/onebot/types';
// 未检测参数 // 未检测参数
class SendPrivateMsg extends SendMsg { class SendPrivateMsg extends SendMsgBase {
actionName = ActionName.SendPrivateMsg; actionName = ActionName.SendPrivateMsg;
contextMode: ContextMode = ContextMode.Private; contextMode: ContextMode = ContextMode.Private;

View File

@@ -3,8 +3,6 @@ import { ActionName, BaseCheckResult } from '@/onebot/action/router';
export abstract class GetPacketStatusDepends<PT, RT> extends OneBotAction<PT, RT> { export abstract class GetPacketStatusDepends<PT, RT> extends OneBotAction<PT, RT> {
actionName = ActionName.GetPacketStatus;
protected async check(payload: PT): Promise<BaseCheckResult>{ protected async check(payload: PT): Promise<BaseCheckResult>{
if (!this.core.apis.PacketApi.available) { if (!this.core.apis.PacketApi.available) {
return { return {
@@ -18,6 +16,8 @@ export abstract class GetPacketStatusDepends<PT, RT> extends OneBotAction<PT, RT
} }
export class GetPacketStatus extends GetPacketStatusDepends<any, null> { export class GetPacketStatus extends GetPacketStatusDepends<any, null> {
actionName = ActionName.GetPacketStatus;
async _handle(payload: any) { async _handle(payload: any) {
return null; return null;
} }

View File

@@ -13,134 +13,134 @@ export interface InvalidCheckResult {
[k: string | number]: any; [k: string | number]: any;
} }
export enum ActionName { export const ActionName = {
// onebot 11 // onebot 11
SendPrivateMsg = 'send_private_msg', SendPrivateMsg : 'send_private_msg',
SendGroupMsg = 'send_group_msg', SendGroupMsg : 'send_group_msg',
SendMsg = 'send_msg', SendMsg : 'send_msg',
DeleteMsg = 'delete_msg', DeleteMsg : 'delete_msg',
GetMsg = 'get_msg', GetMsg : 'get_msg',
GoCQHTTP_GetForwardMsg = 'get_forward_msg', GoCQHTTP_GetForwardMsg : 'get_forward_msg',
SendLike = 'send_like', SendLike : 'send_like',
SetGroupKick = 'set_group_kick', SetGroupKick : 'set_group_kick',
SetGroupBan = 'set_group_ban', SetGroupBan : 'set_group_ban',
// SetGroupAnoymousBan = 'set_group_anonymous_ban', // SetGroupAnoymousBan : 'set_group_anonymous_ban',
SetGroupWholeBan = 'set_group_whole_ban', SetGroupWholeBan : 'set_group_whole_ban',
SetGroupAdmin = 'set_group_admin', SetGroupAdmin : 'set_group_admin',
// SetGroupAnoymous = 'set_group_anonymous', // SetGroupAnoymous : 'set_group_anonymous',
SetGroupCard = 'set_group_card', SetGroupCard : 'set_group_card',
SetGroupName = 'set_group_name', SetGroupName : 'set_group_name',
SetGroupLeave = 'set_group_leave', SetGroupLeave : 'set_group_leave',
SetSpecialTittle = 'set_group_special_title', SetSpecialTittle : 'set_group_special_title',
SetFriendAddRequest = 'set_friend_add_request', SetFriendAddRequest : 'set_friend_add_request',
SetGroupAddRequest = 'set_group_add_request', SetGroupAddRequest : 'set_group_add_request',
GetLoginInfo = 'get_login_info', GetLoginInfo : 'get_login_info',
GoCQHTTP_GetStrangerInfo = 'get_stranger_info', GoCQHTTP_GetStrangerInfo : 'get_stranger_info',
GetFriendList = 'get_friend_list', GetFriendList : 'get_friend_list',
GetGroupInfo = 'get_group_info', GetGroupInfo : 'get_group_info',
GetGroupList = 'get_group_list', GetGroupList : 'get_group_list',
GetGroupMemberInfo = 'get_group_member_info', GetGroupMemberInfo : 'get_group_member_info',
GetGroupMemberList = 'get_group_member_list', GetGroupMemberList : 'get_group_member_list',
GetGroupHonorInfo = 'get_group_honor_info', GetGroupHonorInfo : 'get_group_honor_info',
GetCookies = 'get_cookies', GetCookies : 'get_cookies',
GetCSRF = 'get_csrf_token', GetCSRF : 'get_csrf_token',
GetCredentials = 'get_credentials', GetCredentials : 'get_credentials',
GetRecord = 'get_record', GetRecord : 'get_record',
GetImage = 'get_image', GetImage : 'get_image',
CanSendImage = 'can_send_image', CanSendImage : 'can_send_image',
CanSendRecord = 'can_send_record', CanSendRecord : 'can_send_record',
GetStatus = 'get_status', GetStatus : 'get_status',
GetVersionInfo = 'get_version_info', GetVersionInfo : 'get_version_info',
// Reboot = 'set_restart', // Reboot : 'set_restart',
// CleanCache = 'clean_cache', // CleanCache : 'clean_cache',
// go-cqhttp // go-cqhttp
SetQQProfile = 'set_qq_profile', SetQQProfile : 'set_qq_profile',
// QidianGetAccountInfo = 'qidian_get_account_info', // QidianGetAccountInfo : 'qidian_get_account_info',
GoCQHTTP_GetModelShow = '_get_model_show', GoCQHTTP_GetModelShow : '_get_model_show',
GoCQHTTP_SetModelShow = '_set_model_show', GoCQHTTP_SetModelShow : '_set_model_show',
GetOnlineClient = 'get_online_clients', GetOnlineClient : 'get_online_clients',
// GetUnidirectionalFriendList = 'get_unidirectional_friend_list', // GetUnidirectionalFriendList : 'get_unidirectional_friend_list',
GoCQHTTP_DeleteFriend = 'delete_friend', GoCQHTTP_DeleteFriend : 'delete_friend',
// DeleteUnidirectionalFriendList = 'delete_unidirectional_friend', // DeleteUnidirectionalFriendList : 'delete_unidirectional_friend',
GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read', GoCQHTTP_MarkMsgAsRead : 'mark_msg_as_read',
GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg', GoCQHTTP_SendGroupForwardMsg : 'send_group_forward_msg',
GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg', GoCQHTTP_SendPrivateForwardMsg : 'send_private_forward_msg',
GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history', GoCQHTTP_GetGroupMsgHistory : 'get_group_msg_history',
OCRImage = 'ocr_image', OCRImage : 'ocr_image',
IOCRImage = '.ocr_image', IOCRImage : '.ocr_image',
GetGroupSystemMsg = 'get_group_system_msg', GetGroupSystemMsg : 'get_group_system_msg',
GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list', GoCQHTTP_GetEssenceMsg : 'get_essence_msg_list',
GoCQHTTP_GetGroupAtAllRemain = 'get_group_at_all_remain', GoCQHTTP_GetGroupAtAllRemain : 'get_group_at_all_remain',
SetGroupPortrait = 'set_group_portrait', SetGroupPortrait : 'set_group_portrait',
SetEssenceMsg = 'set_essence_msg', SetEssenceMsg : 'set_essence_msg',
DelEssenceMsg = 'delete_essence_msg', DelEssenceMsg : 'delete_essence_msg',
GoCQHTTP_SendGroupNotice = '_send_group_notice', GoCQHTTP_SendGroupNotice : '_send_group_notice',
GoCQHTTP_GetGroupNotice = '_get_group_notice', GoCQHTTP_GetGroupNotice : '_get_group_notice',
GoCQHTTP_UploadGroupFile = 'upload_group_file', GoCQHTTP_UploadGroupFile : 'upload_group_file',
GOCQHTTP_DeleteGroupFile = 'delete_group_file', GOCQHTTP_DeleteGroupFile : 'delete_group_file',
GoCQHTTP_CreateGroupFileFolder = 'create_group_file_folder', GoCQHTTP_CreateGroupFileFolder : 'create_group_file_folder',
GoCQHTTP_DeleteGroupFileFolder = 'delete_group_folder', GoCQHTTP_DeleteGroupFileFolder : 'delete_group_folder',
GoCQHTTP_GetGroupFileSystemInfo = 'get_group_file_system_info', GoCQHTTP_GetGroupFileSystemInfo : 'get_group_file_system_info',
GoCQHTTP_GetGroupRootFiles = 'get_group_root_files', GoCQHTTP_GetGroupRootFiles : 'get_group_root_files',
GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder', GoCQHTTP_GetGroupFilesByFolder : 'get_group_files_by_folder',
GOCQHTTP_GetGroupFileUrl = 'get_group_file_url', GOCQHTTP_GetGroupFileUrl : 'get_group_file_url',
GOCQHTTP_UploadPrivateFile = 'upload_private_file', GOCQHTTP_UploadPrivateFile : 'upload_private_file',
// GOCQHTTP_ReloadEventFilter = 'reload_event_filter', // GOCQHTTP_ReloadEventFilter : 'reload_event_filter',
GoCQHTTP_DownloadFile = 'download_file', GoCQHTTP_DownloadFile : 'download_file',
GoCQHTTP_CheckUrlSafely = 'check_url_safely', GoCQHTTP_CheckUrlSafely : 'check_url_safely',
GoCQHTTP_GetWordSlices = '.get_word_slices', GoCQHTTP_GetWordSlices : '.get_word_slices',
GoCQHTTP_HandleQuickAction = '.handle_quick_operation', GoCQHTTP_HandleQuickAction : '.handle_quick_operation',
// 以下为扩展napcat扩展 // 以下为扩展napcat扩展
Unknown = 'unknown', Unknown : 'unknown',
SharePeer = 'ArkSharePeer', SharePeer : 'ArkSharePeer',
ShareGroupEx = 'ArkShareGroup', ShareGroupEx : 'ArkShareGroup',
// RebootNormal = 'reboot_normal', //无快速登录重新启动 // RebootNormal : 'reboot_normal', //无快速登录重新启动
GetRobotUinRange = 'get_robot_uin_range', GetRobotUinRange : 'get_robot_uin_range',
SetOnlineStatus = 'set_online_status', SetOnlineStatus : 'set_online_status',
GetFriendsWithCategory = 'get_friends_with_category', GetFriendsWithCategory : 'get_friends_with_category',
SetQQAvatar = 'set_qq_avatar', SetQQAvatar : 'set_qq_avatar',
GetFile = 'get_file', GetFile : 'get_file',
ForwardFriendSingleMsg = 'forward_friend_single_msg', ForwardFriendSingleMsg : 'forward_friend_single_msg',
ForwardGroupSingleMsg = 'forward_group_single_msg', ForwardGroupSingleMsg : 'forward_group_single_msg',
TranslateEnWordToZn = 'translate_en2zh', TranslateEnWordToZn : 'translate_en2zh',
SetMsgEmojiLike = 'set_msg_emoji_like', SetMsgEmojiLike : 'set_msg_emoji_like',
GoCQHTTP_SendForwardMsg = 'send_forward_msg', GoCQHTTP_SendForwardMsg : 'send_forward_msg',
MarkPrivateMsgAsRead = 'mark_private_msg_as_read', MarkPrivateMsgAsRead : 'mark_private_msg_as_read',
MarkGroupMsgAsRead = 'mark_group_msg_as_read', MarkGroupMsgAsRead : 'mark_group_msg_as_read',
GetFriendMsgHistory = 'get_friend_msg_history', GetFriendMsgHistory : 'get_friend_msg_history',
CreateCollection = 'create_collection', CreateCollection : 'create_collection',
GetCollectionList = 'get_collection_list', GetCollectionList : 'get_collection_list',
SetLongNick = 'set_self_longnick', SetLongNick : 'set_self_longnick',
GetRecentContact = 'get_recent_contact', GetRecentContact : 'get_recent_contact',
_MarkAllMsgAsRead = '_mark_all_as_read', _MarkAllMsgAsRead : '_mark_all_as_read',
GetProfileLike = 'get_profile_like', GetProfileLike : 'get_profile_like',
FetchCustomFace = 'fetch_custom_face', FetchCustomFace : 'fetch_custom_face',
FetchEmojiLike = 'fetch_emoji_like', FetchEmojiLike : 'fetch_emoji_like',
SetInputStatus = 'set_input_status', SetInputStatus : 'set_input_status',
GetGroupInfoEx = 'get_group_info_ex', GetGroupInfoEx : 'get_group_info_ex',
GetGroupIgnoreAddRequest = 'get_group_ignore_add_request', GetGroupIgnoreAddRequest : 'get_group_ignore_add_request',
DelGroupNotice = '_del_group_notice', DelGroupNotice : '_del_group_notice',
FetchUserProfileLike = 'fetch_user_profile_like', FetchUserProfileLike : 'fetch_user_profile_like',
FriendPoke = 'friend_poke', FriendPoke : 'friend_poke',
GroupPoke = 'group_poke', GroupPoke : 'group_poke',
GetPacketStatus = 'nc_get_packet_status', GetPacketStatus : 'nc_get_packet_status',
GetUserStatus = 'nc_get_user_status', GetUserStatus : 'nc_get_user_status',
GetRkey = 'nc_get_rkey', GetRkey : 'nc_get_rkey',
GetGroupShutList = 'get_group_shut_list', GetGroupShutList : 'get_group_shut_list',
GetGuildList = 'get_guild_list', GetGuildList : 'get_guild_list',
GetGuildProfile = 'get_guild_service_profile', GetGuildProfile : 'get_guild_service_profile',
GetGroupIgnoredNotifies = 'get_group_ignored_notifies', GetGroupIgnoredNotifies : 'get_group_ignored_notifies',
SetGroupSign = "set_group_sign", SetGroupSign : "set_group_sign",
SendGroupSign = "send_group_sign", SendGroupSign : "send_group_sign",
GetMiniAppArk = "get_mini_app_ark", GetMiniAppArk : "get_mini_app_ark",
// UploadForwardMsg = "upload_forward_msg", // UploadForwardMsg : "upload_forward_msg",
GetAiRecord = "get_ai_record", GetAiRecord : "get_ai_record",
GetAiCharacters = "get_ai_characters", GetAiCharacters : "get_ai_characters",
SendGroupAiRecord = "send_group_ai_record", SendGroupAiRecord : "send_group_ai_record",
} } as const;

View File

@@ -1,10 +1,10 @@
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import CanSendRecord from './CanSendRecord'; import CanSendRecord, {CanSend} from './CanSendRecord';
interface ReturnType { interface ReturnType {
yes: boolean; yes: boolean;
} }
export default class CanSendImage extends CanSendRecord { export default class CanSendImage extends CanSend {
actionName = ActionName.CanSendImage; actionName = ActionName.CanSendImage;
} }

View File

@@ -5,12 +5,15 @@ interface ReturnType {
yes: boolean; yes: boolean;
} }
export default class CanSendRecord extends OneBotAction<any, ReturnType> { export class CanSend extends OneBotAction<any, ReturnType> {
actionName = ActionName.CanSendRecord;
async _handle(_payload: void): Promise<ReturnType> { async _handle(_payload: void): Promise<ReturnType> {
return { return {
yes: true, yes: true,
}; };
} }
} }
export default class CanSendRecord extends CanSend{
actionName = ActionName.CanSendRecord;
}

View File

@@ -1,19 +1,5 @@
import type { OneBotFriendApi } from '@/onebot/api/friend';
import type { OneBotUserApi } from '@/onebot/api/user';
import type { OneBotGroupApi } from '@/onebot/api/group';
import type { OneBotMsgApi } from '@/onebot/api/msg';
import type { OneBotQuickActionApi } from '@/onebot/api/quick-action';
export * from './friend'; export * from './friend';
export * from './group'; export * from './group';
export * from './user'; export * from './user';
export * from './msg'; export * from './msg';
export * from './quick-action'; export * from './quick-action';
export interface StableOneBotApiWrapper {
FriendApi: OneBotFriendApi;
UserApi: OneBotUserApi;
GroupApi: OneBotGroupApi;
MsgApi: OneBotMsgApi;
QuickActionApi: OneBotQuickActionApi,
}

View File

@@ -18,8 +18,8 @@ import { ContextMode, createContext, normalize } from '@/onebot/action/msg/SendM
import { isNull } from '@/common/helper'; import { isNull } from '@/common/helper';
export class OneBotQuickActionApi { export class OneBotQuickActionApi {
private obContext: NapCatOneBot11Adapter; obContext: NapCatOneBot11Adapter;
private core: NapCatCore; core: NapCatCore;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) { constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
this.obContext = obContext; this.obContext = obContext;
this.core = core; this.core = core;
@@ -82,11 +82,20 @@ export class OneBotQuickActionApi {
this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles, false).then().catch(e => this.core.context.logger.logError(e)); this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles, false).then().catch(e => this.core.context.logger.logError(e));
} }
} }
async findNotify(flag: string) {
let notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(false, 100)).find(e => e.seq == flag);
if (!notify) {
notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(true, 100)).find(e => e.seq == flag);
}
return notify;
}
async handleGroupRequest(request: OB11GroupRequestEvent, quickAction: QuickActionGroupRequest) { async handleGroupRequest(request: OB11GroupRequestEvent, quickAction: QuickActionGroupRequest) {
if (!isNull(quickAction.approve)) { let noify = await this.findNotify(request.flag);
if (!isNull(quickAction.approve) && noify) {
this.core.apis.GroupApi.handleGroupRequest( this.core.apis.GroupApi.handleGroupRequest(
request.flag, noify,
quickAction.approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE, quickAction.approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,
quickAction.reason, quickAction.reason,
).catch(e => this.core.context.logger.logError(e)); ).catch(e => this.core.context.logger.logError(e));
@@ -94,8 +103,9 @@ export class OneBotQuickActionApi {
} }
async handleFriendRequest(request: OB11FriendRequestEvent, quickAction: QuickActionFriendRequest) { async handleFriendRequest(request: OB11FriendRequestEvent, quickAction: QuickActionFriendRequest) {
if (!isNull(quickAction.approve)) { const notify = (await this.core.apis.FriendApi.getBuddyReq()).buddyReqs.find(e => e.reqTime == request.flag.toString());
this.core.apis.FriendApi.handleFriendRequest(request.flag, !!quickAction.approve).then().catch(e => this.core.context.logger.logError(e)); if (!isNull(quickAction.approve) && notify) {
this.core.apis.FriendApi.handleFriendRequest(notify, !!quickAction.approve).then().catch(e => this.core.context.logger.logError(e));
} }
} }
} }

View File

@@ -31,7 +31,6 @@ import {
OneBotMsgApi, OneBotMsgApi,
OneBotQuickActionApi, OneBotQuickActionApi,
OneBotUserApi, OneBotUserApi,
StableOneBotApiWrapper,
} from '@/onebot/api'; } from '@/onebot/api';
import { ActionMap, createActionMap } from '@/onebot/action'; import { ActionMap, createActionMap } from '@/onebot/action';
import { WebUiDataRuntime } from '@/webui/src/helper/Data'; import { WebUiDataRuntime } from '@/webui/src/helper/Data';
@@ -55,7 +54,7 @@ export class NapCatOneBot11Adapter {
readonly context: InstanceContext; readonly context: InstanceContext;
configLoader: OB11ConfigLoader; configLoader: OB11ConfigLoader;
public readonly apis: StableOneBotApiWrapper; public readonly apis;
networkManager: OB11NetworkManager; networkManager: OB11NetworkManager;
actions: ActionMap; actions: ActionMap;
private readonly bootTime = Date.now() / 1000; private readonly bootTime = Date.now() / 1000;
@@ -72,7 +71,7 @@ export class NapCatOneBot11Adapter {
UserApi: new OneBotUserApi(this, core), UserApi: new OneBotUserApi(this, core),
FriendApi: new OneBotFriendApi(this, core), FriendApi: new OneBotFriendApi(this, core),
MsgApi: new OneBotMsgApi(this, core), MsgApi: new OneBotMsgApi(this, core),
QuickActionApi: new OneBotQuickActionApi(this, core), QuickActionApi: new OneBotQuickActionApi(this, core)
} as const; } as const;
this.actions = createActionMap(this, core); this.actions = createActionMap(this, core);
this.networkManager = new OB11NetworkManager(); this.networkManager = new OB11NetworkManager();
@@ -157,9 +156,9 @@ export class NapCatOneBot11Adapter {
this.initBuddyListener(); this.initBuddyListener();
this.initGroupListener(); this.initGroupListener();
await WebUiDataRuntime.setQQLoginUin(selfInfo.uin.toString()); WebUiDataRuntime.setQQLoginInfo(selfInfo);
await WebUiDataRuntime.setQQLoginStatus(true); WebUiDataRuntime.setQQLoginStatus(true);
await WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => { WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
const prev = this.configLoader.configData; const prev = this.configLoader.configData;
this.configLoader.save(newConfig); this.configLoader.save(newConfig);
this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);

View File

@@ -11,7 +11,8 @@ import { ActionMap } from '@/onebot/action';
export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter { export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter {
logger: LogWrapper; logger: LogWrapper;
isEnable: boolean = false; isEnable: boolean = false;
public config: HttpClientConfig; config: HttpClientConfig;
constructor( constructor(
public name: string, public name: string,
config: HttpClientConfig, config: HttpClientConfig,
@@ -24,39 +25,30 @@ export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter {
} }
onEvent<T extends OB11EmitEventContent>(event: T) { onEvent<T extends OB11EmitEventContent>(event: T) {
if (!this.isEnable) { this.emitEventAsync(event).catch(e => this.logger.logError('[OneBot] [Http Client] 新消息事件HTTP上报返回快速操作失败', e));
return;
} }
async emitEventAsync<T extends OB11EmitEventContent>(event: T) {
if (!this.isEnable) return;
const headers: Record<string, string> = { const headers: Record<string, string> = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-self-id': this.core.selfInfo.uin, 'x-self-id': this.core.selfInfo.uin,
}; };
const msgStr = JSON.stringify(event); const msgStr = JSON.stringify(event);
if (this.config.token && this.config.token.length > 0) { if (this.config.token) {
const hmac = createHmac('sha1', this.config.token); const hmac = createHmac('sha1', this.config.token);
hmac.update(msgStr); hmac.update(msgStr);
const sig = hmac.digest('hex'); headers['x-signature'] = 'sha1=' + hmac.digest('hex');
headers['x-signature'] = 'sha1=' + sig;
} }
RequestUtil.HttpGetText(this.config.url, 'POST', msgStr, headers).then(async (res) => {
let resJson: QuickAction; const data = await RequestUtil.HttpGetText(this.config.url, 'POST', msgStr, headers);
try { const resJson: QuickAction = data ? JSON.parse(data) : {};
resJson = JSON.parse(res);
//logDebug('新消息事件HTTP上报返回快速操作: ', JSON.stringify(resJson)); if (!this.obContext.apis || !this.obContext.apis.QuickActionApi.handleQuickOperation) {
} catch (e) { throw new Error('apis.QuickActionApi.handleQuickOperation 异常');
this.logger.logDebug('[OneBot] [Http Client] 新消息事件HTTP上报没有返回快速操作不需要处理');
return;
} }
try { await this.obContext.apis.QuickActionApi.handleQuickOperation(event as QuickActionEvent, resJson);
this.obContext.apis.QuickActionApi
.handleQuickOperation(event as QuickActionEvent, resJson)
.catch(e => this.logger.logError(e));
} catch (e: any) {
this.logger.logError('[OneBot] [Http Client] 新消息事件HTTP上报返回快速操作失败', e);
}
}).catch((e) => {
this.logger.logError('[OneBot] [Http Client] 新消息事件HTTP上报失败', e);
});
} }
open() { open() {
@@ -66,20 +58,24 @@ export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter {
close() { close() {
this.isEnable = false; this.isEnable = false;
} }
async reload(newconfig: HttpClientConfig) {
async reload(newConfig: HttpClientConfig) {
const wasEnabled = this.isEnable; const wasEnabled = this.isEnable;
const oldUrl = this.config.url; const oldUrl = this.config.url;
this.config = newconfig; this.config = newConfig;
if (newconfig.enable && !wasEnabled) {
if (newConfig.enable && !wasEnabled) {
this.open(); this.open();
return OB11NetworkReloadType.NetWorkOpen; return OB11NetworkReloadType.NetWorkOpen;
} else if (!newconfig.enable && wasEnabled) { } else if (!newConfig.enable && wasEnabled) {
this.close(); this.close();
return OB11NetworkReloadType.NetWorkClose; return OB11NetworkReloadType.NetWorkClose;
} }
if (oldUrl !== newconfig.url) {
if (oldUrl !== newConfig.url) {
return OB11NetworkReloadType.NetWorkReload; return OB11NetworkReloadType.NetWorkReload;
} }
return OB11NetworkReloadType.Normal; return OB11NetworkReloadType.Normal;
} }
} }

View File

@@ -133,7 +133,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
} }
private async handleMessage(message: any) { private async handleMessage(message: any) {
let receiveData: { action: ActionName, params?: any, echo?: any } = { action: ActionName.Unknown, params: {} }; let receiveData: { action: typeof ActionName[keyof typeof ActionName], params?: any, echo?: any } = { action: ActionName.Unknown, params: {} };
let echo = undefined; let echo = undefined;
try { try {
@@ -145,7 +145,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
return; return;
} }
receiveData.params = (receiveData?.params) ? receiveData.params : {};// 兼容类型验证 receiveData.params = (receiveData?.params) ? receiveData.params : {};// 兼容类型验证
const action = this.actions.get(receiveData.action); const action = this.actions.get(receiveData.action as any);
if (!action) { if (!action) {
this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的Api ' + receiveData.action); this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的Api ' + receiveData.action);
this.checkStateAndReply<any>(OB11Response.error('不支持的Api ' + receiveData.action, 1404, echo)); this.checkStateAndReply<any>(OB11Response.error('不支持的Api ' + receiveData.action, 1404, echo));

View File

@@ -105,7 +105,7 @@ export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter {
return res.json(hello); return res.json(hello);
} }
const actionName = req.path.split('/')[1]; const actionName = req.path.split('/')[1];
const action = this.actions.get(actionName); const action = this.actions.get(actionName as any);
if (action) { if (action) {
try { try {
const result = await action.handle(payload, this.name); const result = await action.handle(payload, this.name);

View File

@@ -166,7 +166,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
} }
private async handleMessage(wsClient: WebSocket, message: any) { private async handleMessage(wsClient: WebSocket, message: any) {
let receiveData: { action: ActionName, params?: any, echo?: any } = { action: ActionName.Unknown, params: {} }; let receiveData: { action: typeof ActionName[keyof typeof ActionName], params?: any, echo?: any } = { action: ActionName.Unknown, params: {} };
let echo = undefined; let echo = undefined;
try { try {
receiveData = JSON.parse(message.toString()); receiveData = JSON.parse(message.toString());
@@ -177,7 +177,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
return; return;
} }
receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证 不然类型校验爆炸 receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证 不然类型校验爆炸
const action = this.actions.get(receiveData.action); const action = this.actions.get(receiveData.action as any);
if (!action) { if (!action) {
this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的API ' + receiveData.action); this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的API ' + receiveData.action);
this.checkStateAndReply<any>(OB11Response.error('不支持的API ' + receiveData.action, 1404, echo), wsClient); this.checkStateAndReply<any>(OB11Response.error('不支持的API ' + receiveData.action, 1404, echo), wsClient);

View File

@@ -1,9 +1,9 @@
import { IOB11NetworkAdapter, OB11EmitEventContent, OB11NetworkReloadType } from './index'; import { IOB11NetworkAdapter, OB11EmitEventContent, OB11NetworkReloadType } from './index';
import { NapCatOneBot11Adapter, OB11Message } from '@/onebot'; import { NapCatOneBot11Adapter, OB11Message } from '@/onebot';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
import { ActionMap } from '../action';
import { AdapterConfig } from '../config/config'; import { AdapterConfig } from '../config/config';
import { plugin_onmessage } from '@/plugin'; import { plugin_onmessage } from '@/plugin';
import { ActionMap } from '../action';
export class OB11PluginAdapter implements IOB11NetworkAdapter { export class OB11PluginAdapter implements IOB11NetworkAdapter {
isEnable: boolean = true; isEnable: boolean = true;
@@ -27,7 +27,7 @@ export class OB11PluginAdapter implements IOB11NetworkAdapter {
onEvent<T extends OB11EmitEventContent>(event: T) { onEvent<T extends OB11EmitEventContent>(event: T) {
if (event.post_type === 'message') { if (event.post_type === 'message') {
plugin_onmessage(this.config.name, this.core, this.obCore, event as OB11Message).then().catch(); plugin_onmessage(this.config.name, this.core, this.obCore, event as OB11Message,this.actions).then().catch();
} }
} }

View File

@@ -1,10 +1,10 @@
import { NapCatOneBot11Adapter, OB11Message } from "@/onebot"; import { NapCatOneBot11Adapter, OB11Message } from "@/onebot";
import { NapCatCore } from "../core"; import { NapCatCore } from "../core";
import { SetSpecialTittle } from "@/onebot/action/extends/SetSpecialTittle"; import { ActionMap } from "@/onebot/action";
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCore: NapCatOneBot11Adapter, message: OB11Message) => { export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCore: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap) => {
if (message.raw_message.startsWith('设置头衔') && message.group_id) { if (message.raw_message === 'ping') {
const ret = await new SetSpecialTittle(obCore, core) const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter);
.handle({ group_id: message.group_id, user_id: message.user_id, special_title: message.raw_message.replace('设置头衔', '') }, adapter); console.log(ret);
} }
} }

View File

@@ -175,7 +175,9 @@ async function handleLogin(
loginService.getLoginList().then((res) => { loginService.getLoginList().then((res) => {
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList // 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString())); const list = res.LocalLoginInfoList.filter((item) => item.isQuickLogin);
WebUiDataRuntime.setQQQuickLoginList(list.map((item) => item.uin.toString()));
WebUiDataRuntime.setQQNewLoginList(list);
}); });
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => { WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
@@ -354,8 +356,6 @@ export class NapCatShell {
}; };
this.core = new NapCatCore(this.context, selfInfo); this.core = new NapCatCore(this.context, selfInfo);
} }
async InitNapCat() { async InitNapCat() {
await this.core.initCore(); await this.core.initCore();

View File

@@ -18,7 +18,7 @@ export const LoginHandler: RequestHandler = async (req, res) => {
return sendError(res, 'token is empty'); return sendError(res, 'token is empty');
} }
// 检查登录频率 // 检查登录频率
if (!(await WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate))) { if (!WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate)) {
return sendError(res, 'login rate limit'); return sendError(res, 'login rate limit');
} }
//验证config.token是否等于token //验证config.token是否等于token

View File

@@ -1,15 +1,9 @@
import { RequestHandler } from 'express'; import { RequestHandler } from 'express';
import { WebUiDataRuntime } from '@webapi/helper/Data';
import { sendSuccess } from '@webapi/utils/response'; import { sendSuccess } from '@webapi/utils/response';
// TODO: Implement LogFileListHandler export const PackageInfoHandler: RequestHandler = (_, res) => {
export const LogFileListHandler: RequestHandler = async (_, res) => { const data = WebUiDataRuntime.getPackageJson();
const fakeData = { sendSuccess(res, data);
uin: 0,
nick: 'NapCat',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=0&s=640',
status: 'online',
boottime: Date.now(),
};
sendSuccess(res, fakeData);
}; };

View File

@@ -10,15 +10,15 @@ import { sendError, sendSuccess } from '@webapi/utils/response';
import { isEmpty } from '@webapi/utils/check'; import { isEmpty } from '@webapi/utils/check';
// 获取OneBot11配置 // 获取OneBot11配置
export const OB11GetConfigHandler: RequestHandler = async (_, res) => { export const OB11GetConfigHandler: RequestHandler = (_, res) => {
// 获取QQ登录状态 // 获取QQ登录状态
const isLogin = await WebUiDataRuntime.getQQLoginStatus(); const isLogin = WebUiDataRuntime.getQQLoginStatus();
// 如果未登录,返回错误 // 如果未登录,返回错误
if (!isLogin) { if (!isLogin) {
return sendError(res, 'Not Login'); return sendError(res, 'Not Login');
} }
// 获取登录的QQ号 // 获取登录的QQ号
const uin = await WebUiDataRuntime.getQQLoginUin(); const uin = WebUiDataRuntime.getQQLoginUin();
// 读取配置文件 // 读取配置文件
const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`); const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`);
// 尝试解析配置文件 // 尝试解析配置文件
@@ -39,7 +39,7 @@ export const OB11GetConfigHandler: RequestHandler = async (_, res) => {
// 写入OneBot11配置 // 写入OneBot11配置
export const OB11SetConfigHandler: RequestHandler = async (req, res) => { export const OB11SetConfigHandler: RequestHandler = async (req, res) => {
// 获取QQ登录状态 // 获取QQ登录状态
const isLogin = await WebUiDataRuntime.getQQLoginStatus(); const isLogin = WebUiDataRuntime.getQQLoginStatus();
// 如果未登录,返回错误 // 如果未登录,返回错误
if (!isLogin) { if (!isLogin) {
return sendError(res, 'Not Login'); return sendError(res, 'Not Login');

View File

@@ -7,12 +7,12 @@ import { sendError, sendSuccess } from '@webapi/utils/response';
// 获取QQ登录二维码 // 获取QQ登录二维码
export const QQGetQRcodeHandler: RequestHandler = async (req, res) => { export const QQGetQRcodeHandler: RequestHandler = async (req, res) => {
// 判断是否已经登录 // 判断是否已经登录
if (await WebUiDataRuntime.getQQLoginStatus()) { if (WebUiDataRuntime.getQQLoginStatus()) {
// 已经登录 // 已经登录
return sendError(res, 'QQ Is Logined'); return sendError(res, 'QQ Is Logined');
} }
// 获取二维码 // 获取二维码
const qrcodeUrl = await WebUiDataRuntime.getQQLoginQrcodeURL(); const qrcodeUrl = WebUiDataRuntime.getQQLoginQrcodeURL();
// 判断二维码是否为空 // 判断二维码是否为空
if (isEmpty(qrcodeUrl)) { if (isEmpty(qrcodeUrl)) {
return sendError(res, 'QRCode Get Error'); return sendError(res, 'QRCode Get Error');
@@ -27,8 +27,8 @@ export const QQGetQRcodeHandler: RequestHandler = async (req, res) => {
// 获取QQ登录状态 // 获取QQ登录状态
export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => { export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => {
const data = { const data = {
isLogin: await WebUiDataRuntime.getQQLoginStatus(), isLogin: WebUiDataRuntime.getQQLoginStatus(),
qrcodeurl: await WebUiDataRuntime.getQQLoginQrcodeURL(), qrcodeurl: WebUiDataRuntime.getQQLoginQrcodeURL(),
}; };
return sendSuccess(res, data); return sendSuccess(res, data);
}; };
@@ -38,7 +38,7 @@ export const QQSetQuickLoginHandler: RequestHandler = async (req, res) => {
// 获取QQ号 // 获取QQ号
const { uin } = req.body; const { uin } = req.body;
// 判断是否已经登录 // 判断是否已经登录
const isLogin = await WebUiDataRuntime.getQQLoginStatus(); const isLogin = WebUiDataRuntime.getQQLoginStatus();
if (isLogin) { if (isLogin) {
return sendError(res, 'QQ Is Logined'); return sendError(res, 'QQ Is Logined');
} }
@@ -53,12 +53,24 @@ export const QQSetQuickLoginHandler: RequestHandler = async (req, res) => {
return sendError(res, message); return sendError(res, message);
} }
//本来应该验证 但是http不宜这么搞 建议前端验证 //本来应该验证 但是http不宜这么搞 建议前端验证
//isLogin = await WebUiDataRuntime.getQQLoginStatus(); //isLogin = WebUiDataRuntime.getQQLoginStatus();
return sendSuccess(res, null); return sendSuccess(res, null);
}; };
// 获取快速登录列表 // 获取快速登录列表
export const QQGetQuickLoginListHandler: RequestHandler = async (_, res) => { export const QQGetQuickLoginListHandler: RequestHandler = async (_, res) => {
const quickLoginList = await WebUiDataRuntime.getQQQuickLoginList(); const quickLoginList = WebUiDataRuntime.getQQQuickLoginList();
return sendSuccess(res, quickLoginList); return sendSuccess(res, quickLoginList);
}; };
// 获取快速登录列表(新)
export const QQGetLoginListNewHandler: RequestHandler = async (_, res) => {
const newLoginList = WebUiDataRuntime.getQQNewLoginList();
return sendSuccess(res, newLoginList);
};
// 获取登录的QQ的信息
export const getQQLoginInfoHandler: RequestHandler = async (_, res) => {
const data = WebUiDataRuntime.getQQLoginInfo();
return sendSuccess(res, data);
};

View File

@@ -1,11 +1,16 @@
import { OneBotConfig } from '@/onebot/config/config'; import type { LoginRuntimeType } from '../types/data';
import packageJson from '../../../../package.json';
const LoginRuntime: LoginRuntimeType = { const LoginRuntime: LoginRuntimeType = {
LoginCurrentTime: Date.now(), LoginCurrentTime: Date.now(),
LoginCurrentRate: 0, LoginCurrentRate: 0,
QQLoginStatus: false, //已实现 但太傻了 得去那边注册个回调刷新 QQLoginStatus: false, //已实现 但太傻了 得去那边注册个回调刷新
QQQRCodeURL: '', QQQRCodeURL: '',
QQLoginUin: '', QQLoginUin: '',
QQLoginInfo: {
uid: '',
uin: '',
nick: '',
},
NapCatHelper: { NapCatHelper: {
onOB11ConfigChanged: async () => { onOB11ConfigChanged: async () => {
return; return;
@@ -14,11 +19,13 @@ const LoginRuntime: LoginRuntimeType = {
return { result: false, message: '' }; return { result: false, message: '' };
}, },
QQLoginList: [], QQLoginList: [],
NewQQLoginList: [],
}, },
packageJson: packageJson,
}; };
export const WebUiDataRuntime = { export const WebUiDataRuntime = {
checkLoginRate: async function (RateLimit: number): Promise<boolean> { checkLoginRate(RateLimit: number): boolean {
LoginRuntime.LoginCurrentRate++; LoginRuntime.LoginCurrentRate++;
//console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime); //console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime);
if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) { if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) {
@@ -29,51 +36,68 @@ export const WebUiDataRuntime = {
return LoginRuntime.LoginCurrentRate <= RateLimit; return LoginRuntime.LoginCurrentRate <= RateLimit;
}, },
getQQLoginStatus: async function (): Promise<boolean> { getQQLoginStatus(): LoginRuntimeType['QQLoginStatus'] {
return LoginRuntime.QQLoginStatus; return LoginRuntime.QQLoginStatus;
}, },
setQQLoginStatus: async function (status: boolean): Promise<void> { setQQLoginStatus(status: LoginRuntimeType['QQLoginStatus']): void {
LoginRuntime.QQLoginStatus = status; LoginRuntime.QQLoginStatus = status;
}, },
setQQLoginQrcodeURL: async function (url: string): Promise<void> { setQQLoginQrcodeURL(url: LoginRuntimeType['QQQRCodeURL']): void {
LoginRuntime.QQQRCodeURL = url; LoginRuntime.QQQRCodeURL = url;
}, },
getQQLoginQrcodeURL: async function (): Promise<string> { getQQLoginQrcodeURL(): LoginRuntimeType['QQQRCodeURL'] {
return LoginRuntime.QQQRCodeURL; return LoginRuntime.QQQRCodeURL;
}, },
setQQLoginUin: async function (uin: string): Promise<void> { setQQLoginInfo(info: LoginRuntimeType['QQLoginInfo']): void {
LoginRuntime.QQLoginUin = uin; LoginRuntime.QQLoginInfo = info;
LoginRuntime.QQLoginUin = info.uin.toString();
}, },
getQQLoginUin: async function (): Promise<string> { getQQLoginInfo(): LoginRuntimeType['QQLoginInfo'] {
return LoginRuntime.QQLoginInfo;
},
getQQLoginUin(): LoginRuntimeType['QQLoginUin'] {
return LoginRuntime.QQLoginUin; return LoginRuntime.QQLoginUin;
}, },
getQQQuickLoginList: async function (): Promise<any[]> { getQQQuickLoginList(): LoginRuntimeType['NapCatHelper']['QQLoginList'] {
return LoginRuntime.NapCatHelper.QQLoginList; return LoginRuntime.NapCatHelper.QQLoginList;
}, },
setQQQuickLoginList: async function (list: string[]): Promise<void> { setQQQuickLoginList(list: LoginRuntimeType['NapCatHelper']['QQLoginList']): void {
LoginRuntime.NapCatHelper.QQLoginList = list; LoginRuntime.NapCatHelper.QQLoginList = list;
}, },
setQuickLoginCall(func: (uin: string) => Promise<{ result: boolean; message: string }>): void { getQQNewLoginList(): LoginRuntimeType['NapCatHelper']['NewQQLoginList'] {
return LoginRuntime.NapCatHelper.NewQQLoginList;
},
setQQNewLoginList(list: LoginRuntimeType['NapCatHelper']['NewQQLoginList']): void {
LoginRuntime.NapCatHelper.NewQQLoginList = list;
},
setQuickLoginCall(func: LoginRuntimeType['NapCatHelper']['onQuickLoginRequested']): void {
LoginRuntime.NapCatHelper.onQuickLoginRequested = func; LoginRuntime.NapCatHelper.onQuickLoginRequested = func;
}, },
requestQuickLogin: async function (uin: string): Promise<{ result: boolean; message: string }> { requestQuickLogin: function (uin) {
return await LoginRuntime.NapCatHelper.onQuickLoginRequested(uin); return LoginRuntime.NapCatHelper.onQuickLoginRequested(uin);
}, } as LoginRuntimeType['NapCatHelper']['onQuickLoginRequested'],
setOnOB11ConfigChanged: async function (func: (ob11: OneBotConfig) => Promise<void>): Promise<void> { setOnOB11ConfigChanged(func: LoginRuntimeType['NapCatHelper']['onOB11ConfigChanged']): void {
LoginRuntime.NapCatHelper.onOB11ConfigChanged = func; LoginRuntime.NapCatHelper.onOB11ConfigChanged = func;
}, },
setOB11Config: async function (ob11: OneBotConfig): Promise<void> { setOB11Config: function (ob11) {
await LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11); return LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
} as LoginRuntimeType['NapCatHelper']['onOB11ConfigChanged'],
getPackageJson() {
return LoginRuntime.packageJson;
}, },
}; };

View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { PackageInfoHandler } from '../api/BaseInfo';
const router = Router();
// router: 获取nc的package.json信息
router.get('/PackageInfo', PackageInfoHandler);
export { router as BaseRouter };

View File

@@ -5,16 +5,22 @@ import {
QQGetQRcodeHandler, QQGetQRcodeHandler,
QQGetQuickLoginListHandler, QQGetQuickLoginListHandler,
QQSetQuickLoginHandler, QQSetQuickLoginHandler,
QQGetLoginListNewHandler,
getQQLoginInfoHandler,
} from '@webapi/api/QQLogin'; } from '@webapi/api/QQLogin';
const router = Router(); const router = Router();
// router:获取快速登录列表 // router:获取快速登录列表
router.all('/GetQuickLoginList', QQGetQuickLoginListHandler); router.all('/GetQuickLoginList', QQGetQuickLoginListHandler);
// router:获取快速登录列表(新)
router.all('/GetQuickLoginListNew', QQGetLoginListNewHandler);
// router:检查QQ登录状态 // router:检查QQ登录状态
router.post('/CheckLoginStatus', QQCheckLoginStatusHandler); router.post('/CheckLoginStatus', QQCheckLoginStatusHandler);
// router:获取QQ登录二维码 // router:获取QQ登录二维码
router.post('/GetQQLoginQrcode', QQGetQRcodeHandler); router.post('/GetQQLoginQrcode', QQGetQRcodeHandler);
// router:设置QQ快速登录 // router:设置QQ快速登录
router.post('/SetQuickLogin', QQSetQuickLoginHandler); router.post('/SetQuickLogin', QQSetQuickLoginHandler);
// router:获取QQ登录信息
router.post('/GetQQLoginInfo', getQQLoginInfoHandler);
export { router as QQLoginRouter }; export { router as QQLoginRouter };

View File

@@ -11,6 +11,7 @@ import { sendSuccess } from '@webapi/utils/response';
import { QQLoginRouter } from '@webapi/router/QQLogin'; import { QQLoginRouter } from '@webapi/router/QQLogin';
import { AuthRouter } from '@webapi/router/auth'; import { AuthRouter } from '@webapi/router/auth';
import { LogRouter } from '@webapi/router/Log'; import { LogRouter } from '@webapi/router/Log';
import { BaseRouter } from '@webapi/router/Base';
const router = Router(); const router = Router();
@@ -21,6 +22,8 @@ router.use(auth);
router.all('/test', (_, res) => { router.all('/test', (_, res) => {
return sendSuccess(res); return sendSuccess(res);
}); });
// router:基础信息相关路由
router.use('/base', BaseRouter);
// router:WebUI登录相关路由 // router:WebUI登录相关路由
router.use('/auth', AuthRouter); router.use('/auth', AuthRouter);
// router:QQ登录相关路由 // router:QQ登录相关路由

View File

@@ -1,12 +1,17 @@
import type { LoginListItem, SelfInfo } from '@/core';
interface LoginRuntimeType { interface LoginRuntimeType {
LoginCurrentTime: number; LoginCurrentTime: number;
LoginCurrentRate: number; LoginCurrentRate: number;
QQLoginStatus: boolean; QQLoginStatus: boolean;
QQQRCodeURL: string; QQQRCodeURL: string;
QQLoginUin: string; QQLoginUin: string;
QQLoginInfo: SelfInfo;
NapCatHelper: { NapCatHelper: {
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>; onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>;
onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>; onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>;
QQLoginList: string[]; QQLoginList: string[];
NewQQLoginList: LoginListItem[];
}; };
packageJson: object;
} }