Compare commits

...

20 Commits

Author SHA1 Message Date
手瓜一十雪
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
43 changed files with 422 additions and 331 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
//LiteLoader需要提供部分IPC接口以便于其他插件调用
const { ipcMain } = require('electron');
const { ipcMain, BrowserWindow } = require('electron');
const napcat = require('./napcat.cjs');
const { shell } = require('electron');
ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
@@ -13,4 +13,14 @@ ipcMain.handle('napcat_get_reactweb', async (event, arg) => {
let port = url.port;
let token = url.searchParams.get('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) => {
ipcRenderer.send('open_external_url', url);
},
openInnerUrl: async (url) => {
ipcRenderer.send('napcat_open_inner_url', url);
},
getWebUiUrlReact: async () => {
return ipcRenderer.invoke('napcat_get_reactweb');
}

View File

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

View File

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

View File

@@ -11,7 +11,8 @@ const SchemaData = Type.Union([
desc: Type.String(),
picUrl: 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({
title: Type.String(),
@@ -19,6 +20,7 @@ const SchemaData = Type.Union([
picUrl: Type.String(),
jumpUrl: Type.String(),
iconUrl: Type.String(),
webUrl: Type.Optional(Type.String()),
appId: Type.String(),
scene: Type.Union([Type.Number(), Type.String()]),
templateType: Type.Union([Type.Number(), Type.String()]),
@@ -28,7 +30,7 @@ const SchemaData = Type.Union([
versionId: Type.String(),
sdkId: 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>;
@@ -45,7 +47,8 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
title: payload.title,
desc: payload.desc,
picUrl: payload.picUrl,
jumpUrl: payload.jumpUrl
jumpUrl: payload.jumpUrl,
webUrl: payload.webUrl,
} as MiniAppReqCustomParams;
if ('type' in payload) {
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
@@ -63,13 +66,13 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
verType: +verType,
shareType: +shareType,
versionId: versionId,
withShareTicket: +withShareTicket
withShareTicket: +withShareTicket,
}
);
}
const arkData = await this.core.apis.PacketApi.pkt.operation.GetMiniAppAdaptShareInfo(reqParam);
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>;
export class OCRImage extends OneBotAction<Payload, any> {
actionName = ActionName.OCRImage;
class OCRImageBase extends OneBotAction<Payload, any> {
payloadSchema = SchemaData;
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;
}

View File

@@ -8,14 +8,18 @@ const SchemaData = Type.Object({
type Payload = Static<typeof SchemaData>;
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.SetGroupSign;
class SetGroupSignBase extends GetPacketStatusDepends<Payload, any> {
payloadSchema = SchemaData;
async _handle(payload: Payload) {
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;
}

View File

@@ -29,13 +29,14 @@ class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
async _handle(payload: Payload) {
const isNocache = this.parseBoolean(payload.no_cache ?? true);
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.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) {
Object.assign(member, info);
member = { ...groupMember, ...member, ...info };
} else {
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 { OB11PostSendMsg } from '@/onebot/types';
// 未检测参数
class SendGroupMsg extends SendMsg {
class SendGroupMsg extends SendMsgBase {
actionName = ActionName.SendGroupMsg;
contextMode: ContextMode = ContextMode.Group;

View File

@@ -103,10 +103,7 @@ import { GetAiCharacters } from "@/onebot/action/extends/GetAiCharacters";
import { GetGuildList } from './guild/GetGuildList';
import { GetGuildProfile } from './guild/GetGuildProfile';
export type ActionMap = Map<string, OneBotAction<any, any>>;
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore): ActionMap {
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
const actionHandlers = [
new GetGroupInfoEx(obContext, core),
@@ -220,12 +217,30 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new SendGroupAiRecord(obContext, core),
new GetAiCharacters(obContext, core),
];
const actionMap = new Map();
for (const action of actionHandlers) {
actionMap.set(action.actionName, action);
actionMap.set(action.actionName + '_async', action);
actionMap.set(action.actionName + '_rate_limited', action);
type HandlerUnion = typeof actionHandlers[number];
type MapType = {
[H in HandlerUnion as H['actionName']]: H;
} & {
[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;
}
export class SendMsg extends OneBotAction<OB11PostSendMsg, ReturnDataType> {
actionName = ActionName.SendMsg;
export class SendMsgBase extends OneBotAction<OB11PostSendMsg, ReturnDataType> {
contextMode = ContextMode.Normal;
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 { OB11PostSendMsg } from '@/onebot/types';
// 未检测参数
class SendPrivateMsg extends SendMsg {
class SendPrivateMsg extends SendMsgBase {
actionName = ActionName.SendPrivateMsg;
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> {
actionName = ActionName.GetPacketStatus;
protected async check(payload: PT): Promise<BaseCheckResult>{
if (!this.core.apis.PacketApi.available) {
return {
@@ -18,6 +16,8 @@ export abstract class GetPacketStatusDepends<PT, RT> extends OneBotAction<PT, RT
}
export class GetPacketStatus extends GetPacketStatusDepends<any, null> {
actionName = ActionName.GetPacketStatus;
async _handle(payload: any) {
return null;
}

View File

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

View File

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

View File

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

View File

@@ -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));
}
}
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) {
if (!isNull(quickAction.approve)) {
let noify = await this.findNotify(request.flag);
if (!isNull(quickAction.approve) && noify) {
this.core.apis.GroupApi.handleGroupRequest(
request.flag,
noify,
quickAction.approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,
quickAction.reason,
).catch(e => this.core.context.logger.logError(e));
@@ -94,8 +103,9 @@ export class OneBotQuickActionApi {
}
async handleFriendRequest(request: OB11FriendRequestEvent, quickAction: QuickActionFriendRequest) {
if (!isNull(quickAction.approve)) {
this.core.apis.FriendApi.handleFriendRequest(request.flag, !!quickAction.approve).then().catch(e => this.core.context.logger.logError(e));
const notify = (await this.core.apis.FriendApi.getBuddyReq()).buddyReqs.find(e => e.reqTime == request.flag.toString());
if (!isNull(quickAction.approve) && notify) {
this.core.apis.FriendApi.handleFriendRequest(notify, !!quickAction.approve).then().catch(e => this.core.context.logger.logError(e));
}
}
}

View File

@@ -157,9 +157,9 @@ export class NapCatOneBot11Adapter {
this.initBuddyListener();
this.initGroupListener();
await WebUiDataRuntime.setQQLoginUin(selfInfo.uin.toString());
await WebUiDataRuntime.setQQLoginStatus(true);
await WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
WebUiDataRuntime.setQQLoginInfo(selfInfo);
WebUiDataRuntime.setQQLoginStatus(true);
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
const prev = this.configLoader.configData;
this.configLoader.save(newConfig);
this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);
@@ -207,7 +207,7 @@ export class NapCatOneBot11Adapter {
}
}
}
// 通知新配置重载 删除关闭的 加入新开的
// 通知新配置重载 删除关闭的 加入新开的
for (const adapterConfig of nowConfig) {
const existingAdapter = this.networkManager.findSomeAdapter(adapterConfig.name);
if (existingAdapter) {

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
import { IOB11NetworkAdapter, OB11EmitEventContent, OB11NetworkReloadType } from './index';
import { NapCatOneBot11Adapter, OB11Message } from '@/onebot';
import { NapCatCore } from '@/core';
import { ActionMap } from '../action';
import { AdapterConfig } from '../config/config';
import { plugin_onmessage } from '@/plugin';
import { ActionMap } from '../action';
export class OB11PluginAdapter implements IOB11NetworkAdapter {
isEnable: boolean = true;
@@ -27,7 +27,7 @@ export class OB11PluginAdapter implements IOB11NetworkAdapter {
onEvent<T extends OB11EmitEventContent>(event: T) {
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 { 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) => {
if (message.raw_message.startsWith('设置头衔') && message.group_id) {
const ret = await new SetSpecialTittle(obCore, core)
.handle({ group_id: message.group_id, user_id: message.user_id, special_title: message.raw_message.replace('设置头衔', '') }, adapter);
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCore: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap) => {
if (message.raw_message === 'ping') {
const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter);
console.log(ret);
}
}
}

View File

@@ -175,7 +175,9 @@ async function handleLogin(
loginService.getLoginList().then((res) => {
// 遍历 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) => {
@@ -285,7 +287,7 @@ export async function NCoreInitShell() {
await initializeEngine(engine, basicInfoWrapper, dataPathGlobal, systemPlatform, systemVersion);
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
program.option('-q, --qq [number]', 'QQ号').parse(process.argv);
const cmdOptions = program.opts();
const quickLoginUin = cmdOptions.qq;
@@ -354,8 +356,6 @@ export class NapCatShell {
};
this.core = new NapCatCore(this.context, selfInfo);
}
async InitNapCat() {
await this.core.initCore();

View File

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

View File

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

View File

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

View File

@@ -7,12 +7,12 @@ import { sendError, sendSuccess } from '@webapi/utils/response';
// 获取QQ登录二维码
export const QQGetQRcodeHandler: RequestHandler = async (req, res) => {
// 判断是否已经登录
if (await WebUiDataRuntime.getQQLoginStatus()) {
if (WebUiDataRuntime.getQQLoginStatus()) {
// 已经登录
return sendError(res, 'QQ Is Logined');
}
// 获取二维码
const qrcodeUrl = await WebUiDataRuntime.getQQLoginQrcodeURL();
const qrcodeUrl = WebUiDataRuntime.getQQLoginQrcodeURL();
// 判断二维码是否为空
if (isEmpty(qrcodeUrl)) {
return sendError(res, 'QRCode Get Error');
@@ -27,8 +27,8 @@ export const QQGetQRcodeHandler: RequestHandler = async (req, res) => {
// 获取QQ登录状态
export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => {
const data = {
isLogin: await WebUiDataRuntime.getQQLoginStatus(),
qrcodeurl: await WebUiDataRuntime.getQQLoginQrcodeURL(),
isLogin: WebUiDataRuntime.getQQLoginStatus(),
qrcodeurl: WebUiDataRuntime.getQQLoginQrcodeURL(),
};
return sendSuccess(res, data);
};
@@ -38,7 +38,7 @@ export const QQSetQuickLoginHandler: RequestHandler = async (req, res) => {
// 获取QQ号
const { uin } = req.body;
// 判断是否已经登录
const isLogin = await WebUiDataRuntime.getQQLoginStatus();
const isLogin = WebUiDataRuntime.getQQLoginStatus();
if (isLogin) {
return sendError(res, 'QQ Is Logined');
}
@@ -53,12 +53,24 @@ export const QQSetQuickLoginHandler: RequestHandler = async (req, res) => {
return sendError(res, message);
}
//本来应该验证 但是http不宜这么搞 建议前端验证
//isLogin = await WebUiDataRuntime.getQQLoginStatus();
//isLogin = WebUiDataRuntime.getQQLoginStatus();
return sendSuccess(res, null);
};
// 获取快速登录列表
export const QQGetQuickLoginListHandler: RequestHandler = async (_, res) => {
const quickLoginList = await WebUiDataRuntime.getQQQuickLoginList();
const quickLoginList = WebUiDataRuntime.getQQQuickLoginList();
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 = {
LoginCurrentTime: Date.now(),
LoginCurrentRate: 0,
QQLoginStatus: false, //已实现 但太傻了 得去那边注册个回调刷新
QQQRCodeURL: '',
QQLoginUin: '',
QQLoginInfo: {
uid: '',
uin: '',
nick: '',
},
NapCatHelper: {
onOB11ConfigChanged: async () => {
return;
@@ -14,11 +19,13 @@ const LoginRuntime: LoginRuntimeType = {
return { result: false, message: '' };
},
QQLoginList: [],
NewQQLoginList: [],
},
packageJson: packageJson,
};
export const WebUiDataRuntime = {
checkLoginRate: async function (RateLimit: number): Promise<boolean> {
checkLoginRate(RateLimit: number): boolean {
LoginRuntime.LoginCurrentRate++;
//console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime);
if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) {
@@ -29,51 +36,68 @@ export const WebUiDataRuntime = {
return LoginRuntime.LoginCurrentRate <= RateLimit;
},
getQQLoginStatus: async function (): Promise<boolean> {
getQQLoginStatus(): LoginRuntimeType['QQLoginStatus'] {
return LoginRuntime.QQLoginStatus;
},
setQQLoginStatus: async function (status: boolean): Promise<void> {
setQQLoginStatus(status: LoginRuntimeType['QQLoginStatus']): void {
LoginRuntime.QQLoginStatus = status;
},
setQQLoginQrcodeURL: async function (url: string): Promise<void> {
setQQLoginQrcodeURL(url: LoginRuntimeType['QQQRCodeURL']): void {
LoginRuntime.QQQRCodeURL = url;
},
getQQLoginQrcodeURL: async function (): Promise<string> {
getQQLoginQrcodeURL(): LoginRuntimeType['QQQRCodeURL'] {
return LoginRuntime.QQQRCodeURL;
},
setQQLoginUin: async function (uin: string): Promise<void> {
LoginRuntime.QQLoginUin = uin;
setQQLoginInfo(info: LoginRuntimeType['QQLoginInfo']): void {
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;
},
getQQQuickLoginList: async function (): Promise<any[]> {
getQQQuickLoginList(): LoginRuntimeType['NapCatHelper']['QQLoginList'] {
return LoginRuntime.NapCatHelper.QQLoginList;
},
setQQQuickLoginList: async function (list: string[]): Promise<void> {
setQQQuickLoginList(list: LoginRuntimeType['NapCatHelper']['QQLoginList']): void {
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;
},
requestQuickLogin: async function (uin: string): Promise<{ result: boolean; message: string }> {
return await LoginRuntime.NapCatHelper.onQuickLoginRequested(uin);
},
requestQuickLogin: function (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;
},
setOB11Config: async function (ob11: OneBotConfig): Promise<void> {
await LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
setOB11Config: function (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,
QQGetQuickLoginListHandler,
QQSetQuickLoginHandler,
QQGetLoginListNewHandler,
getQQLoginInfoHandler,
} from '@webapi/api/QQLogin';
const router = Router();
// router:获取快速登录列表
router.all('/GetQuickLoginList', QQGetQuickLoginListHandler);
// router:获取快速登录列表(新)
router.all('/GetQuickLoginListNew', QQGetLoginListNewHandler);
// router:检查QQ登录状态
router.post('/CheckLoginStatus', QQCheckLoginStatusHandler);
// router:获取QQ登录二维码
router.post('/GetQQLoginQrcode', QQGetQRcodeHandler);
// router:设置QQ快速登录
router.post('/SetQuickLogin', QQSetQuickLoginHandler);
// router:获取QQ登录信息
router.post('/GetQQLoginInfo', getQQLoginInfoHandler);
export { router as QQLoginRouter };

View File

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

View File

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