Skip to content
This repository has been archived by the owner on Nov 2, 2023. It is now read-only.

Commit

Permalink
Merge pull request #91 from takayama-lily/dev
Browse files Browse the repository at this point in the history
-
  • Loading branch information
takayama-lily authored Nov 16, 2020
2 parents a91183a + 988d083 commit 6df879c
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 72 deletions.
2 changes: 1 addition & 1 deletion docs/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@ CQ码是指字符串格式下用于表示多媒体内容的方式,形如:
|video|||
|location|||[CQ:location,address=江西省九江市修水县,lat=29.063940,lng=114.339610]|
|contact|◯|✕|联系人或群推荐
|reply|||
|reply|◯|◯|[CQ:reply,id=xxxxxx]
|share|◯|◯|链接分享
|<s>node</s>|||<s>[CQ:node,uin=123456789,name=昵称,content=消息内容,time=时间戳]<br>time可省略,暂时只支持纯文本/s>|
38 changes: 37 additions & 1 deletion lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,43 @@ function log(any) {
console.log(util.inspect(any, {depth: 20, showHidden: false, maxArrayLength: 1000, maxStringLength: 5000}));
}

function genC2CMessageId(user_id, seq, random, time) {
const buf = Buffer.allocUnsafe(16);
buf.writeUInt32BE(user_id),
buf.writeInt32BE(seq&0xffffffff, 4),
buf.writeInt32BE(random&0xffffffff, 8),
buf.writeUInt32BE(time, 12);
return buf.toString("base64");
}
function parseC2CMessageId(message_id) {
const buf = Buffer.from(message_id, "base64");
const user_id = buf.readUInt32BE(),
seq = buf.readUInt32BE(4),
random = buf.readUInt32BE(8),
time = buf.readUInt32BE(12);
return {user_id, seq, random, time};
}
function genGroupMessageId(group_id, user_id, seq, random, time) {
const buf = Buffer.allocUnsafe(20);
buf.writeUInt32BE(group_id),
buf.writeUInt32BE(user_id, 4),
buf.writeInt32BE(seq&0xffffffff, 8),
buf.writeInt32BE(random&0xffffffff, 12),
buf.writeUInt32BE(time, 16);
return buf.toString("base64");
}
function parseGroupMessageId(message_id) {
const buf = Buffer.from(message_id, "base64");
const group_id = buf.readUInt32BE(),
user_id = buf.readUInt32BE(4),
seq = buf.readUInt32BE(8),
random = buf.readUInt32BE(12),
time = buf.readUInt32BE(16);
return {group_id, user_id, seq, random, time};
}

module.exports = {
uuid, md5, timestamp, checkUin, uinAutoCheck,
log, code2uin, uin2code, escapeXml
log, code2uin, uin2code, escapeXml,
genC2CMessageId, parseC2CMessageId, genGroupMessageId, parseGroupMessageId
};
10 changes: 0 additions & 10 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@ function onPushReq(blob, seq) {
};
const body = jce.encodeWrapper({PushResp}, extra);
this.writeUNI("ConfigPushSvc.PushResp", body);

let ip, port;
if (parent[1] === 1) {
let server = jce.decode(parent[2])[1][0];
server = jce.decode(server);
ip = server[0], port = server[1];
}
//更换服务器理论上可以获得更好的性能和连接稳定性,一般来说无视这个包也没什么问题
//据说前段时间服务器不稳定导致的频繁掉线和这个有关
this.em("internal.change-server", {ip, port});
}

/**
Expand Down
38 changes: 38 additions & 0 deletions lib/message/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const face = require("./face");
const {downloadWebImage, downloadWebRecord, readFile} = require("../service");
const {uploadPtt, uploadImages, setPrivateImageNested, setGroupImageNested, getAnonInfo} = require("./storage");
const common = require("../common");
const {parseC2CMessageId, parseGroupMessageId} = common;

function unescapeCQ(s) {
if (s === "&#91;") return "[";
Expand Down Expand Up @@ -47,6 +48,7 @@ class Builder {
tasks = [];
imgs = [];
is_forward = false;
reply = false;

/**
* @param {import("../ref").Client} c
Expand Down Expand Up @@ -447,6 +449,39 @@ class Builder {
};
}

buildReplyElem(cq) {
if (this.reply)
return;
var {id} = cq;
try {
if (this.type)
var {user_id, seq, random, time} = parseGroupMessageId(id);
else
var {user_id, seq, random, time} = parseC2CMessageId(id);
} catch {
return;
}
this.elems.unshift({
45: {
1: [seq],
2: user_id,
3: time,
4: 1,
5: [{
1: {
1: "[消息]"
}
}],
6: this.type,
8: {
3: 0x01000000n<<32n|BigInt(random&0xffffffff)
},
10: this.type ? common.code2uin(this.target) : this.c.uin
}
});
this.reply = true;
}

buildGeneralFlagsElem() {
this.elems.push({
37: {
Expand Down Expand Up @@ -504,6 +539,9 @@ class Builder {
case "anonymous":
await this.buildAnonElem(data)
break;
case "reply":
this.buildReplyElem(data);
break;
default:
this.c.logger.warn("未知的CQ码类型:" + type);
break;
Expand Down
43 changes: 11 additions & 32 deletions lib/message/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const parseMessage = require("./parser");
const {uploadMultiMsg, getPrivateFileUrl} = require("./storage");
const common = require("../common");
const pb = require("../pb");
const {genC2CMessageId, parseC2CMessageId, genGroupMessageId, parseGroupMessageId} = common;

//send msg----------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -99,7 +100,7 @@ async function sendPrivateMsg(user_id, rich) {
}
}
const seq = this.seq_id;
const random = crypto.randomBytes(2).readUInt16BE();
const random = crypto.randomBytes(4).readUInt32BE();
const body = pb.encode({
1: routing,
2: {1:1, 2:0, 3:0},
Expand All @@ -112,7 +113,7 @@ async function sendPrivateMsg(user_id, rich) {
const blob = await this.sendUNI("MessageSvc.PbSendMsg", body);
const rsp = pb.decode(blob);
if (rsp[1] === 0) {
const message_id = genSelfMessageId(user_id, seq, random, rsp[3]);
const message_id = genC2CMessageId(user_id, seq, random, rsp[3]);
this.logger.info(`send to: [Private: ${user_id} / message_id: ${message_id}]`);
return {result: 0, data: {message_id}};
}
Expand Down Expand Up @@ -256,39 +257,18 @@ async function sendB77RichMsg(buf) {
return {result: 0, data: {message_id: "该消息暂不支持"}};
}

function genSelfMessageId(user_id, seq, random, timestamp) {
const buf = Buffer.allocUnsafe(12);
buf.writeUInt32BE(user_id), buf.writeUInt16BE(seq, 4), buf.writeUInt16BE(random, 6), buf.writeUInt32BE(timestamp, 8);
return "0" + buf.toString("base64");
}
function parseSelfMessageId(message_id) {
const buf = Buffer.from(message_id.substr(1), "base64");
const user_id = buf.readUInt32BE(), seq = buf.readUInt16BE(4), random = buf.readUInt16BE(6), timestamp = buf.readUInt32BE(8);
return {user_id, seq, random, timestamp};
}
function genGroupMessageId(group_id, seq, random) {
const buf = Buffer.allocUnsafe(12);
buf.writeUInt32BE(group_id), buf.writeInt32BE(seq&0xffffffff, 4), buf.writeInt32BE(random&0xffffffff, 8);
return "1" + buf.toString("base64");
}
function parseGroupMessageId(message_id) {
const buf = Buffer.from(message_id.substr(1), "base64");
const group_id = buf.readUInt32BE(), seq = buf.readUInt32BE(4), random = buf.readUInt32BE(8);
return {group_id, seq, random};
}

//recall----------------------------------------------------------------------------------------------------

async function recallMsg(message_id) {
let body;
if (message_id[0] === "1")
if (message_id.length > 24)
body = recallGroupMsg.call(this, message_id);
else
body = recallPrivateMsg.call(this, message_id);
await this.sendUNI("PbMessageSvc.PbMsgWithDraw", body);
}
function recallPrivateMsg(message_id) {
const {user_id, seq, random, timestamp} = parseSelfMessageId(message_id);
const {user_id, seq, random, time} = parseC2CMessageId(message_id);
let type = 0;
try {
if (this.sl.get(user_id).group_id)
Expand All @@ -301,7 +281,7 @@ function recallPrivateMsg(message_id) {
2: user_id,
3: seq,
4: 16777216n<<32n|BigInt(random),
5: timestamp,
5: time,
6: random,
}],
2: 0,
Expand Down Expand Up @@ -374,7 +354,7 @@ async function onPrivateMsg(type, head, content, body) {
const raw_message = `[CQ:file,url=${url},size=${size},md5=${md5},duration=${duration},busid=0,fileid=${fileid}]`;
this.logger.info(`recv from: [Private: ${user_id}(${sub_type})] ` + raw_message);
this.em("message.private." + sub_type, {
message_id: "none", user_id,
message_id: "", user_id,
message: [{
type: "file",
data: {
Expand All @@ -394,9 +374,9 @@ async function onPrivateMsg(type, head, content, body) {
font = String(body[1][1][9].raw);
random = body[1][1][3];
}
message_id = genGroupMessageId(user_id, seq, random);
message_id = genC2CMessageId(user_id, seq, random, time);
try {
var {chain, raw_message} = await parseMessage.call(this, body[1]);
var {chain, raw_message} = await parseMessage.call(this, body[1], user_id);
} catch (e) {return}
if (raw_message) {
this.logger.info(`recv from: [Private: ${user_id}(${sub_type})] ` + raw_message);
Expand Down Expand Up @@ -424,7 +404,7 @@ async function onGroupMsg(head, body) {
group_name = String(group[8].raw);

this.msgExists(group_id, 0, seq, time);
const message_id = genGroupMessageId(group_id, seq, body[1][1][3]);
const message_id = genGroupMessageId(group_id, user_id, seq, body[1][1][3], time);
this.emit(`interval.${group_id}.${body[1][1][3]}`, message_id);
this.getGroupInfo(group_id);

Expand Down Expand Up @@ -534,6 +514,5 @@ async function onDiscussMsg(head, body) {

module.exports = {
sendMsg, recallMsg, buildSyncCookie,
onPrivateMsg, onGroupMsg, onDiscussMsg,
genGroupMessageId
onPrivateMsg, onGroupMsg, onDiscussMsg
};
15 changes: 15 additions & 0 deletions lib/message/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const music = require("./music");
const face = require("./face");
const {downloadMultiMsg, getGroupFileUrl} = require("./storage");
const pb = require("../pb");
const {genC2CMessageId, genGroupMessageId} = require("../common");

function escapeCQInside(s) {
if (s === "&") return "&amp;";
Expand All @@ -32,6 +33,18 @@ async function parseMessage(rich, from = 0) {
const msg = {type:"",data:{}};
const o = v[type];
switch (type) {
case 45: //reply
if (Array.isArray(o[1]))
o[1] = o[1][0];
try {
const random = parseInt(o[8][3]&0xffffffffn);
if (o[6])
msg.data.id = genGroupMessageId(from, o[2], o[1], random, o[3]);
else
msg.data.id = genC2CMessageId(from, o[1], random, o[3]);
msg.type = "reply";
} catch {}
break;
case 21: //anonGroupMsg
anon = o;
break;
Expand Down Expand Up @@ -84,12 +97,14 @@ async function parseMessage(rich, from = 0) {
bface_tmp = o[4].raw.toString("hex") + o[7].raw.toString("hex") + o[5];
break;
case 4: //notOnlineImage
// console.log(Object.getPrototypeOf(o))
msg.type = "image";
msg.data.file = o[7].raw.toString("hex") + (o[2]?o[2]:"");
if (o[15])
msg.data.url = "http://c2cpicdw.qpic.cn" + o[15].raw;
break;
case 8: //customFace
// console.log(Object.getPrototypeOf(o))
msg.type = "image";
msg.data.file = o[13].raw.toString("hex") + (o[25]?o[25]:"");
if (o[16])
Expand Down
Loading

0 comments on commit 6df879c

Please sign in to comment.