feat: 发送戳一戳

This commit is contained in:
linyuchen
2024-04-03 00:03:50 +08:00
parent 80131e0472
commit ec073da3f6
10 changed files with 116 additions and 44 deletions

View File

@@ -32,7 +32,7 @@ let config = {
targets: [ targets: [
...external.map(genCpModule), ...external.map(genCpModule),
{src: './manifest.json', dest: 'dist'}, {src: './icon.jpg', dest: 'dist'}, {src: './manifest.json', dest: 'dist'}, {src: './icon.jpg', dest: 'dist'},
{src: './src/ntqqapi/external/ccpoke/poke-win32-x64.node', dest: 'dist/main/ccpoke/'}, {src: './src/ntqqapi/external/crychic/crychic-win32-x64.node', dest: 'dist/main/'},
] ]
})] })]
}, },

View File

@@ -47,7 +47,7 @@ import {dbUtil} from "../common/db";
import {setConfig} from "./setConfig"; import {setConfig} from "./setConfig";
import {NTQQUserApi} from "../ntqqapi/api/user"; import {NTQQUserApi} from "../ntqqapi/api/user";
import {NTQQGroupApi} from "../ntqqapi/api/group"; import {NTQQGroupApi} from "../ntqqapi/api/group";
import {registerPokeHandler} from "../ntqqapi/external/ccpoke"; import {crychic} from "../ntqqapi/external/crychic";
import {OB11FriendPokeEvent, OB11GroupPokeEvent} from "../onebot11/event/notice/OB11PokeEvent"; import {OB11FriendPokeEvent, OB11GroupPokeEvent} from "../onebot11/event/notice/OB11PokeEvent";
import {checkNewVersion, upgradeLLOneBot} from "../common/utils/upgrade"; import {checkNewVersion, upgradeLLOneBot} from "../common/utils/upgrade";
import {log} from "../common/utils/log"; import {log} from "../common/utils/log";
@@ -183,7 +183,8 @@ function onLoad() {
async function startReceiveHook() { async function startReceiveHook() {
if (getConfigUtil().getConfig().enablePoke) { if (getConfigUtil().getConfig().enablePoke) {
registerPokeHandler((id, isGroup) => { crychic.loadNode()
crychic.registerPokeHandler((id, isGroup) => {
log(`收到戳一戳消息了!是否群聊:${isGroup}id:${id}`) log(`收到戳一戳消息了!是否群聊:${isGroup}id:${id}`)
let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent; let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent;
if (isGroup) { if (isGroup) {

View File

@@ -21,6 +21,10 @@ import {encodeSilk} from "../common/utils/audio";
export class SendMsgElementConstructor { export class SendMsgElementConstructor {
static poke(groupCode: string, uin: string){
return null
}
static text(content: string): SendTextElement { static text(content: string): SendTextElement {
return { return {
elementType: ElementType.TEXT, elementType: ElementType.TEXT,

View File

@@ -1,28 +0,0 @@
import {log} from "../../../common/utils/log";
let pokeEngine: any = null
type PokeHandler = (id: string, isGroup: boolean)=>void
let pokeRecords: Record<string, number> = {}
export function registerPokeHandler(handler: PokeHandler){
if(!pokeEngine){
try {
pokeEngine = require("./ccpoke/poke-win32-x64.node")
pokeEngine.performHooks();
}catch (e) {
log("戳一戳引擎加载失败", e)
return
}
}
pokeEngine.setHandlerForPokeHook((id: string, isGroup: boolean)=>{
let existTime = pokeRecords[id]
if (existTime){
if (Date.now() - existTime < 1500){
return
}
}
pokeRecords[id] = Date.now()
handler(id, isGroup);
})
}

Binary file not shown.

Binary file not shown.

53
src/ntqqapi/external/crychic/index.ts vendored Normal file
View File

@@ -0,0 +1,53 @@
import {log} from "../../../common/utils";
import {NTQQApi} from "../../ntcall";
type PokeHandler = (id: string, isGroup: boolean) => void
type CrychicHandler = (event: string, id: string, isGroup: boolean) => void
let pokeRecords: Record<string, number> = {}
class Crychic{
private crychic: any = undefined
loadNode(){
if (!this.crychic){
try {
this.crychic = require("./crychic-win32-x64.node")
this.crychic.init()
}catch (e) {
log("crychic加载失败", e)
}
}
}
registerPokeHandler(fn: PokeHandler){
this.registerHandler((event, id, isGroup)=>{
if (event === "poke"){
let existTime = pokeRecords[id]
if (existTime) {
if (Date.now() - existTime < 1500) {
return
}
}
pokeRecords[id] = Date.now()
fn(id, isGroup);
}
})
}
registerHandler(fn: CrychicHandler){
if (!this.crychic) return;
this.crychic.setCryHandler(fn)
}
sendFriendPoke(friendUid: string){
if (!this.crychic) return;
this.crychic.sendFriendPoke(parseInt(friendUid))
NTQQApi.fetchUnitedCommendConfig().then()
}
sendGroupPoke(groupCode: string, memberUin: string){
if (!this.crychic) return;
this.crychic.sendGroupPoke(parseInt(memberUin), parseInt(groupCode))
NTQQApi.fetchUnitedCommendConfig().then()
}
}
export const crychic = new Crychic()

View File

@@ -77,7 +77,9 @@ export enum NTQQApiMethod {
SET_QQ_AVATAR = 'nodeIKernelProfileService/setHeader', SET_QQ_AVATAR = 'nodeIKernelProfileService/setHeader',
GET_SKEY = "nodeIKernelTipOffService/getPskey", GET_SKEY = "nodeIKernelTipOffService/getPskey",
UPDATE_SKEY = "updatePskey" UPDATE_SKEY = "updatePskey",
FETCH_UNITED_COMMEND_CONFIG = "nodeIKernelUnitedConfigService/fetchUnitedCommendConfig" // 发包需要调用的
} }
enum NTQQApiChannel { enum NTQQApiChannel {
@@ -194,4 +196,15 @@ export class NTQQApi {
] ]
}) })
} }
static async fetchUnitedCommendConfig() {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.FETCH_UNITED_COMMEND_CONFIG,
args:[
{
groups: ['100243']
}
]
})
}
} }

View File

@@ -1,7 +1,7 @@
import { import {
AtType, AtType,
ChatType, ChatType,
ElementType, ElementType, Friend,
Group, PicSubType, Group, PicSubType,
RawMessage, RawMessage,
SendArkElement, SendArkElement,
@@ -35,6 +35,7 @@ import {NTQQMsgApi} from "../../../ntqqapi/api/msg";
import {log} from "../../../common/utils/log"; import {log} from "../../../common/utils/log";
import {sleep} from "../../../common/utils/helper"; import {sleep} from "../../../common/utils/helper";
import {uri2local} from "../../../common/utils"; import {uri2local} from "../../../common/utils";
import {crychic} from "../../../ntqqapi/external/crychic";
function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkSendMessage(sendMsgList: OB11MessageData[]) {
function checkUri(uri: string): boolean { function checkUri(uri: string): boolean {
@@ -93,7 +94,7 @@ export function convertMessage2List(message: OB11MessageMixType, autoEscape = fa
return message; return message;
} }
export async function createSendElements(messageData: OB11MessageData[], group: Group | undefined, ignoreTypes: OB11MessageDataType[] = []) { export async function createSendElements(messageData: OB11MessageData[], target: Group | Friend | undefined, ignoreTypes: OB11MessageDataType[] = []) {
let sendElements: SendMessageElement[] = [] let sendElements: SendMessageElement[] = []
let deleteAfterSentFiles: string[] = [] let deleteAfterSentFiles: string[] = []
for (let sendMsg of messageData) { for (let sendMsg of messageData) {
@@ -109,7 +110,7 @@ export async function createSendElements(messageData: OB11MessageData[], group:
} }
break; break;
case OB11MessageDataType.at: { case OB11MessageDataType.at: {
if (!group) { if (!target) {
continue continue
} }
let atQQ = sendMsg.data?.qq; let atQQ = sendMsg.data?.qq;
@@ -119,7 +120,7 @@ export async function createSendElements(messageData: OB11MessageData[], group:
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员")) sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员"))
} else { } else {
// const atMember = group?.members.find(m => m.uin == atQQ) // const atMember = group?.members.find(m => m.uin == atQQ)
const atMember = await getGroupMember(group?.groupCode, atQQ); const atMember = await getGroupMember((target as Group)?.groupCode, atQQ);
if (atMember) { if (atMember) {
sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick)) sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick))
} }
@@ -197,7 +198,22 @@ export async function createSendElements(messageData: OB11MessageData[], group:
case OB11MessageDataType.json: { case OB11MessageDataType.json: {
sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data)) sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data))
} }
break break;
case OB11MessageDataType.poke: {
let qq = sendMsg.data?.qq || sendMsg.data?.id
if (qq) {
if ("groupCode" in target) {
crychic.sendGroupPoke(target.groupCode, qq.toString())
} else {
if (!qq) {
qq = parseInt(target.uin)
}
crychic.sendFriendPoke(qq.toString())
}
sendElements.push(SendMsgElementConstructor.poke("", ""))
}
}
break;
} }
} }
@@ -232,7 +248,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
message: "转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素" message: "转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素"
} }
} }
if (payload.message_type !== "private" && payload.group_id &&!(await getGroup(payload.group_id))) { if (payload.message_type !== "private" && payload.group_id && !(await getGroup(payload.group_id))) {
return { return {
valid: false, valid: false,
message: `${payload.group_id}不存在` message: `${payload.group_id}不存在`
@@ -261,6 +277,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
let isTempMsg = false; let isTempMsg = false;
let group: Group | undefined = undefined; let group: Group | undefined = undefined;
let friend: Friend | undefined = undefined;
const genGroupPeer = async () => { const genGroupPeer = async () => {
group = await getGroup(payload.group_id.toString()) group = await getGroup(payload.group_id.toString())
peer.chatType = ChatType.group peer.chatType = ChatType.group
@@ -269,7 +286,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
const genFriendPeer = () => { const genFriendPeer = () => {
const friend = friends.find(f => f.uin == payload.user_id.toString()) friend = friends.find(f => f.uin == payload.user_id.toString())
if (friend) { if (friend) {
// peer.name = friend.nickName // peer.name = friend.nickName
peer.peerUid = friend.uid peer.peerUid = friend.uid
@@ -318,7 +335,12 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
} }
// log("send msg:", peer, sendElements) // log("send msg:", peer, sendElements)
const {sendElements, deleteAfterSentFiles} = await createSendElements(messages, group) const {sendElements, deleteAfterSentFiles} = await createSendElements(messages, group || friend)
if (sendElements.length === 1){
if (sendElements[0] === null){
return {message_id: 0}
}
}
const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles) const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles)
deleteAfterSentFiles.map(f => fs.unlink(f, () => { deleteAfterSentFiles.map(f => fs.unlink(f, () => {
})); }));
@@ -478,8 +500,6 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement { private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement {
const musicJson = { const musicJson = {
app: 'com.tencent.structmsg', app: 'com.tencent.structmsg',

View File

@@ -116,7 +116,8 @@ export enum OB11MessageDataType {
markdown = "markdown", markdown = "markdown",
node = "node", // 合并转发消息节点 node = "node", // 合并转发消息节点
forward = "forward", // 合并转发消息,用于上报 forward = "forward", // 合并转发消息,用于上报
xml = "xml" xml = "xml",
poke = "poke"
} }
export interface OB11MessageMFace{ export interface OB11MessageMFace{
@@ -132,6 +133,14 @@ export interface OB11MessageText {
} }
} }
export interface OB11MessagePoke{
type: OB11MessageDataType.poke
data: {
qq?: number,
id?: number
}
}
interface OB11MessageFileBase { interface OB11MessageFileBase {
data: { data: {
thumb?: string; thumb?: string;
@@ -217,7 +226,7 @@ export type OB11MessageData =
OB11MessageFace | OB11MessageMFace | OB11MessageFace | OB11MessageMFace |
OB11MessageAt | OB11MessageReply | OB11MessageAt | OB11MessageReply |
OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo | OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo |
OB11MessageNode | OB11MessageCustomMusic | OB11MessageJson OB11MessageNode | OB11MessageCustomMusic | OB11MessageJson | OB11MessagePoke
export interface OB11PostSendMsg { export interface OB11PostSendMsg {
message_type?: "private" | "group" message_type?: "private" | "group"