feat(server): first version
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const socket = require("./socket.js");
|
||||
const db = require("./db.js");
|
||||
const {
|
||||
bot,
|
||||
getDisplayName,
|
||||
getGroupMsgSpeaker,
|
||||
getNickName,
|
||||
} = require("./bot.js");
|
||||
const {
|
||||
composeMessageID,
|
||||
composeMediaFilePath,
|
||||
composeFilename,
|
||||
composeCacheFilePath,
|
||||
fileMD5,
|
||||
ensureMediaDir,
|
||||
} = require("./util");
|
||||
|
||||
async function processMessage(msg) {
|
||||
if ([50, 51, 52, 53, 9999].includes(msg.MsgType)) {
|
||||
return;
|
||||
}
|
||||
const peerContact = bot.contacts[msg.getPeerUserName()];
|
||||
const fromContact = bot.contacts[msg["FromUserName"]];
|
||||
const toContact = bot.contacts[msg["ToUserName"]];
|
||||
if (!peerContact || !fromContact || !toContact) {
|
||||
// TODO: notify self
|
||||
return;
|
||||
}
|
||||
if (
|
||||
bot.Contact.isPublicContact(peerContact) ||
|
||||
(bot.Contact.isSpContact(peerContact) &&
|
||||
peerContact.UserName !== "filehelper")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureMediaDir(msg);
|
||||
|
||||
const msgID = msg["MsgId"];
|
||||
const msgType = msg["MsgType"];
|
||||
|
||||
const m = {
|
||||
messageID: msgID,
|
||||
composedID: composeMessageID(msg),
|
||||
createTimestamp: msg["CreateTime"],
|
||||
messageType: msgType,
|
||||
fromID: msg["FromUserName"],
|
||||
toID: msg["ToUserName"],
|
||||
fromName: getDisplayName(fromContact),
|
||||
fromNickName: getNickName(fromContact),
|
||||
toName: getDisplayName(toContact),
|
||||
toNickName: getNickName(toContact),
|
||||
type: "unknown",
|
||||
content: null,
|
||||
group: bot.Contact.isRoomContact(peerContact) ? peerContact : null,
|
||||
speakingGroupMember: null,
|
||||
filename: null,
|
||||
displayFilename: msg["FileName"] || "",
|
||||
isGroupMessage: bot.Contact.isRoomContact(peerContact),
|
||||
};
|
||||
|
||||
if (m.isGroupMessage) {
|
||||
if (!msg.isSendBySelf) {
|
||||
m.speakingGroupMember = getGroupMsgSpeaker(msg);
|
||||
}
|
||||
}
|
||||
|
||||
switch (msgType) {
|
||||
case bot.CONF.MSGTYPE_TEXT:
|
||||
// 文本消息
|
||||
m.type = "text";
|
||||
m.content = msg["Content"];
|
||||
break;
|
||||
case bot.CONF.MSGTYPE_EMOTICON:
|
||||
case bot.CONF.MSGTYPE_IMAGE: {
|
||||
const suffix = msgType === bot.CONF.MSGTYPE_IMAGE ? ".jpg" : ".gif";
|
||||
m.type = "img";
|
||||
m.content =
|
||||
`【${msgType === bot.CONF.MSGTYPE_IMAGE ? "图片" : "表情"}】` +
|
||||
(msg["FileName"] || "");
|
||||
if (msg["HasProductId"]) {
|
||||
m.type = "unknown";
|
||||
m.content = "【表情贴图】请在手机上查看";
|
||||
break;
|
||||
}
|
||||
const cachePath = composeCacheFilePath(msg, suffix);
|
||||
// ENHANCE: 提前判断表情是否存在,节约带宽
|
||||
const res = await bot.getMsgImg(msg.MsgId);
|
||||
fs.writeFileSync(cachePath, res.data);
|
||||
const md5 = await fileMD5(cachePath);
|
||||
m.filename = md5 + suffix;
|
||||
const filename = composeMediaFilePath(msg, m.filename);
|
||||
if (fs.existsSync(filename)) {
|
||||
fs.rmSync(cachePath);
|
||||
} else {
|
||||
fs.renameSync(cachePath, filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case bot.CONF.MSGTYPE_VOICE: {
|
||||
m.type = "voice";
|
||||
m.content = "【语音消息】";
|
||||
m.filename = composeFilename(msg, ".mp3");
|
||||
const { data } = await bot.getVoice(msg.MsgId);
|
||||
fs.writeFileSync(composeMediaFilePath(msg, m.filename), data);
|
||||
break;
|
||||
}
|
||||
case bot.CONF.MSGTYPE_VIDEO:
|
||||
case bot.CONF.MSGTYPE_MICROVIDEO: {
|
||||
m.type = "video";
|
||||
const suffix = ".mp4";
|
||||
const cachePath = composeCacheFilePath(msg, suffix);
|
||||
const res = await bot.getVideo(msg.MsgId);
|
||||
fs.writeFileSync(cachePath, res.data);
|
||||
const md5 = await fileMD5(cachePath);
|
||||
m.filename = md5 + suffix;
|
||||
const filename = composeMediaFilePath(msg, m.filename);
|
||||
if (fs.existsSync(filename)) {
|
||||
fs.rmSync(cachePath);
|
||||
} else {
|
||||
fs.renameSync(cachePath, filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case bot.CONF.MSGTYPE_APP:
|
||||
m.type = "file";
|
||||
if (msg.AppMsgType === 5) {
|
||||
m.type = "text";
|
||||
m.content = "【链接】" + msg["FileName"] + ": " + msg["Url"];
|
||||
break;
|
||||
} else if (msg.AppMsgType == 6) {
|
||||
if (!(msg.FileSize < 10 * 1024 * 1024)) {
|
||||
// 忽略10M以上的大文件
|
||||
m.type = "unknown";
|
||||
m.content = "【文件】" + m.displayFilename;
|
||||
m.filename = null;
|
||||
break;
|
||||
}
|
||||
const suffix = path.extname(m.displayFilename);
|
||||
const cachePath = composeCacheFilePath(msg, suffix);
|
||||
const res = await bot.getDoc(
|
||||
msg.FromUserName,
|
||||
msg.MediaId,
|
||||
msg.FileName
|
||||
);
|
||||
fs.writeFileSync(cachePath, res.data);
|
||||
const md5 = await fileMD5(cachePath);
|
||||
m.filename = md5 + suffix;
|
||||
const filename = composeMediaFilePath(msg, m.filename);
|
||||
if (fs.existsSync(filename)) {
|
||||
fs.rmSync(cachePath);
|
||||
} else {
|
||||
fs.renameSync(cachePath, filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (m.type === "unknown") {
|
||||
m.content ||= "未知类型的消息,请在手机上查看";
|
||||
}
|
||||
|
||||
const dbMsg = {
|
||||
messageID: m.composedID,
|
||||
createTimestamp: m.createTimestamp,
|
||||
type: m.type,
|
||||
messageType: m.messageType,
|
||||
fromName: m.fromName,
|
||||
fromNickName: m.fromNickName,
|
||||
toName: m.toName,
|
||||
toNickName: m.toNickName,
|
||||
isGroupMessage: m.isGroupMessage,
|
||||
speakingGroupMemberName:
|
||||
(m.speakingGroupMember && getDisplayName(m.speakingGroupMember)) || null,
|
||||
content: m.content,
|
||||
filename: m.filename,
|
||||
displayFilename: m.displayFilename,
|
||||
};
|
||||
const clientMsg = {
|
||||
msgID: m.messageID,
|
||||
composedID: m.composedID,
|
||||
createTimestamp: m.createTimestamp,
|
||||
type: m.type,
|
||||
fromID: m.fromID,
|
||||
fromName: m.fromName,
|
||||
fromNickName: m.fromNickName,
|
||||
toID: m.toID,
|
||||
toName: m.toName,
|
||||
toNickName: m.toNickName,
|
||||
isGroupMessage: m.isGroupMessage,
|
||||
speakingGroupMemberID:
|
||||
m.speakingGroupMember && m.speakingGroupMember.UserName,
|
||||
speakingGroupMemberName:
|
||||
(m.speakingGroupMember && getDisplayName(m.speakingGroupMember)) || null,
|
||||
content: m.content,
|
||||
filename: m.filename,
|
||||
displayFilename: m.displayFilename,
|
||||
};
|
||||
await db.pushMessage(dbMsg);
|
||||
socket.pushMessage(clientMsg);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processMessage,
|
||||
};
|
||||
Reference in New Issue
Block a user