mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
fix: send multi forward msg
This commit is contained in:
parent
9b8b9a203c
commit
1938eef746
@ -1,3 +1,5 @@
|
|||||||
|
import {Peer} from "../ntqqapi/ntcall";
|
||||||
|
|
||||||
export const CHANNEL_GET_CONFIG = "llonebot_get_config"
|
export const CHANNEL_GET_CONFIG = "llonebot_get_config"
|
||||||
export const CHANNEL_SET_CONFIG = "llonebot_set_config"
|
export const CHANNEL_SET_CONFIG = "llonebot_set_config"
|
||||||
export const CHANNEL_LOG = "llonebot_log"
|
export const CHANNEL_LOG = "llonebot_log"
|
@ -2,8 +2,6 @@ import * as path from "path";
|
|||||||
import {selfInfo} from "./data";
|
import {selfInfo} from "./data";
|
||||||
import {ConfigUtil} from "./config";
|
import {ConfigUtil} from "./config";
|
||||||
import util from "util";
|
import util from "util";
|
||||||
import { sendLog } from '../main/ipcsend';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
export const CONFIG_DIR = global.LiteLoader.plugins["LLOneBot"].path.data;
|
export const CONFIG_DIR = global.LiteLoader.plugins["LLOneBot"].path.data;
|
||||||
@ -94,3 +92,6 @@ export async function file2base64(path: string){
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sleep = (ms: number): Promise<void> =>
|
||||||
|
new Promise((resolve) => setTimeout(resolve, ms))
|
9
src/global.d.ts
vendored
9
src/global.d.ts
vendored
@ -1,15 +1,10 @@
|
|||||||
import { Config } from "./common/types";
|
import {LLOneBot} from "./preload";
|
||||||
|
|
||||||
|
|
||||||
declare var llonebot: {
|
|
||||||
log(data: any): void,
|
|
||||||
setConfig(config: Config):void;
|
|
||||||
getConfig():Promise<Config>;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
llonebot: typeof llonebot;
|
llonebot: LLOneBot;
|
||||||
LiteLoader: any;
|
LiteLoader: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,12 @@
|
|||||||
import {webContents} from 'electron';
|
import {webContents} from 'electron';
|
||||||
import { CHANNEL_LOG } from '../common/channels';
|
|
||||||
|
|
||||||
|
function sendIPCMsg(channel: string, data: any) {
|
||||||
function sendIPCMsg(channel: string, ...data: any) {
|
|
||||||
let contents = webContents.getAllWebContents();
|
let contents = webContents.getAllWebContents();
|
||||||
for (const content of contents) {
|
for (const content of contents) {
|
||||||
try {
|
try {
|
||||||
content.send(channel, ...data)
|
content.send(channel, data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("llonebot send ipc msg to render error:", e)
|
console.log("llonebot send ipc msg to render error:", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendLog(...args){
|
|
||||||
sendIPCMsg(CHANNEL_LOG, ...args)
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@ import { CHANNEL_GET_CONFIG, CHANNEL_LOG, CHANNEL_SET_CONFIG, } from "../common/
|
|||||||
import { postMsg, setToken, startHTTPServer, startWSServer } from "../onebot11/server";
|
import { postMsg, setToken, startHTTPServer, startWSServer } from "../onebot11/server";
|
||||||
import { CONFIG_DIR, getConfigUtil, log } from "../common/utils";
|
import { CONFIG_DIR, getConfigUtil, log } from "../common/utils";
|
||||||
import { addHistoryMsg, getGroupMember, msgHistory, selfInfo, uidMaps } from "../common/data";
|
import { addHistoryMsg, getGroupMember, msgHistory, selfInfo, uidMaps } from "../common/data";
|
||||||
import { hookNTQQApiReceive, ReceiveCmd, registerReceiveHook } from "../ntqqapi/hook";
|
import { hookNTQQApiCall, hookNTQQApiReceive, ReceiveCmd, registerReceiveHook } from "../ntqqapi/hook";
|
||||||
import { OB11Constructor } from "../onebot11/constructor";
|
import { OB11Constructor } from "../onebot11/constructor";
|
||||||
import { NTQQApi } from "../ntqqapi/ntcall";
|
import { NTQQApi } from "../ntqqapi/ntcall";
|
||||||
import { ChatType, RawMessage } from "../ntqqapi/types";
|
import { ChatType, RawMessage } from "../ntqqapi/types";
|
||||||
@ -20,10 +20,6 @@ let running = false;
|
|||||||
// 加载插件时触发
|
// 加载插件时触发
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
log("llonebot main onLoad");
|
log("llonebot main onLoad");
|
||||||
|
|
||||||
// const config_dir = browserWindow.LiteLoader.plugins["LLOneBot"].path.data;
|
|
||||||
|
|
||||||
|
|
||||||
if (!fs.existsSync(CONFIG_DIR)) {
|
if (!fs.existsSync(CONFIG_DIR)) {
|
||||||
fs.mkdirSync(CONFIG_DIR, {recursive: true});
|
fs.mkdirSync(CONFIG_DIR, {recursive: true});
|
||||||
}
|
}
|
||||||
@ -52,7 +48,7 @@ function onLoad() {
|
|||||||
function postRawMsg(msgList: RawMessage[]) {
|
function postRawMsg(msgList: RawMessage[]) {
|
||||||
const {debug, reportSelfMessage} = getConfigUtil().getConfig();
|
const {debug, reportSelfMessage} = getConfigUtil().getConfig();
|
||||||
for (let message of msgList) {
|
for (let message of msgList) {
|
||||||
log("收到新消息", message)
|
// log("收到新消息", message)
|
||||||
message.msgShortId = msgHistory[message.msgId]?.msgShortId
|
message.msgShortId = msgHistory[message.msgId]?.msgShortId
|
||||||
if (!message.msgShortId) {
|
if (!message.msgShortId) {
|
||||||
addHistoryMsg(message)
|
addHistoryMsg(message)
|
||||||
@ -82,8 +78,8 @@ function onLoad() {
|
|||||||
})
|
})
|
||||||
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, async (payload) => {
|
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, async (payload) => {
|
||||||
for (const message of payload.msgList) {
|
for (const message of payload.msgList) {
|
||||||
// log("message update", message, message.sendStatus)
|
// log("message update", message.sendStatus, message)
|
||||||
if (message.sendStatus === 2) {
|
if (message.recallTime != "0") {
|
||||||
// 撤回消息上报
|
// 撤回消息上报
|
||||||
const oriMessage = msgHistory[message.msgId]
|
const oriMessage = msgHistory[message.msgId]
|
||||||
if (!oriMessage) {
|
if (!oriMessage) {
|
||||||
@ -166,6 +162,7 @@ function onLoad() {
|
|||||||
// 创建窗口时触发
|
// 创建窗口时触发
|
||||||
function onBrowserWindowCreated(window: BrowserWindow) {
|
function onBrowserWindowCreated(window: BrowserWindow) {
|
||||||
try {
|
try {
|
||||||
|
hookNTQQApiCall(window);
|
||||||
hookNTQQApiReceive(window);
|
hookNTQQApiReceive(window);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log("LLOneBot hook error: ", e.toString())
|
log("LLOneBot hook error: ", e.toString())
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { BrowserWindow } from 'electron';
|
import { BrowserWindow } from 'electron';
|
||||||
import { getConfigUtil, log } from "../common/utils";
|
import { log } from "../common/utils";
|
||||||
import { NTQQApi, NTQQApiClass, sendMessagePool } from "./ntcall";
|
import { NTQQApi, NTQQApiClass, sendMessagePool } from "./ntcall";
|
||||||
import { Group, User } from "./types";
|
import { Group, RawMessage, User } from "./types";
|
||||||
import { RawMessage } from "./types";
|
|
||||||
import { addHistoryMsg, friends, groups, msgHistory } from "../common/data";
|
import { addHistoryMsg, friends, groups, msgHistory } from "../common/data";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
|||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
let _ = hook.hookFunc(receiveData.payload)
|
let _ = hook.hookFunc(receiveData.payload)
|
||||||
if (hook.hookFunc.constructor.name === "AsyncFunction"){
|
if (hook.hookFunc.constructor.name === "AsyncFunction") {
|
||||||
(_ as Promise<void>).then()
|
(_ as Promise<void>).then()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -78,6 +77,24 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
|||||||
window.webContents.send = patchSend;
|
window.webContents.send = patchSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hookNTQQApiCall(window: BrowserWindow) {
|
||||||
|
// 监听调用NTQQApi
|
||||||
|
let webContents = window.webContents as any;
|
||||||
|
const ipc_message_proxy = webContents._events["-ipc-message"]?.[0] || webContents._events["-ipc-message"];
|
||||||
|
|
||||||
|
const proxyIpcMsg = new Proxy(ipc_message_proxy, {
|
||||||
|
apply(target, thisArg, args) {
|
||||||
|
log("call NTQQ api", thisArg, args);
|
||||||
|
return target.apply(thisArg, args);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// if (webContents._events["-ipc-message"]?.[0]) {
|
||||||
|
// webContents._events["-ipc-message"][0] = proxyIpcMsg;
|
||||||
|
// } else {
|
||||||
|
// webContents._events["-ipc-message"] = proxyIpcMsg;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (payload: PayloadType) => void): string {
|
export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (payload: PayloadType) => void): string {
|
||||||
const id = uuidv4()
|
const id = uuidv4()
|
||||||
receiveHooks.push({
|
receiveHooks.push({
|
||||||
@ -133,7 +150,6 @@ registerReceiveHook<{
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload) => {
|
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload) => {
|
||||||
for (const message of payload.msgList) {
|
for (const message of payload.msgList) {
|
||||||
// log("收到新消息,push到历史记录", message)
|
// log("收到新消息,push到历史记录", message)
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import { ipcMain } from "electron";
|
import {ipcMain} from "electron";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import { ReceiveCmd, hookApiCallbacks, registerReceiveHook, removeReceiveHook } from "./hook";
|
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
|
||||||
import { log } from "../common/utils";
|
import {log} from "../common/utils";
|
||||||
import { ChatType, Friend, PicElement, SelfInfo, User } from "./types";
|
import {ChatType, Friend, Group, GroupMember, RawMessage, SelfInfo, SendMessageElement, User} from "./types";
|
||||||
import { Group } from "./types";
|
|
||||||
import { GroupMember } from "./types";
|
|
||||||
import { RawMessage } from "./types";
|
|
||||||
import { SendMessageElement } from "./types";
|
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import {addHistoryMsg, msgHistory, selfInfo} from "../common/data";
|
||||||
|
|
||||||
interface IPCReceiveEvent {
|
interface IPCReceiveEvent {
|
||||||
eventName: string
|
eventName: string
|
||||||
@ -29,7 +26,6 @@ export enum NTQQApiClass {
|
|||||||
|
|
||||||
export enum NTQQApiMethod {
|
export enum NTQQApiMethod {
|
||||||
LIKE_FRIEND = "nodeIKernelProfileLikeService/setBuddyProfileLike",
|
LIKE_FRIEND = "nodeIKernelProfileLikeService/setBuddyProfileLike",
|
||||||
UPDATE_MSG = "nodeIKernelMsgListener/onMsgInfoListUpdate",
|
|
||||||
SELF_INFO = "fetchAuthData",
|
SELF_INFO = "fetchAuthData",
|
||||||
FRIENDS = "nodeIKernelBuddyService/getBuddyList",
|
FRIENDS = "nodeIKernelBuddyService/getBuddyList",
|
||||||
GROUPS = "nodeIKernelGroupService/getGroupList",
|
GROUPS = "nodeIKernelGroupService/getGroupList",
|
||||||
@ -44,7 +40,8 @@ export enum NTQQApiMethod {
|
|||||||
MEDIA_FILE_PATH = "nodeIKernelMsgService/getRichMediaFilePathForGuild",
|
MEDIA_FILE_PATH = "nodeIKernelMsgService/getRichMediaFilePathForGuild",
|
||||||
RECALL_MSG = "nodeIKernelMsgService/recallMsg",
|
RECALL_MSG = "nodeIKernelMsgService/recallMsg",
|
||||||
SEND_MSG = "nodeIKernelMsgService/sendMsg",
|
SEND_MSG = "nodeIKernelMsgService/sendMsg",
|
||||||
DOWNLOAD_MEDIA = "nodeIKernelMsgService/downloadRichMedia"
|
DOWNLOAD_MEDIA = "nodeIKernelMsgService/downloadRichMedia",
|
||||||
|
MULTI_FORWARD_MSG = "nodeIKernelMsgService/multiForwardMsgWithComment" // 合并转发
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NTQQApiChannel {
|
enum NTQQApiChannel {
|
||||||
@ -64,8 +61,24 @@ enum CallBackType {
|
|||||||
METHOD
|
METHOD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NTQQApiParams {
|
||||||
|
methodName: NTQQApiMethod,
|
||||||
|
className?: NTQQApiClass,
|
||||||
|
channel?: NTQQApiChannel,
|
||||||
|
args?: unknown[],
|
||||||
|
cbCmd?: ReceiveCmd | null
|
||||||
|
timeoutSecond?: number,
|
||||||
|
}
|
||||||
|
|
||||||
function callNTQQApi<ReturnType>(channel: NTQQApiChannel, className: NTQQApiClass, methodName: NTQQApiMethod, args: unknown[] = [], cbCmd: ReceiveCmd | null = null, timeout = 5) {
|
function callNTQQApi<ReturnType>(params: NTQQApiParams) {
|
||||||
|
let {
|
||||||
|
className, methodName, channel, args,
|
||||||
|
cbCmd, timeoutSecond: timeout
|
||||||
|
} = params;
|
||||||
|
className = className ?? NTQQApiClass.NT_API;
|
||||||
|
channel = channel ?? NTQQApiChannel.IPC_UP_2;
|
||||||
|
args = args ?? [];
|
||||||
|
timeout = timeout ?? 5;
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
// log("callNTQQApi", channel, className, methodName, args, uuid)
|
// log("callNTQQApi", channel, className, methodName, args, uuid)
|
||||||
return new Promise((resolve: (data: ReturnType) => void, reject) => {
|
return new Promise((resolve: (data: ReturnType) => void, reject) => {
|
||||||
@ -102,16 +115,18 @@ function callNTQQApi<ReturnType>(channel: NTQQApiChannel, className: NTQQApiClas
|
|||||||
reject(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
|
reject(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
|
||||||
}
|
}
|
||||||
}, _timeout)
|
}, _timeout)
|
||||||
|
const eventName = className + "-" + channel[channel.length - 1];
|
||||||
|
const apiArgs = [methodName, ...args]
|
||||||
ipcMain.emit(
|
ipcMain.emit(
|
||||||
channel,
|
channel,
|
||||||
{},
|
{},
|
||||||
{type: 'request', callbackId: uuid, eventName: className + "-" + channel[channel.length - 1]},
|
{type: 'request', callbackId: uuid, eventName},
|
||||||
[methodName, ...args],
|
apiArgs
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
|
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
|
||||||
|
|
||||||
interface GeneralCallResult {
|
interface GeneralCallResult {
|
||||||
@ -123,34 +138,49 @@ interface GeneralCallResult {
|
|||||||
export class NTQQApi {
|
export class NTQQApi {
|
||||||
// static likeFriend = defineNTQQApi<void>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.LIKE_FRIEND)
|
// static likeFriend = defineNTQQApi<void>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.LIKE_FRIEND)
|
||||||
static likeFriend(uid: string, count = 1) {
|
static likeFriend(uid: string, count = 1) {
|
||||||
return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.LIKE_FRIEND, [{
|
return callNTQQApi({
|
||||||
doLikeUserInfo: {
|
methodName: NTQQApiMethod.LIKE_FRIEND,
|
||||||
friendUid: uid,
|
args: [{
|
||||||
sourceId: 71,
|
doLikeUserInfo: {
|
||||||
doLikeCount: count,
|
friendUid: uid,
|
||||||
doLikeTollCount: 0
|
sourceId: 71,
|
||||||
}
|
doLikeCount: count,
|
||||||
},
|
doLikeTollCount: 0
|
||||||
null])
|
}
|
||||||
|
}, null]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static getSelfInfo() {
|
static getSelfInfo() {
|
||||||
return callNTQQApi<SelfInfo>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.GLOBAL_DATA, NTQQApiMethod.SELF_INFO, [], null, 2)
|
return callNTQQApi<SelfInfo>({
|
||||||
|
className: NTQQApiClass.GLOBAL_DATA,
|
||||||
|
methodName: NTQQApiMethod.SELF_INFO, timeoutSecond: 2
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getUserInfo(uid: string) {
|
static async getUserInfo(uid: string) {
|
||||||
const result = await callNTQQApi<{
|
const result = await callNTQQApi<{ profiles: Map<string, User> }>({
|
||||||
profiles: Map<string, User>
|
methodName: NTQQApiMethod.USER_INFO,
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.USER_INFO,
|
args: [{force: true, uids: [uid]}, undefined],
|
||||||
[{force: true, uids: [uid]}, undefined], ReceiveCmd.USER_INFO)
|
cbCmd: ReceiveCmd.USER_INFO
|
||||||
|
})
|
||||||
return result.profiles.get(uid)
|
return result.profiles.get(uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getFriends(forced = false) {
|
static async getFriends(forced = false) {
|
||||||
const data = await callNTQQApi<{
|
const data = await callNTQQApi<{
|
||||||
data: { categoryId: number, categroyName: string, categroyMbCount: number, buddyList: Friend[] }[]
|
data: {
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.FRIENDS, [{force_update: forced}, undefined], ReceiveCmd.FRIENDS)
|
categoryId: number,
|
||||||
|
categroyName: string,
|
||||||
|
categroyMbCount: number,
|
||||||
|
buddyList: Friend[]
|
||||||
|
}[]
|
||||||
|
}>(
|
||||||
|
{
|
||||||
|
methodName: NTQQApiMethod.FRIENDS,
|
||||||
|
args: [{force_update: forced}, undefined],
|
||||||
|
cbCmd: ReceiveCmd.FRIENDS
|
||||||
|
})
|
||||||
let _friends: Friend[] = [];
|
let _friends: Friend[] = [];
|
||||||
for (const fData of data.data) {
|
for (const fData of data.data) {
|
||||||
_friends.push(...fData.buddyList)
|
_friends.push(...fData.buddyList)
|
||||||
@ -166,26 +196,31 @@ export class NTQQApi {
|
|||||||
const result = await callNTQQApi<{
|
const result = await callNTQQApi<{
|
||||||
updateType: number,
|
updateType: number,
|
||||||
groupList: Group[]
|
groupList: Group[]
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUPS, [{force_update: forced}, undefined], cbCmd)
|
}>({methodName: NTQQApiMethod.GROUPS, args: [{force_update: forced}, undefined], cbCmd})
|
||||||
return result.groupList
|
return result.groupList
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupMembers(groupQQ: string, num = 3000) {
|
static async getGroupMembers(groupQQ: string, num = 3000) {
|
||||||
const sceneId = await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBER_SCENE, [{
|
const sceneId = await callNTQQApi({
|
||||||
groupCode: groupQQ,
|
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
||||||
scene: "groupMemberList_MainWindow"
|
args: [{
|
||||||
}])
|
groupCode: groupQQ,
|
||||||
|
scene: "groupMemberList_MainWindow"
|
||||||
|
}]
|
||||||
|
})
|
||||||
// log("get group member sceneId", sceneId);
|
// log("get group member sceneId", sceneId);
|
||||||
try {
|
try {
|
||||||
const result = await callNTQQApi<{
|
const result = await callNTQQApi<{
|
||||||
result: { infos: any }
|
result: { infos: any }
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBERS,
|
}>({
|
||||||
[{
|
methodName: NTQQApiMethod.GROUP_MEMBERS,
|
||||||
|
args: [{
|
||||||
sceneId: sceneId,
|
sceneId: sceneId,
|
||||||
num: num
|
num: num
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
])
|
]
|
||||||
|
})
|
||||||
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
||||||
let values = result.result.infos.values()
|
let values = result.result.infos.values()
|
||||||
|
|
||||||
@ -200,31 +235,38 @@ export class NTQQApi {
|
|||||||
|
|
||||||
|
|
||||||
static getFileType(filePath: string) {
|
static getFileType(filePath: string) {
|
||||||
return callNTQQApi<{
|
return callNTQQApi<{ ext: string }>({
|
||||||
ext: string
|
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_TYPE, args: [filePath]
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_TYPE, [filePath])
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static getFileMd5(filePath: string) {
|
static getFileMd5(filePath: string) {
|
||||||
return callNTQQApi<string>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_MD5, [filePath])
|
return callNTQQApi<string>({
|
||||||
|
className: NTQQApiClass.FS_API,
|
||||||
|
methodName: NTQQApiMethod.FILE_MD5,
|
||||||
|
args: [filePath]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static copyFile(filePath: string, destPath: string) {
|
static copyFile(filePath: string, destPath: string) {
|
||||||
return callNTQQApi<string>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_COPY, [{
|
return callNTQQApi<string>({
|
||||||
fromPath: filePath,
|
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_COPY, args: [{
|
||||||
toPath: destPath
|
fromPath: filePath,
|
||||||
}])
|
toPath: destPath
|
||||||
|
}]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static getImageSize(filePath: string) {
|
static getImageSize(filePath: string) {
|
||||||
return callNTQQApi<{
|
return callNTQQApi<{ width: number, height: number }>({
|
||||||
width: number,
|
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.IMAGE_SIZE, args: [filePath]
|
||||||
height: number
|
})
|
||||||
}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.IMAGE_SIZE, [filePath])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getFileSize(filePath: string) {
|
static getFileSize(filePath: string) {
|
||||||
return callNTQQApi<number>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_SIZE, [filePath])
|
return callNTQQApi<number>({
|
||||||
|
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_SIZE, args: [filePath]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传文件到QQ的文件夹
|
// 上传文件到QQ的文件夹
|
||||||
@ -233,23 +275,25 @@ export class NTQQApi {
|
|||||||
let ext = (await NTQQApi.getFileType(filePath))?.ext
|
let ext = (await NTQQApi.getFileType(filePath))?.ext
|
||||||
if (ext) {
|
if (ext) {
|
||||||
ext = "." + ext
|
ext = "." + ext
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
ext = ""
|
ext = ""
|
||||||
}
|
}
|
||||||
const fileName = `${md5}${ext}`;
|
const fileName = `${md5}${ext}`;
|
||||||
const mediaPath = await callNTQQApi<string>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.MEDIA_FILE_PATH, [{
|
const mediaPath = await callNTQQApi<string>({
|
||||||
path_info: {
|
methodName: NTQQApiMethod.MEDIA_FILE_PATH,
|
||||||
md5HexStr: md5,
|
args: [{
|
||||||
fileName: fileName,
|
path_info: {
|
||||||
elementType: 2,
|
md5HexStr: md5,
|
||||||
elementSubType: 0,
|
fileName: fileName,
|
||||||
thumbSize: 0,
|
elementType: 2,
|
||||||
needCreate: true,
|
elementSubType: 0,
|
||||||
downloadType: 1,
|
thumbSize: 0,
|
||||||
file_uuid: ""
|
needCreate: true,
|
||||||
}
|
downloadType: 1,
|
||||||
}])
|
file_uuid: ""
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
log("media path", mediaPath)
|
log("media path", mediaPath)
|
||||||
await NTQQApi.copyFile(filePath, mediaPath);
|
await NTQQApi.copyFile(filePath, mediaPath);
|
||||||
const fileSize = await NTQQApi.getFileSize(filePath);
|
const fileSize = await NTQQApi.getFileSize(filePath);
|
||||||
@ -280,28 +324,32 @@ export class NTQQApi {
|
|||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
]
|
]
|
||||||
await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.DOWNLOAD_MEDIA, apiParams)
|
await callNTQQApi({methodName: NTQQApiMethod.DOWNLOAD_MEDIA, args: apiParams})
|
||||||
return sourcePath
|
return sourcePath
|
||||||
}
|
}
|
||||||
|
|
||||||
static recallMsg(peer: Peer, msgIds: string[]) {
|
static recallMsg(peer: Peer, msgIds: string[]) {
|
||||||
return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.RECALL_MSG, [{
|
return callNTQQApi({
|
||||||
peer,
|
methodName: NTQQApiMethod.RECALL_MSG, args: [{
|
||||||
msgIds
|
peer,
|
||||||
}, null])
|
msgIds
|
||||||
|
}, null]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static sendMsg(peer: Peer, msgElements: SendMessageElement[]) {
|
static sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = false) {
|
||||||
const sendTimeout = 10 * 1000
|
const sendTimeout = 10 * 1000
|
||||||
|
|
||||||
return new Promise<RawMessage>((resolve, reject) => {
|
return new Promise<RawMessage>((resolve, reject) => {
|
||||||
const peerUid = peer.peerUid;
|
const peerUid = peer.peerUid;
|
||||||
let usingTime = 0;
|
let usingTime = 0;
|
||||||
let success = false;
|
let success = false;
|
||||||
|
let isTimeout = false;
|
||||||
|
|
||||||
const checkSuccess = () => {
|
const checkSuccess = () => {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
sendMessagePool[peerUid] = null;
|
sendMessagePool[peerUid] = null;
|
||||||
|
isTimeout = true;
|
||||||
reject("发送超时")
|
reject("发送超时")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,29 +359,99 @@ export class NTQQApi {
|
|||||||
let lastSending = sendMessagePool[peerUid]
|
let lastSending = sendMessagePool[peerUid]
|
||||||
if (sendTimeout < usingTime) {
|
if (sendTimeout < usingTime) {
|
||||||
sendMessagePool[peerUid] = null;
|
sendMessagePool[peerUid] = null;
|
||||||
|
isTimeout = true;
|
||||||
reject("发送超时")
|
reject("发送超时")
|
||||||
}
|
}
|
||||||
if (!!lastSending) {
|
if (!!lastSending) {
|
||||||
// log("有正在发送的消息,等待中...")
|
// log("有正在发送的消息,等待中...")
|
||||||
usingTime += 100;
|
usingTime += 500;
|
||||||
setTimeout(checkLastSend, 100);
|
setTimeout(checkLastSend, 500);
|
||||||
} else {
|
} else {
|
||||||
log("可以进行发送消息,设置发送成功回调", sendMessagePool)
|
log("可以进行发送消息,设置发送成功回调", sendMessagePool)
|
||||||
sendMessagePool[peerUid] = (rawMessage: RawMessage) => {
|
sendMessagePool[peerUid] = (rawMessage: RawMessage) => {
|
||||||
success = true;
|
|
||||||
sendMessagePool[peerUid] = null;
|
sendMessagePool[peerUid] = null;
|
||||||
resolve(rawMessage);
|
const checkSendComplete = () => {
|
||||||
|
if (isTimeout) {
|
||||||
|
return reject("发送超时")
|
||||||
|
}
|
||||||
|
if (msgHistory[rawMessage.msgId]?.sendStatus == 2) {
|
||||||
|
success = true;
|
||||||
|
resolve(rawMessage);
|
||||||
|
} else {
|
||||||
|
setTimeout(checkSendComplete, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (waitComplete) {
|
||||||
|
checkSendComplete();
|
||||||
|
} else {
|
||||||
|
success = true;
|
||||||
|
resolve(rawMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkLastSend()
|
checkLastSend()
|
||||||
callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.SEND_MSG, [{
|
callNTQQApi({
|
||||||
msgId: "0",
|
methodName: NTQQApiMethod.SEND_MSG,
|
||||||
peer, msgElements,
|
args: [{
|
||||||
msgAttributeInfos: new Map(),
|
msgId: "0",
|
||||||
}, null]).then()
|
peer, msgElements,
|
||||||
|
msgAttributeInfos: new Map(),
|
||||||
|
}, null]
|
||||||
|
}).then()
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||||
|
let msgInfos = msgIds.map(id => {
|
||||||
|
return {msgId: id, senderShowName: "LLOneBot"}
|
||||||
|
})
|
||||||
|
const apiArgs = [
|
||||||
|
{
|
||||||
|
msgInfos,
|
||||||
|
srcContact: srcPeer,
|
||||||
|
dstContact: destPeer,
|
||||||
|
commentElements: [],
|
||||||
|
msgAttributeInfos: new Map()
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
]
|
||||||
|
return new Promise<RawMessage>((resolve, reject) => {
|
||||||
|
let complete = false
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!complete) {
|
||||||
|
reject("转发消息超时");
|
||||||
|
}
|
||||||
|
}, 5000)
|
||||||
|
registerReceiveHook(ReceiveCmd.SELF_SEND_MSG, (payload: { msgRecord: RawMessage }) => {
|
||||||
|
const msg = payload.msgRecord;
|
||||||
|
// 需要判断它是转发的消息,并且识别到是当前转发的这一条
|
||||||
|
const arkElement = msg.elements.find(ele => ele.arkElement)
|
||||||
|
if (!arkElement) {
|
||||||
|
log("收到的不是转发消息")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const forwardData: any = JSON.parse(arkElement.arkElement.bytesData);
|
||||||
|
if (forwardData.app != "com.tencent.multimsg") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (msg.peerUid == destPeer.peerUid && msg.senderUid == selfInfo.uid) {
|
||||||
|
complete = true;
|
||||||
|
addHistoryMsg(msg)
|
||||||
|
resolve(msg);
|
||||||
|
log("收到转发消息:", payload)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
callNTQQApi<GeneralCallResult>({
|
||||||
|
methodName: NTQQApiMethod.MULTI_FORWARD_MSG,
|
||||||
|
args: apiArgs
|
||||||
|
}).then(result => {
|
||||||
|
log("转发消息结果:", result, apiArgs)
|
||||||
|
if (result.result !== 0) {
|
||||||
|
complete = true;
|
||||||
|
reject("转发消息失败," + JSON.stringify(result));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
@ -211,13 +211,15 @@ export interface RawMessage {
|
|||||||
msgShortId?: number; // 自己维护的消息id
|
msgShortId?: number; // 自己维护的消息id
|
||||||
msgTime: string;
|
msgTime: string;
|
||||||
msgSeq: string;
|
msgSeq: string;
|
||||||
senderUin: string; // 发送者QQ号
|
senderUid: string;
|
||||||
|
senderUin?: string; // 发送者QQ号
|
||||||
peerUid: string; // 群号 或者 QQ uid
|
peerUid: string; // 群号 或者 QQ uid
|
||||||
peerUin: string; // 群号 或者 发送者QQ号
|
peerUin: string; // 群号 或者 发送者QQ号
|
||||||
sendNickName: string;
|
sendNickName: string;
|
||||||
sendMemberName?: string; // 发送者群名片
|
sendMemberName?: string; // 发送者群名片
|
||||||
chatType: ChatType;
|
chatType: ChatType;
|
||||||
sendStatus?: number; // 消息状态,2是已撤回
|
sendStatus?: number; // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
||||||
|
recallTime: string; // 撤回时间, "0"是没有撤回
|
||||||
elements: {
|
elements: {
|
||||||
elementId: string,
|
elementId: string,
|
||||||
replyElement: {
|
replyElement: {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { AtType, ChatType, Group, SendMessageElement } from "../../ntqqapi/types";
|
import {AtType, ChatType, Group, SendMessageElement} from "../../ntqqapi/types";
|
||||||
import { addHistoryMsg, friends, getGroup, getHistoryMsgByShortId, getStrangerByUin, } from "../../common/data";
|
import {addHistoryMsg, friends, getGroup, getHistoryMsgByShortId, getStrangerByUin, selfInfo,} from "../../common/data";
|
||||||
import { OB11MessageData, OB11MessageDataType, OB11PostSendMsg } from '../types';
|
import {OB11MessageData, OB11MessageDataType, OB11MessageNode, OB11PostSendMsg} from '../types';
|
||||||
import { NTQQApi, Peer } from "../../ntqqapi/ntcall";
|
import {NTQQApi, Peer} from "../../ntqqapi/ntcall";
|
||||||
import { SendMsgElementConstructor } from "../../ntqqapi/constructor";
|
import {SendMsgElementConstructor} from "../../ntqqapi/constructor";
|
||||||
import { uri2local } from "../utils";
|
import {uri2local} from "../utils";
|
||||||
import { v4 as uuid4 } from 'uuid';
|
import {v4 as uuid4} from 'uuid';
|
||||||
import BaseAction from "./BaseAction";
|
import BaseAction from "./BaseAction";
|
||||||
import { ActionName } from "./types";
|
import {ActionName, BaseCheckResult} from "./types";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import {log, sleep} from "../../common/utils";
|
||||||
|
|
||||||
export interface ReturnDataType {
|
export interface ReturnDataType {
|
||||||
message_id: number
|
message_id: number
|
||||||
@ -16,12 +17,26 @@ export interface ReturnDataType {
|
|||||||
class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||||
actionName = ActionName.SendMsg
|
actionName = ActionName.SendMsg
|
||||||
|
|
||||||
|
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
|
||||||
|
const messages = this.convertMessage2List(payload);
|
||||||
|
const fmNum = this.forwardMsgNum(payload)
|
||||||
|
if ( fmNum && fmNum != messages.length) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: "转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected async _handle(payload: OB11PostSendMsg) {
|
protected async _handle(payload: OB11PostSendMsg) {
|
||||||
const peer: Peer = {
|
const peer: Peer = {
|
||||||
chatType: ChatType.friend,
|
chatType: ChatType.friend,
|
||||||
peerUid: ""
|
peerUid: ""
|
||||||
}
|
}
|
||||||
let deleteAfterSentFiles: string[] = []
|
|
||||||
let group: Group | undefined = undefined;
|
let group: Group | undefined = undefined;
|
||||||
if (payload?.group_id) {
|
if (payload?.group_id) {
|
||||||
group = await getGroup(payload.group_id.toString())
|
group = await getGroup(payload.group_id.toString())
|
||||||
@ -46,6 +61,26 @@ class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
peer.peerUid = tempUser.uid
|
peer.peerUid = tempUser.uid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const messages = this.convertMessage2List(payload);
|
||||||
|
if (this.forwardMsgNum(payload)) {
|
||||||
|
try {
|
||||||
|
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group)
|
||||||
|
return {message_id: returnMsg.msgShortId}
|
||||||
|
} catch (e) {
|
||||||
|
throw ("发送转发消息失败 " + e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log("send msg:", peer, sendElements)
|
||||||
|
const {sendElements, deleteAfterSentFiles} = await this.createSendElements(messages, group)
|
||||||
|
try {
|
||||||
|
const returnMsg = await this.send(peer, sendElements, deleteAfterSentFiles)
|
||||||
|
return {message_id: returnMsg.msgShortId}
|
||||||
|
} catch (e) {
|
||||||
|
throw (e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertMessage2List(payload: OB11PostSendMsg) {
|
||||||
if (typeof payload.message === "string") {
|
if (typeof payload.message === "string") {
|
||||||
payload.message = [{
|
payload.message = [{
|
||||||
type: OB11MessageDataType.text,
|
type: OB11MessageDataType.text,
|
||||||
@ -56,8 +91,62 @@ class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
} else if (!Array.isArray(payload.message)) {
|
} else if (!Array.isArray(payload.message)) {
|
||||||
payload.message = [payload.message]
|
payload.message = [payload.message]
|
||||||
}
|
}
|
||||||
const sendElements: SendMessageElement[] = []
|
return payload.message;
|
||||||
for (let sendMsg of payload.message) {
|
}
|
||||||
|
|
||||||
|
private forwardMsgNum(payload: OB11PostSendMsg): number {
|
||||||
|
if (Array.isArray(payload.message)) {
|
||||||
|
return payload.message.filter(msg => msg.type == OB11MessageDataType.node).length
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回一个合并转发的消息id
|
||||||
|
private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[], group: Group | undefined) {
|
||||||
|
const selfPeer: Peer = {
|
||||||
|
chatType: ChatType.friend,
|
||||||
|
peerUid: selfInfo.uid
|
||||||
|
}
|
||||||
|
let nodeIds: string[] = []
|
||||||
|
for (const messageNode of messageNodes) {
|
||||||
|
// 一个node表示一个人的消息
|
||||||
|
|
||||||
|
let nodeId = messageNode.data.id;
|
||||||
|
// 有nodeId表示一个子转发消息卡片
|
||||||
|
if (nodeId) {
|
||||||
|
nodeIds.push(nodeId)
|
||||||
|
} else {
|
||||||
|
// 自定义的消息
|
||||||
|
// 提取消息段,发给自己生成消息id
|
||||||
|
const {
|
||||||
|
sendElements,
|
||||||
|
deleteAfterSentFiles
|
||||||
|
} = await this.createSendElements(messageNode.data.content, group)
|
||||||
|
try {
|
||||||
|
const nodeMsg = await this.send(selfPeer, sendElements, deleteAfterSentFiles, true);
|
||||||
|
nodeIds.push(nodeMsg.msgId)
|
||||||
|
} catch (e) {
|
||||||
|
log("生效转发消息节点失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开发转发
|
||||||
|
try {
|
||||||
|
return await NTQQApi.multiForwardMsg(selfPeer, destPeer, nodeIds)
|
||||||
|
} catch (e) {
|
||||||
|
log("forward failed", e)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createSendElements(messageData: OB11MessageData[], group: Group | undefined, ignoreTypes: OB11MessageDataType[] = []) {
|
||||||
|
let sendElements: SendMessageElement[] = []
|
||||||
|
let deleteAfterSentFiles: string[] = []
|
||||||
|
for (let sendMsg of messageData) {
|
||||||
|
if (ignoreTypes.includes(sendMsg.type)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
switch (sendMsg.type) {
|
switch (sendMsg.type) {
|
||||||
case OB11MessageDataType.text: {
|
case OB11MessageDataType.text: {
|
||||||
const text = sendMsg.data?.text;
|
const text = sendMsg.data?.text;
|
||||||
@ -116,19 +205,36 @@ class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
// case OB11MessageDataType.node: {
|
||||||
|
// try {
|
||||||
|
// await this.handleForwardNode(peer, sendMsg, group);
|
||||||
|
// } catch (e) {
|
||||||
|
// log("forward msg crash", e.stack)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// log("send msg:", peer, sendElements)
|
|
||||||
try {
|
return {
|
||||||
const returnMsg = await NTQQApi.sendMsg(peer, sendElements)
|
sendElements,
|
||||||
addHistoryMsg(returnMsg)
|
deleteAfterSentFiles
|
||||||
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
|
||||||
}))
|
|
||||||
return {message_id: returnMsg.msgShortId}
|
|
||||||
} catch (e) {
|
|
||||||
throw (e.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async send(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete=false) {
|
||||||
|
if (!sendElements.length) {
|
||||||
|
throw ("消息体无法解析")
|
||||||
|
}
|
||||||
|
const returnMsg = await NTQQApi.sendMsg(peer, sendElements, waitComplete)
|
||||||
|
addHistoryMsg(returnMsg)
|
||||||
|
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
||||||
|
}))
|
||||||
|
return returnMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SendMsg
|
export default SendMsg
|
34
src/onebot11/actions/TestForwdMsg.ts
Normal file
34
src/onebot11/actions/TestForwdMsg.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { OB11Message } from '../types';
|
||||||
|
import BaseAction from "./BaseAction";
|
||||||
|
import { ActionName } from "./types";
|
||||||
|
import { NTQQApi, Peer } from "../../ntqqapi/ntcall";
|
||||||
|
import { ChatType } from "../../ntqqapi/types";
|
||||||
|
import { selfInfo } from "../../common/data";
|
||||||
|
import { SendMsgElementConstructor } from "../../ntqqapi/constructor";
|
||||||
|
import {sleep} from "../../common/utils";
|
||||||
|
|
||||||
|
|
||||||
|
export interface PayloadType {
|
||||||
|
message: string,
|
||||||
|
group_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TestForwardMsg extends BaseAction<PayloadType, OB11Message> {
|
||||||
|
actionName = ActionName.TestForwardMsg
|
||||||
|
|
||||||
|
protected async _handle(payload: PayloadType) {
|
||||||
|
// log("history msg ids", Object.keys(msgHistory));
|
||||||
|
const selfPeer: Peer = {
|
||||||
|
chatType: ChatType.friend,
|
||||||
|
peerUid: selfInfo.uid
|
||||||
|
}
|
||||||
|
const sendMsg = await NTQQApi.sendMsg(selfPeer, [SendMsgElementConstructor.text(payload.message)])
|
||||||
|
const sendMsg2 = await NTQQApi.sendMsg(selfPeer, [SendMsgElementConstructor.text(payload.message)])
|
||||||
|
await NTQQApi.multiForwardMsg(
|
||||||
|
selfPeer,
|
||||||
|
{chatType: ChatType.group, peerUid: payload.group_id, guildId: ""},
|
||||||
|
[sendMsg.msgId, sendMsg2.msgId]
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,10 @@ import GetVersionInfo from "./GetVersionInfo";
|
|||||||
import CanSendRecord from "./CanSendRecord";
|
import CanSendRecord from "./CanSendRecord";
|
||||||
import CanSendImage from "./CanSendImage";
|
import CanSendImage from "./CanSendImage";
|
||||||
import GetStatus from "./GetStatus";
|
import GetStatus from "./GetStatus";
|
||||||
|
import TestForwardMsg from "./TestForwdMsg";
|
||||||
|
|
||||||
export const actionHandlers = [
|
export const actionHandlers = [
|
||||||
|
new TestForwardMsg(),
|
||||||
new GetMsg(),
|
new GetMsg(),
|
||||||
new GetLoginInfo(),
|
new GetLoginInfo(),
|
||||||
new GetFriendList(),
|
new GetFriendList(),
|
||||||
|
@ -14,6 +14,7 @@ export interface InvalidCheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ActionName{
|
export enum ActionName{
|
||||||
|
TestForwardMsg = "test_forward_msg",
|
||||||
GetLoginInfo = "get_login_info",
|
GetLoginInfo = "get_login_info",
|
||||||
GetFriendList = "get_friend_list",
|
GetFriendList = "get_friend_list",
|
||||||
GetGroupInfo = "get_group_info",
|
GetGroupInfo = "get_group_info",
|
||||||
|
@ -41,24 +41,28 @@ expressAPP.use((req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const expressAuthorize = (req: Request, res: Response, next: () => void) => {
|
const expressAuthorize = (req: Request, res: Response, next: () => void) => {
|
||||||
let token = ""
|
try {
|
||||||
const authHeader = req.get("authorization")
|
let token = ""
|
||||||
if (authHeader) {
|
const authHeader = req.get("authorization")
|
||||||
token = authHeader.split("Bearer ").pop()
|
if (authHeader) {
|
||||||
log("receive http header token", token)
|
token = authHeader.split("Bearer ").pop()
|
||||||
} else if (req.query.access_token) {
|
log("receive http header token", token)
|
||||||
if (Array.isArray(req.query.access_token)) {
|
} else if (req.query.access_token) {
|
||||||
token = req.query.access_token[0].toString();
|
if (Array.isArray(req.query.access_token)) {
|
||||||
} else {
|
token = req.query.access_token[0].toString();
|
||||||
token = req.query.access_token.toString();
|
} else {
|
||||||
|
token = req.query.access_token.toString();
|
||||||
|
}
|
||||||
|
log("receive http url token", token)
|
||||||
}
|
}
|
||||||
log("receive http url token", token)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
if (token != accessToken) {
|
if (token != accessToken) {
|
||||||
return res.status(403).send(JSON.stringify({message: 'token verify failed!'}));
|
return res.status(403).send(JSON.stringify({message: 'token verify failed!'}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}catch (e) {
|
||||||
|
log("receive http failed", e.stack)
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
|
|
||||||
|
@ -71,19 +71,6 @@ export interface OB11Message {
|
|||||||
raw?: RawMessage
|
raw?: RawMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OB11ApiName =
|
|
||||||
"send_msg"
|
|
||||||
| "send_private_msg"
|
|
||||||
| "send_group_msg"
|
|
||||||
| "get_group_list"
|
|
||||||
| "get_group_info"
|
|
||||||
| "get_friend_list"
|
|
||||||
| "delete_msg"
|
|
||||||
| "get_login_info"
|
|
||||||
| "get_group_member_list"
|
|
||||||
| "get_group_member_info"
|
|
||||||
| "get_msg"
|
|
||||||
|
|
||||||
export interface OB11Return<DataType> {
|
export interface OB11Return<DataType> {
|
||||||
status: number
|
status: number
|
||||||
retcode: number
|
retcode: number
|
||||||
@ -102,45 +89,69 @@ export enum OB11MessageDataType {
|
|||||||
at = "at",
|
at = "at",
|
||||||
reply = "reply",
|
reply = "reply",
|
||||||
json = "json",
|
json = "json",
|
||||||
face = "face"
|
face = "face",
|
||||||
|
node = "node" // 合并转发消息
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OB11MessageData = {
|
export interface OB11MessageText {
|
||||||
type: OB11MessageDataType.text,
|
type: OB11MessageDataType.text,
|
||||||
content: string,
|
data: {
|
||||||
data?: {
|
|
||||||
text: string, // 纯文本
|
text: string, // 纯文本
|
||||||
}
|
}
|
||||||
} | {
|
}
|
||||||
type: "image" | "voice" | "record",
|
|
||||||
file: string, // 本地路径
|
interface OB11MessageFileBase {
|
||||||
data?: {
|
|
||||||
file: string // 本地路径
|
|
||||||
}
|
|
||||||
} | {
|
|
||||||
type: OB11MessageDataType.at,
|
|
||||||
atType?: AtType,
|
|
||||||
content?: string,
|
|
||||||
atUid?: string,
|
|
||||||
atNtUid?: string,
|
|
||||||
data?: {
|
|
||||||
qq: string // at的qq号
|
|
||||||
}
|
|
||||||
} | {
|
|
||||||
type: OB11MessageDataType.reply,
|
|
||||||
msgId: string,
|
|
||||||
msgSeq: string,
|
|
||||||
senderUin: string,
|
|
||||||
data: {
|
data: {
|
||||||
id: string,
|
file: string
|
||||||
}
|
}
|
||||||
} | {
|
}
|
||||||
type: OB11MessageDataType.face,
|
|
||||||
|
export interface OB11MessageImage extends OB11MessageFileBase {
|
||||||
|
type: OB11MessageDataType.image
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OB11MessageRecord extends OB11MessageFileBase {
|
||||||
|
type: OB11MessageDataType.voice
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OB11MessageAt {
|
||||||
|
type: OB11MessageDataType.at
|
||||||
|
data: {
|
||||||
|
qq: string | "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OB11MessageReply {
|
||||||
|
type: OB11MessageDataType.reply
|
||||||
data: {
|
data: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OB11MessageFace {
|
||||||
|
type: OB11MessageDataType.face
|
||||||
|
data: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OB11MessageNode {
|
||||||
|
type: OB11MessageDataType.node
|
||||||
|
data: {
|
||||||
|
id?: string
|
||||||
|
user_id?: number
|
||||||
|
nickname: string
|
||||||
|
content: OB11MessageData[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OB11MessageData =
|
||||||
|
OB11MessageText |
|
||||||
|
OB11MessageFace |
|
||||||
|
OB11MessageAt | OB11MessageReply |
|
||||||
|
OB11MessageImage | OB11MessageRecord |
|
||||||
|
OB11MessageNode
|
||||||
|
|
||||||
export interface OB11PostSendMsg {
|
export interface OB11PostSendMsg {
|
||||||
message_type?: "private" | "group"
|
message_type?: "private" | "group"
|
||||||
user_id: string,
|
user_id: string,
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
// Electron 主进程 与 渲染进程 交互的桥梁
|
// Electron 主进程 与 渲染进程 交互的桥梁
|
||||||
|
|
||||||
import {Config} from "./common/types";
|
import {Config} from "./common/types";
|
||||||
import {
|
import {CHANNEL_GET_CONFIG, CHANNEL_LOG, CHANNEL_SET_CONFIG,} from "./common/channels";
|
||||||
CHANNEL_GET_CONFIG,
|
|
||||||
CHANNEL_LOG,
|
|
||||||
CHANNEL_SET_CONFIG,
|
|
||||||
} from "./common/channels";
|
|
||||||
|
|
||||||
|
|
||||||
const {contextBridge} = require("electron");
|
const {contextBridge} = require("electron");
|
||||||
const {ipcRenderer} = require('electron');
|
const {ipcRenderer} = require('electron');
|
||||||
|
|
||||||
// 在window对象下导出只读对象
|
const llonebot = {
|
||||||
contextBridge.exposeInMainWorld("llonebot", {
|
|
||||||
log: (data: any) => {
|
log: (data: any) => {
|
||||||
ipcRenderer.send(CHANNEL_LOG, data);
|
ipcRenderer.send(CHANNEL_LOG, data);
|
||||||
},
|
},
|
||||||
setConfig: (config: Config)=>{
|
setConfig: (config: Config) => {
|
||||||
ipcRenderer.send(CHANNEL_SET_CONFIG, config);
|
ipcRenderer.send(CHANNEL_SET_CONFIG, config);
|
||||||
},
|
},
|
||||||
getConfig: async () => {
|
getConfig: async () => {
|
||||||
return ipcRenderer.invoke(CHANNEL_GET_CONFIG);
|
return ipcRenderer.invoke(CHANNEL_GET_CONFIG);
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export type LLOneBot = typeof llonebot;
|
||||||
|
|
||||||
|
// 在window对象下导出只读对象
|
||||||
|
contextBridge.exposeInMainWorld("llonebot", llonebot);
|
||||||
|
;
|
@ -67,7 +67,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
<div>
|
<div>
|
||||||
<div>上报自身消息</div>
|
<div>上报自身消息</div>
|
||||||
<div class="tips">开启后上报自己发出的消息</div>
|
<div class="tips">慎用,不然会自己和自己聊个不停</div>
|
||||||
</div>
|
</div>
|
||||||
<setting-switch id="reportSelfMessage" ${config.reportSelfMessage ? "is-active" : ""}></setting-switch>
|
<setting-switch id="reportSelfMessage" ${config.reportSelfMessage ? "is-active" : ""}></setting-switch>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
@ -165,6 +165,21 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
let hash = location.hash;
|
||||||
|
if (hash === "#/blank") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (location.hash === "#/blank") {
|
||||||
|
(window as any).navigation.addEventListener("navigatesuccess", init, {once: true});
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
onSettingWindowCreated
|
onSettingWindowCreated
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user