mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
refactor: 统一时间戳为毫秒,优化发送消息逻辑代码
fix: 发送文件的文件名保持原样
This commit is contained in:
parent
c636af0b0e
commit
9faa56ec32
@ -47,6 +47,8 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
|||||||
- [x] 处理添加好友请求
|
- [x] 处理添加好友请求
|
||||||
- [x] 处理加群请求
|
- [x] 处理加群请求
|
||||||
- [x] 退群
|
- [x] 退群
|
||||||
|
- [ ] 上报加群邀请
|
||||||
|
- [ ] 同意加群邀请
|
||||||
- [x] 上报好友消息
|
- [x] 上报好友消息
|
||||||
- [x] 上报添加好友请求
|
- [x] 上报添加好友请求
|
||||||
- [x] 上报群消息
|
- [x] 上报群消息
|
||||||
@ -159,6 +161,8 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
|||||||
- [x] 群管理功能,禁言、踢人,改群名片等
|
- [x] 群管理功能,禁言、踢人,改群名片等
|
||||||
- [x] 视频消息
|
- [x] 视频消息
|
||||||
- [x] 文件消息
|
- [x] 文件消息
|
||||||
|
- [ ] 上报加群邀请
|
||||||
|
- [ ] 同意加群邀请
|
||||||
- [ ] 音乐卡片
|
- [ ] 音乐卡片
|
||||||
- [ ] 无头模式
|
- [ ] 无头模式
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
SendTextElement
|
SendTextElement
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import {NTQQApi} from "./ntcall";
|
import {NTQQApi} from "./ntcall";
|
||||||
import {encodeSilk, log} from "../common/utils";
|
import {encodeSilk} from "../common/utils";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ export class SendMsgElementConstructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async pic(picPath: string): Promise<SendPicElement> {
|
static async pic(picPath: string): Promise<SendPicElement> {
|
||||||
const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(picPath);
|
const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(picPath, ElementType.PIC);
|
||||||
const imageSize = await NTQQApi.getImageSize(picPath);
|
const imageSize = await NTQQApi.getImageSize(picPath);
|
||||||
const picElement = {
|
const picElement = {
|
||||||
md5HexStr: md5,
|
md5HexStr: md5,
|
||||||
@ -81,8 +81,14 @@ export class SendMsgElementConstructor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static async file(filePath: string, isVideo:boolean = false): Promise<SendFileElement> {
|
static async file(filePath: string, isVideo: boolean = false): Promise<SendFileElement> {
|
||||||
const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(filePath);
|
let picHeight = 0;
|
||||||
|
let picWidth = 0;
|
||||||
|
if (isVideo) {
|
||||||
|
picHeight = 1024;
|
||||||
|
picWidth = 768;
|
||||||
|
}
|
||||||
|
const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(filePath, ElementType.FILE);
|
||||||
let element: SendFileElement = {
|
let element: SendFileElement = {
|
||||||
elementType: ElementType.FILE,
|
elementType: ElementType.FILE,
|
||||||
elementId: "",
|
elementId: "",
|
||||||
@ -90,18 +96,18 @@ export class SendMsgElementConstructor {
|
|||||||
fileName,
|
fileName,
|
||||||
"filePath": path,
|
"filePath": path,
|
||||||
"fileSize": (fileSize).toString(),
|
"fileSize": (fileSize).toString(),
|
||||||
|
picHeight,
|
||||||
|
picWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isVideo){
|
|
||||||
element.fileElement.picHeight = 1024;
|
|
||||||
element.fileElement.picWidth = 768;
|
|
||||||
}
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
static video(filePath: string): Promise<SendFileElement> {
|
static video(filePath: string): Promise<SendFileElement> {
|
||||||
return SendMsgElementConstructor.file(filePath, true);
|
return SendMsgElementConstructor.file(filePath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async ptt(pttPath: string): Promise<SendPttElement> {
|
static async ptt(pttPath: string): Promise<SendPttElement> {
|
||||||
const {converted, path: silkPath, duration} = await encodeSilk(pttPath);
|
const {converted, path: silkPath, duration} = await encodeSilk(pttPath);
|
||||||
// log("生成语音", silkPath, duration);
|
// log("生成语音", silkPath, duration);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import {ipcMain} from "electron";
|
import {ipcMain} from "electron";
|
||||||
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
|
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
|
||||||
import {log} from "../common/utils";
|
import {log, sleep} from "../common/utils";
|
||||||
import {
|
import {
|
||||||
ChatType,
|
ChatType,
|
||||||
ElementType,
|
ElementType,
|
||||||
Friend,
|
Friend,
|
||||||
FriendRequest,
|
FriendRequest,
|
||||||
Group,
|
Group,
|
||||||
GroupMember, GroupMemberRole,
|
GroupMember,
|
||||||
|
GroupMemberRole,
|
||||||
GroupNotifies,
|
GroupNotifies,
|
||||||
GroupNotify,
|
GroupNotify,
|
||||||
GroupRequestOperateTypes,
|
GroupRequestOperateTypes,
|
||||||
@ -19,6 +20,7 @@ import {
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import {addHistoryMsg, friendRequests, groupNotifies, msgHistory, selfInfo} from "../common/data";
|
import {addHistoryMsg, friendRequests, groupNotifies, msgHistory, selfInfo} from "../common/data";
|
||||||
import {v4 as uuidv4} from "uuid"
|
import {v4 as uuidv4} from "uuid"
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
interface IPCReceiveEvent {
|
interface IPCReceiveEvent {
|
||||||
eventName: string
|
eventName: string
|
||||||
@ -346,7 +348,10 @@ export class NTQQApi {
|
|||||||
} else {
|
} else {
|
||||||
ext = ""
|
ext = ""
|
||||||
}
|
}
|
||||||
const fileName = `${md5}${ext}`;
|
let fileName = `${path.basename(filePath)}`;
|
||||||
|
if (fileName.indexOf(".") === -1) {
|
||||||
|
fileName += ext;
|
||||||
|
}
|
||||||
const mediaPath = await callNTQQApi<string>({
|
const mediaPath = await callNTQQApi<string>({
|
||||||
methodName: NTQQApiMethod.MEDIA_FILE_PATH,
|
methodName: NTQQApiMethod.MEDIA_FILE_PATH,
|
||||||
args: [{
|
args: [{
|
||||||
@ -414,71 +419,57 @@ export class NTQQApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = false, timeout = 10000) {
|
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = false, timeout = 10000) {
|
||||||
const sendTimeout = timeout
|
const peerUid = peer.peerUid;
|
||||||
|
|
||||||
return new Promise<RawMessage>((resolve, reject) => {
|
// 等待上一个相同的peer发送完
|
||||||
const peerUid = peer.peerUid;
|
let checkLastSendUsingTime = 0;
|
||||||
let usingTime = 0;
|
const waitLastSend = async () => {
|
||||||
let success = false;
|
if (checkLastSendUsingTime > timeout) {
|
||||||
let isTimeout = false;
|
throw ("发送超时")
|
||||||
|
|
||||||
const checkSuccess = () => {
|
|
||||||
if (!success) {
|
|
||||||
sendMessagePool[peerUid] = null;
|
|
||||||
isTimeout = true;
|
|
||||||
reject("发送超时")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setTimeout(checkSuccess, sendTimeout);
|
let lastSending = sendMessagePool[peer.peerUid]
|
||||||
|
if (lastSending) {
|
||||||
const checkLastSend = () => {
|
// log("有正在发送的消息,等待中...")
|
||||||
let lastSending = sendMessagePool[peerUid]
|
await sleep(500);
|
||||||
if (sendTimeout < usingTime) {
|
checkLastSendUsingTime += 500;
|
||||||
sendMessagePool[peerUid] = null;
|
return await waitLastSend();
|
||||||
isTimeout = true;
|
} else {
|
||||||
reject("发送超时")
|
return;
|
||||||
}
|
|
||||||
if (!!lastSending) {
|
|
||||||
// log("有正在发送的消息,等待中...")
|
|
||||||
usingTime += 500;
|
|
||||||
setTimeout(checkLastSend, 500);
|
|
||||||
} else {
|
|
||||||
log("可以进行发送消息,设置发送成功回调", sendMessagePool)
|
|
||||||
sendMessagePool[peerUid] = (rawMessage: RawMessage) => {
|
|
||||||
sendMessagePool[peerUid] = null;
|
|
||||||
const checkSendComplete = () => {
|
|
||||||
if (isTimeout) {
|
|
||||||
return reject("发送超时")
|
|
||||||
}
|
|
||||||
if (msgHistory[rawMessage.msgId]?.sendStatus == 2) {
|
|
||||||
log(`给${peerUid}发送消息成功`)
|
|
||||||
success = true;
|
|
||||||
resolve(rawMessage);
|
|
||||||
} else {
|
|
||||||
setTimeout(checkSendComplete, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (waitComplete) {
|
|
||||||
checkSendComplete();
|
|
||||||
} else {
|
|
||||||
success = true;
|
|
||||||
log(`给${peerUid}发送消息成功`)
|
|
||||||
resolve(rawMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checkLastSend()
|
}
|
||||||
callNTQQApi({
|
await waitLastSend();
|
||||||
methodName: NTQQApiMethod.SEND_MSG,
|
|
||||||
args: [{
|
let sentMessage: RawMessage = null;
|
||||||
msgId: "0",
|
sendMessagePool[peerUid] = async (rawMessage: RawMessage) => {
|
||||||
peer, msgElements,
|
delete sendMessagePool[peerUid];
|
||||||
msgAttributeInfos: new Map(),
|
sentMessage = rawMessage;
|
||||||
}, null]
|
}
|
||||||
}).then()
|
|
||||||
})
|
let checkSendCompleteUsingTime = 0;
|
||||||
|
const checkSendComplete = async (): Promise<RawMessage> => {
|
||||||
|
if (sentMessage && msgHistory[sentMessage.msgId]?.sendStatus == 2) {
|
||||||
|
// log(`给${peerUid}发送消息成功`)
|
||||||
|
return sentMessage;
|
||||||
|
} else {
|
||||||
|
checkSendCompleteUsingTime += 500;
|
||||||
|
if (checkSendCompleteUsingTime > timeout) {
|
||||||
|
throw ("发送超时")
|
||||||
|
}
|
||||||
|
await sleep(500);
|
||||||
|
return await checkSendComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callNTQQApi({
|
||||||
|
methodName: NTQQApiMethod.SEND_MSG,
|
||||||
|
args: [{
|
||||||
|
msgId: "0",
|
||||||
|
peer, msgElements,
|
||||||
|
msgAttributeInfos: new Map(),
|
||||||
|
}, null]
|
||||||
|
}).then()
|
||||||
|
return checkSendComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||||
@ -638,7 +629,8 @@ export class NTQQApi {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
static banGroup(groupQQ: string, shutUp: boolean){
|
|
||||||
|
static banGroup(groupQQ: string, shutUp: boolean) {
|
||||||
return callNTQQApi<GeneralCallResult>({
|
return callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.MUTE_GROUP,
|
methodName: NTQQApiMethod.MUTE_GROUP,
|
||||||
args: [
|
args: [
|
||||||
@ -676,14 +668,14 @@ export class NTQQApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static setGroupName(groupQQ: string, groupName: string){
|
static setGroupName(groupQQ: string, groupName: string) {
|
||||||
return callNTQQApi<GeneralCallResult>({
|
return callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
||||||
args:[
|
args: [
|
||||||
{
|
{
|
||||||
groupCode: groupQQ,
|
groupCode: groupQQ,
|
||||||
groupName
|
groupName
|
||||||
},null
|
}, null
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
case OB11MessageDataType.voice: {
|
case OB11MessageDataType.voice: {
|
||||||
const file = sendMsg.data?.file
|
const file = sendMsg.data?.file
|
||||||
if (file) {
|
if (file) {
|
||||||
const {path, isLocal} = (await uri2local(uuidv4(), file))
|
const {path, isLocal} = (await uri2local(file))
|
||||||
if (path) {
|
if (path) {
|
||||||
if (!isLocal) { // 只删除http和base64转过来的文件
|
if (!isLocal) { // 只删除http和base64转过来的文件
|
||||||
deleteAfterSentFiles.push(path)
|
deleteAfterSentFiles.push(path)
|
||||||
|
@ -23,7 +23,7 @@ export class OB11Constructor {
|
|||||||
const resMsg: OB11Message = {
|
const resMsg: OB11Message = {
|
||||||
self_id: parseInt(selfInfo.uin),
|
self_id: parseInt(selfInfo.uin),
|
||||||
user_id: parseInt(msg.senderUin),
|
user_id: parseInt(msg.senderUin),
|
||||||
time: parseInt(msg.msgTime) || 0,
|
time: parseInt(msg.msgTime) * 1000 || Date.now(), // 13位时间戳,毫秒
|
||||||
message_id: msg.msgShortId,
|
message_id: msg.msgShortId,
|
||||||
real_id: msg.msgId,
|
real_id: msg.msgId,
|
||||||
message_type: msg.chatType == ChatType.group ? "group" : "private",
|
message_type: msg.chatType == ChatType.group ? "group" : "private",
|
||||||
|
@ -10,7 +10,7 @@ export enum EventType {
|
|||||||
|
|
||||||
|
|
||||||
export abstract class OB11BaseEvent {
|
export abstract class OB11BaseEvent {
|
||||||
time = new Date().getTime();
|
time = Date.now();
|
||||||
self_id = parseInt(selfInfo.uin);
|
self_id = parseInt(selfInfo.uin);
|
||||||
post_type: EventType;
|
post_type: EventType;
|
||||||
}
|
}
|
@ -1,10 +1,13 @@
|
|||||||
import {CONFIG_DIR, isGIF} from "../common/utils";
|
import {CONFIG_DIR, isGIF} from "../common/utils";
|
||||||
|
import {v4 as uuidv4} from "uuid";
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {OB11MessageData} from "./types";
|
|
||||||
|
|
||||||
const fs = require("fs").promises;
|
const fs = require("fs").promises;
|
||||||
|
|
||||||
export async function uri2local(fileName: string, uri: string){
|
export async function uri2local(uri: string, fileName: string=null){
|
||||||
|
if (!fileName){
|
||||||
|
fileName = uuidv4();
|
||||||
|
}
|
||||||
let filePath = path.join(CONFIG_DIR, fileName)
|
let filePath = path.join(CONFIG_DIR, fileName)
|
||||||
let url = new URL(uri);
|
let url = new URL(uri);
|
||||||
let res = {
|
let res = {
|
||||||
@ -33,6 +36,8 @@ export async function uri2local(fileName: string, uri: string){
|
|||||||
let blob = await fetchRes.blob();
|
let blob = await fetchRes.blob();
|
||||||
let buffer = await blob.arrayBuffer();
|
let buffer = await blob.arrayBuffer();
|
||||||
try {
|
try {
|
||||||
|
fileName = path.basename(url.pathname) || fileName
|
||||||
|
filePath = path.join(CONFIG_DIR, fileName)
|
||||||
await fs.writeFile(filePath, Buffer.from(buffer));
|
await fs.writeFile(filePath, Buffer.from(buffer));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
res.errMsg = `${url}下载失败,` + e.toString()
|
res.errMsg = `${url}下载失败,` + e.toString()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user