mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
refactor
This commit is contained in:
parent
15b85f735d
commit
96aa5e264a
@ -17,7 +17,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@minatojs/driver-sqlite": "4.5.0",
|
||||
"@minatojs/driver-sqlite": "^4.6.0",
|
||||
"compressing": "^1.10.1",
|
||||
"cordis": "^3.18.1",
|
||||
"cors": "^2.8.5",
|
||||
@ -26,7 +26,7 @@
|
||||
"fast-xml-parser": "^4.5.0",
|
||||
"file-type": "^19.5.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"minato": "3.5.1",
|
||||
"minato": "^3.6.0",
|
||||
"protobufjs": "^7.4.0",
|
||||
"silk-wasm": "^3.6.1",
|
||||
"ws": "^8.18.0"
|
||||
|
@ -1,162 +0,0 @@
|
||||
import fsPromise from 'node:fs/promises'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import Database, { Tables } from 'minato'
|
||||
import SQLite from '@minatojs/driver-sqlite'
|
||||
import { Peer } from '@/ntqqapi/types'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { LimitedHashTable } from './table'
|
||||
import { DATA_DIR } from '../globalVars'
|
||||
import { FileCacheV2 } from '../types'
|
||||
|
||||
interface SQLiteTables extends Tables {
|
||||
message: {
|
||||
shortId: number
|
||||
msgId: string
|
||||
chatType: number
|
||||
peerUid: string
|
||||
}
|
||||
file_v2: FileCacheV2
|
||||
}
|
||||
|
||||
interface MsgIdAndPeerByShortId {
|
||||
MsgId: string
|
||||
Peer: Peer
|
||||
}
|
||||
|
||||
// forked from https://github.com/NapNeko/NapCatQQ/blob/6f6b258f22d7563f15d84e7172c4d4cbb547f47e/src/common/utils/MessageUnique.ts#L84
|
||||
class MessageUniqueWrapper {
|
||||
private msgDataMap: LimitedHashTable<string, number>
|
||||
private msgIdMap: LimitedHashTable<string, number>
|
||||
private db: Database<SQLiteTables> | undefined
|
||||
|
||||
constructor(maxMap: number = 1000) {
|
||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap)
|
||||
this.msgDataMap = new LimitedHashTable<string, number>(maxMap)
|
||||
}
|
||||
|
||||
async init(uin: string) {
|
||||
const dbDir = path.join(DATA_DIR, 'database')
|
||||
if (!fs.existsSync(dbDir)) {
|
||||
await fsPromise.mkdir(dbDir)
|
||||
}
|
||||
const database = new Database<SQLiteTables>()
|
||||
await database.connect(SQLite, {
|
||||
path: path.join(dbDir, `${uin}.db`)
|
||||
})
|
||||
database.extend('message', {
|
||||
shortId: 'integer(10)',
|
||||
chatType: 'unsigned',
|
||||
msgId: 'string(24)',
|
||||
peerUid: 'string(24)'
|
||||
}, {
|
||||
primary: 'shortId'
|
||||
})
|
||||
database.extend('file_v2', {
|
||||
fileName: 'string',
|
||||
fileSize: 'string',
|
||||
fileUuid: 'string(128)',
|
||||
msgId: 'string(24)',
|
||||
msgTime: 'unsigned(10)',
|
||||
peerUid: 'string(24)',
|
||||
chatType: 'unsigned',
|
||||
elementId: 'string(24)',
|
||||
elementType: 'unsigned',
|
||||
}, {
|
||||
primary: 'fileUuid',
|
||||
indexes: ['fileName']
|
||||
})
|
||||
this.db = database
|
||||
}
|
||||
|
||||
async getRecentMsgIds(Peer: Peer, size: number): Promise<string[]> {
|
||||
const heads = this.msgIdMap.getHeads(size)
|
||||
if (!heads) {
|
||||
return []
|
||||
}
|
||||
const data: (MsgIdAndPeerByShortId | undefined)[] = []
|
||||
for (const t of heads) {
|
||||
data.push(await MessageUnique.getMsgIdAndPeerByShortId(t.value))
|
||||
}
|
||||
const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid)
|
||||
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined)
|
||||
}
|
||||
|
||||
createMsg(peer: Peer, msgId: string): number {
|
||||
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`
|
||||
const hash = createHash('md5').update(key).digest()
|
||||
//设置第一个bit为0 保证shortId为正数
|
||||
hash[0] &= 0x7f
|
||||
const shortId = hash.readInt32BE(0)
|
||||
//减少性能损耗
|
||||
// const isExist = this.msgIdMap.getKey(shortId)
|
||||
// if (isExist && isExist === msgId) {
|
||||
// return shortId
|
||||
// }
|
||||
this.msgIdMap.set(msgId, shortId)
|
||||
this.msgDataMap.set(key, shortId)
|
||||
this.db?.upsert('message', [{
|
||||
msgId,
|
||||
shortId,
|
||||
chatType: peer.chatType,
|
||||
peerUid: peer.peerUid
|
||||
}], 'shortId').then()
|
||||
return shortId
|
||||
}
|
||||
|
||||
async getMsgIdAndPeerByShortId(shortId: number): Promise<MsgIdAndPeerByShortId | undefined> {
|
||||
const data = this.msgDataMap.getKey(shortId)
|
||||
if (data) {
|
||||
const [msgId, chatTypeStr, peerUid] = data.split('|')
|
||||
const peer: Peer = {
|
||||
chatType: parseInt(chatTypeStr),
|
||||
peerUid,
|
||||
guildId: '',
|
||||
}
|
||||
return { MsgId: msgId, Peer: peer }
|
||||
}
|
||||
const items = await this.db?.get('message', { shortId })
|
||||
if (items?.length) {
|
||||
const { msgId, chatType, peerUid } = items[0]
|
||||
return {
|
||||
MsgId: msgId,
|
||||
Peer: {
|
||||
chatType,
|
||||
peerUid,
|
||||
guildId: '',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getShortIdByMsgId(msgId: string): number | undefined {
|
||||
return this.msgIdMap.getValue(msgId)
|
||||
}
|
||||
|
||||
async getPeerByMsgId(msgId: string) {
|
||||
const shortId = this.msgIdMap.getValue(msgId)
|
||||
if (!shortId) return undefined
|
||||
return await this.getMsgIdAndPeerByShortId(shortId)
|
||||
}
|
||||
|
||||
resize(maxSize: number): void {
|
||||
this.msgIdMap.resize(maxSize)
|
||||
this.msgDataMap.resize(maxSize)
|
||||
}
|
||||
|
||||
addFileCache(data: FileCacheV2) {
|
||||
return this.db?.upsert('file_v2', [data], 'fileUuid')
|
||||
}
|
||||
|
||||
getFileCacheByName(fileName: string) {
|
||||
return this.db?.get('file_v2', { fileName }, {
|
||||
sort: { msgTime: 'desc' }
|
||||
})
|
||||
}
|
||||
|
||||
getFileCacheById(fileUuid: string) {
|
||||
return this.db?.get('file_v2', { fileUuid })
|
||||
}
|
||||
}
|
||||
|
||||
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper()
|
@ -1,5 +1,4 @@
|
||||
import path from 'node:path'
|
||||
import fs from 'node:fs'
|
||||
import Log from './log'
|
||||
import Core from '../ntqqapi/core'
|
||||
import OneBot11Adapter from '../onebot11/adapter'
|
||||
@ -34,6 +33,11 @@ import {
|
||||
NTQQWebApi,
|
||||
NTQQWindowApi
|
||||
} from '../ntqqapi/api'
|
||||
import { mkdir } from 'node:fs/promises'
|
||||
import { existsSync, mkdirSync } from 'node:fs'
|
||||
import Database from 'minato'
|
||||
import SQLiteDriver from '@minatojs/driver-sqlite'
|
||||
import Store from './store'
|
||||
|
||||
declare module 'cordis' {
|
||||
interface Events {
|
||||
@ -45,12 +49,12 @@ let mainWindow: BrowserWindow | null = null
|
||||
|
||||
// 加载插件时触发
|
||||
function onLoad() {
|
||||
if (!fs.existsSync(DATA_DIR)) {
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true })
|
||||
if (!existsSync(DATA_DIR)) {
|
||||
mkdirSync(DATA_DIR, { recursive: true })
|
||||
}
|
||||
|
||||
if (!fs.existsSync(LOG_DIR)) {
|
||||
fs.mkdirSync(LOG_DIR)
|
||||
if (!existsSync(LOG_DIR)) {
|
||||
mkdirSync(LOG_DIR)
|
||||
}
|
||||
|
||||
ipcMain.handle(CHANNEL_CHECK_VERSION, async () => {
|
||||
@ -151,8 +155,12 @@ function onLoad() {
|
||||
log('LLOneBot 开关设置为关闭,不启动LLOneBot')
|
||||
return
|
||||
}
|
||||
if (!fs.existsSync(TEMP_DIR)) {
|
||||
fs.mkdirSync(TEMP_DIR)
|
||||
if (!existsSync(TEMP_DIR)) {
|
||||
await mkdir(TEMP_DIR)
|
||||
}
|
||||
const dbDir = path.join(DATA_DIR, 'database')
|
||||
if (!existsSync(dbDir)) {
|
||||
await mkdir(dbDir)
|
||||
}
|
||||
const ctx = new Context()
|
||||
ctx.plugin(Log, {
|
||||
@ -179,6 +187,11 @@ function onLoad() {
|
||||
enableLocalFile2Url: config.enableLocalFile2Url!,
|
||||
ffmpeg: config.ffmpeg,
|
||||
})
|
||||
ctx.plugin(Database)
|
||||
ctx.plugin(SQLiteDriver, {
|
||||
path: path.join(dbDir, `${selfInfo.uin}.db`)
|
||||
})
|
||||
ctx.plugin(Store)
|
||||
ctx.start()
|
||||
ipcMain.on(CHANNEL_SET_CONFIG_CONFIRMED, (event, config: LLOBConfig) => {
|
||||
ctx.parallel('llonebot/config-updated', config)
|
||||
|
126
src/main/store.ts
Normal file
126
src/main/store.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import { Peer } from '@/ntqqapi/types'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { LimitedHashTable } from '@/common/utils/table'
|
||||
import { FileCacheV2 } from '@/common/types'
|
||||
import { Context, Service } from 'cordis'
|
||||
|
||||
declare module 'cordis' {
|
||||
interface Context {
|
||||
store: Store
|
||||
}
|
||||
interface Tables {
|
||||
message: {
|
||||
shortId: number
|
||||
msgId: string
|
||||
chatType: number
|
||||
peerUid: string
|
||||
}
|
||||
file_v2: FileCacheV2
|
||||
}
|
||||
}
|
||||
|
||||
interface MsgInfo {
|
||||
msgId: string
|
||||
peer: Peer
|
||||
}
|
||||
|
||||
export default class Store extends Service {
|
||||
static inject = ['database', 'model']
|
||||
private cache: LimitedHashTable<string, number>
|
||||
|
||||
constructor(protected ctx: Context) {
|
||||
super(ctx, 'store', true)
|
||||
this.cache = new LimitedHashTable<string, number>(1000)
|
||||
this.initDatabase()
|
||||
}
|
||||
|
||||
private async initDatabase() {
|
||||
this.ctx.model.extend('message', {
|
||||
shortId: 'integer(10)',
|
||||
chatType: 'unsigned',
|
||||
msgId: 'string(24)',
|
||||
peerUid: 'string(24)'
|
||||
}, {
|
||||
primary: 'shortId'
|
||||
})
|
||||
this.ctx.model.extend('file_v2', {
|
||||
fileName: 'string',
|
||||
fileSize: 'string',
|
||||
fileUuid: 'string(128)',
|
||||
msgId: 'string(24)',
|
||||
msgTime: 'unsigned(10)',
|
||||
peerUid: 'string(24)',
|
||||
chatType: 'unsigned',
|
||||
elementId: 'string(24)',
|
||||
elementType: 'unsigned',
|
||||
}, {
|
||||
primary: 'fileUuid',
|
||||
indexes: ['fileName']
|
||||
})
|
||||
}
|
||||
|
||||
createMsgShortId(peer: Peer, msgId: string): number {
|
||||
const cacheKey = `${msgId}|${peer.chatType}|${peer.peerUid}`
|
||||
const hash = createHash('md5').update(cacheKey).digest()
|
||||
hash[0] &= 0x7f //设置第一个bit为0 保证shortId为正数
|
||||
const shortId = hash.readInt32BE()
|
||||
this.cache.set(cacheKey, shortId)
|
||||
this.ctx.database.upsert('message', [{
|
||||
msgId,
|
||||
shortId,
|
||||
chatType: peer.chatType,
|
||||
peerUid: peer.peerUid
|
||||
}], 'shortId').then()
|
||||
return shortId
|
||||
}
|
||||
|
||||
async getMsgInfoByShortId(shortId: number): Promise<MsgInfo | undefined> {
|
||||
const data = this.cache.getKey(shortId)
|
||||
if (data) {
|
||||
const [msgId, chatTypeStr, peerUid] = data.split('|')
|
||||
return {
|
||||
msgId,
|
||||
peer: {
|
||||
chatType: +chatTypeStr,
|
||||
peerUid,
|
||||
guildId: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
const items = await this.ctx.database.get('message', { shortId })
|
||||
if (items?.length) {
|
||||
const { msgId, chatType, peerUid } = items[0]
|
||||
return {
|
||||
msgId,
|
||||
peer: {
|
||||
chatType,
|
||||
peerUid,
|
||||
guildId: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getShortIdByMsgId(msgId: string): Promise<number | undefined> {
|
||||
return (await this.ctx.database.get('message', { msgId }))[0]?.shortId
|
||||
}
|
||||
|
||||
getShortIdByMsgInfo(peer: Peer, msgId: string) {
|
||||
const cacheKey = `${msgId}|${peer.chatType}|${peer.peerUid}`
|
||||
return this.cache.getValue(cacheKey)
|
||||
}
|
||||
|
||||
addFileCache(data: FileCacheV2) {
|
||||
return this.ctx.database.upsert('file_v2', [data], 'fileUuid')
|
||||
}
|
||||
|
||||
getFileCacheByName(fileName: string) {
|
||||
return this.ctx.database.get('file_v2', { fileName }, {
|
||||
sort: { msgTime: 'desc' }
|
||||
})
|
||||
}
|
||||
|
||||
getFileCacheById(fileUuid: string) {
|
||||
return this.ctx.database.get('file_v2', { fileUuid })
|
||||
}
|
||||
}
|
@ -233,34 +233,48 @@ export class NTQQGroupApi extends Service {
|
||||
>(NTMethod.GROUP_AT_ALL_REMAIN_COUNT, [{ groupCode }, null])
|
||||
}
|
||||
|
||||
/** 27187 TODO */
|
||||
async removeGroupEssence(groupCode: string, msgId: string) {
|
||||
const session = getSession()
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
const data = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
const param = {
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
if (session) {
|
||||
const data = await session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
return session.getGroupService().removeGroupEssence({
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
})
|
||||
} else {
|
||||
const ntMsgApi = this.ctx.get('ntMsgApi')!
|
||||
const data = await ntMsgApi.getMsgHistory({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
return await invoke('nodeIKernelGroupService/removeGroupEssence', [{
|
||||
req: {
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
}
|
||||
}, null])
|
||||
}
|
||||
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||
return session?.getGroupService().removeGroupEssence(param)
|
||||
}
|
||||
|
||||
/** 27187 TODO */
|
||||
async addGroupEssence(groupCode: string, msgId: string) {
|
||||
const session = getSession()
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
const data = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
const param = {
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
if (session) {
|
||||
const data = await session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
return session.getGroupService().addGroupEssence({
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
})
|
||||
} else {
|
||||
const ntMsgApi = this.ctx.get('ntMsgApi')!
|
||||
const data = await ntMsgApi.getMsgHistory({ chatType: 2, guildId: '', peerUid: groupCode }, msgId, 1, false)
|
||||
return await invoke('nodeIKernelGroupService/addGroupEssence', [{
|
||||
req: {
|
||||
groupCode: groupCode,
|
||||
msgRandom: Number(data?.msgList[0].msgRandom),
|
||||
msgSeq: Number(data?.msgList[0].msgSeq)
|
||||
}
|
||||
}, null])
|
||||
}
|
||||
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||
return session?.getGroupService().addGroupEssence(param)
|
||||
}
|
||||
|
||||
async createGroupFileFolder(groupId: string, folderName: string) {
|
||||
@ -311,4 +325,14 @@ export class NTQQGroupApi extends Service {
|
||||
const ret = await invoke('nodeIKernelGroupService/getGroupRecommendContactArkJson', [{ groupCode }, null])
|
||||
return ret.arkJson
|
||||
}
|
||||
|
||||
async queryCachedEssenceMsg(groupCode: string, msgSeq = '0', msgRandom = '0') {
|
||||
return await invoke('nodeIKernelGroupService/queryCachedEssenceMsg', [{
|
||||
key: {
|
||||
groupCode,
|
||||
msgSeq: +msgSeq,
|
||||
msgRandom: +msgRandom
|
||||
}
|
||||
}, null])
|
||||
}
|
||||
}
|
||||
|
@ -102,18 +102,6 @@ export class NTQQUserApi extends Service {
|
||||
return await invoke('nodeIKernelTipOffService/getPskey', [{ domains, isForNewPCQQ: true }, null])
|
||||
}
|
||||
|
||||
genBkn(sKey: string) {
|
||||
sKey = sKey || ''
|
||||
let hash = 5381
|
||||
|
||||
for (let i = 0; i < sKey.length; i++) {
|
||||
const code = sKey.charCodeAt(i)
|
||||
hash = hash + (hash << 5) + code
|
||||
}
|
||||
|
||||
return (hash & 0x7fffffff).toString()
|
||||
}
|
||||
|
||||
async like(uid: string, count = 1) {
|
||||
const session = getSession()
|
||||
if (session) {
|
||||
|
@ -75,30 +75,6 @@ export interface GroupEssenceMsgRet {
|
||||
}
|
||||
}
|
||||
|
||||
interface SetGroupNoticeParams {
|
||||
groupCode: string
|
||||
content: string
|
||||
pinned: number
|
||||
type: number
|
||||
isShowEditCard: number
|
||||
tipWindowType: number
|
||||
confirmRequired: number
|
||||
picId: string
|
||||
imgWidth?: number
|
||||
imgHeight?: number
|
||||
}
|
||||
|
||||
interface SetGroupNoticeRet {
|
||||
ec: number
|
||||
em: string
|
||||
id: number
|
||||
ltsm: number
|
||||
new_fid: string
|
||||
read_only: number
|
||||
role: number
|
||||
srv_code: number
|
||||
}
|
||||
|
||||
export class NTQQWebApi extends Service {
|
||||
static inject = ['ntUserApi']
|
||||
|
||||
@ -274,65 +250,7 @@ export class NTQQWebApi extends Service {
|
||||
return honorInfo
|
||||
}
|
||||
|
||||
async setGroupNotice(params: SetGroupNoticeParams): Promise<SetGroupNoticeRet> {
|
||||
const cookieObject = await this.ctx.ntUserApi.getCookies('qun.qq.com')
|
||||
const settings = JSON.stringify({
|
||||
is_show_edit_card: params.isShowEditCard,
|
||||
tip_window_type: params.tipWindowType,
|
||||
confirm_required: params.confirmRequired
|
||||
})
|
||||
|
||||
return await RequestUtil.HttpGetJson<SetGroupNoticeRet>(
|
||||
`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?${new URLSearchParams({
|
||||
bkn: this.genBkn(cookieObject.skey),
|
||||
qid: params.groupCode,
|
||||
text: params.content,
|
||||
pinned: params.pinned.toString(),
|
||||
type: params.type.toString(),
|
||||
settings: settings,
|
||||
...(params.picId !== '' && {
|
||||
pic: params.picId,
|
||||
imgWidth: params.imgWidth?.toString(),
|
||||
imgHeight: params.imgHeight?.toString(),
|
||||
})
|
||||
})}`,
|
||||
'POST',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
)
|
||||
}
|
||||
|
||||
private cookieToString(cookieObject: Dict) {
|
||||
return Object.entries(cookieObject).map(([key, value]) => `${key}=${value}`).join('; ')
|
||||
}
|
||||
|
||||
async findGroupEssenceMsg(groupCode: string, msgSeq: number) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const res = await this.getGroupEssenceMsgList(groupCode, i, 50)
|
||||
if (!res) break
|
||||
const msg = res.data.msg_list.find(e => e.msg_seq === msgSeq)
|
||||
if (msg) return msg
|
||||
if (res.data.is_end) break
|
||||
}
|
||||
}
|
||||
|
||||
async getGroupEssenceMsgList(groupCode: string, pageStart: number, pageLimit: number) {
|
||||
const cookieObject = await this.ctx.ntUserApi.getCookies('qun.qq.com')
|
||||
try {
|
||||
const ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>(
|
||||
`https://qun.qq.com/cgi-bin/group_digest/digest_list?${new URLSearchParams({
|
||||
bkn: this.genBkn(cookieObject.skey),
|
||||
page_start: pageStart.toString(),
|
||||
page_limit: pageLimit.toString(),
|
||||
group_code: groupCode,
|
||||
})}`,
|
||||
'GET',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
)
|
||||
return ret.retcode === 0 ? ret : undefined
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import fs from 'node:fs'
|
||||
import { Service, Context } from 'cordis'
|
||||
import { registerCallHook, registerReceiveHook, ReceiveCmdS } from './hook'
|
||||
import { MessageUnique } from '../common/utils/messageUnique'
|
||||
import { Config as LLOBConfig } from '../common/types'
|
||||
import { llonebotError } from '../common/globalVars'
|
||||
import { isNumeric } from '../common/utils/misc'
|
||||
@ -45,7 +44,6 @@ class Core extends Service {
|
||||
|
||||
public start() {
|
||||
llonebotError.otherError = ''
|
||||
MessageUnique.init(selfInfo.uin)
|
||||
this.registerListener()
|
||||
this.ctx.logger.info(`LLOneBot/${version}`)
|
||||
this.ctx.on('llonebot/config-updated', input => {
|
||||
|
@ -72,14 +72,24 @@ export interface NodeIKernelGroupService {
|
||||
}
|
||||
}): Promise<unknown>
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
isEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||
isEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
queryCachedEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||
queryCachedEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<{
|
||||
items: {
|
||||
groupCode: string
|
||||
msgSeq: number
|
||||
msgRandom: number
|
||||
msgSenderUin: string
|
||||
msgSenderNick: string
|
||||
opType: number
|
||||
opUin: string
|
||||
opNick: string
|
||||
opTime: number
|
||||
grayTipSeq: string
|
||||
}[]
|
||||
}>
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
fetchGroupEssenceList(Req: { groupCode: string, pageStart: number, pageLimit: number }, Arg: unknown): Promise<unknown>
|
||||
fetchGroupEssenceList(req: { groupCode: string, pageStart: number, pageLimit: number }, arg: unknown): Promise<unknown>
|
||||
|
||||
//26702
|
||||
getAllMemberList(groupCode: string, forceFetch: boolean): Promise<{
|
||||
|
@ -2,7 +2,6 @@ import { BaseAction, Schema } from '../BaseAction'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { ActionName } from '../types'
|
||||
import { Peer, ElementType } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
export interface GetFilePayload {
|
||||
file: string // 文件名或者fileUuid
|
||||
@ -24,9 +23,9 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
|
||||
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
||||
const { enableLocalFile2Url } = this.adapter.config
|
||||
|
||||
let fileCache = await MessageUnique.getFileCacheById(payload.file)
|
||||
let fileCache = await this.ctx.store.getFileCacheById(payload.file)
|
||||
if (!fileCache?.length) {
|
||||
fileCache = await MessageUnique.getFileCacheByName(payload.file)
|
||||
fileCache = await this.ctx.store.getFileCacheByName(payload.file)
|
||||
}
|
||||
|
||||
if (fileCache?.length) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -13,13 +12,13 @@ export class DelEssenceMsg extends BaseAction<Payload, unknown> {
|
||||
})
|
||||
|
||||
protected async _handle(payload: Payload) {
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
return await this.ctx.ntGroupApi.removeGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId,
|
||||
msg.peer.peerUid,
|
||||
msg.msgId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { BaseAction, Schema } from '../BaseAction'
|
||||
import { OB11ForwardMessage } from '../../types'
|
||||
import { OB11Entities } from '../../entities'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { filterNullable } from '@/common/utils/misc'
|
||||
|
||||
interface Payload {
|
||||
@ -26,12 +25,12 @@ export class GetForwardMsg extends BaseAction<Payload, Response> {
|
||||
if (!msgId) {
|
||||
throw Error('message_id不能为空')
|
||||
}
|
||||
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId)
|
||||
const rootMsg = await MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || +msgId)
|
||||
const rootMsgId = await this.ctx.store.getShortIdByMsgId(msgId)
|
||||
const rootMsg = await this.ctx.store.getMsgInfoByShortId(rootMsgId || +msgId)
|
||||
if (!rootMsg) {
|
||||
throw Error('msg not found')
|
||||
}
|
||||
const data = await this.ctx.ntMsgApi.getMultiMsg(rootMsg.Peer, rootMsg.MsgId, rootMsg.MsgId)
|
||||
const data = await this.ctx.ntMsgApi.getMultiMsg(rootMsg.peer, rootMsg.msgId, rootMsg.msgId)
|
||||
if (data?.result !== 0) {
|
||||
throw Error('找不到相关的聊天记录' + data?.errMsg)
|
||||
}
|
||||
@ -40,7 +39,7 @@ export class GetForwardMsg extends BaseAction<Payload, Response> {
|
||||
msgList.map(async (msg) => {
|
||||
const resMsg = await OB11Entities.message(this.ctx, msg)
|
||||
if (!resMsg) return
|
||||
resMsg.message_id = MessageUnique.createMsg({
|
||||
resMsg.message_id = this.ctx.store.createMsgShortId({
|
||||
chatType: msg.chatType,
|
||||
peerUid: msg.peerUid,
|
||||
}, msg.msgId)
|
||||
|
@ -4,7 +4,6 @@ import { ActionName } from '../types'
|
||||
import { ChatType } from '@/ntqqapi/types'
|
||||
import { OB11Entities } from '../../entities'
|
||||
import { RawMessage } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { filterNullable } from '@/common/utils/misc'
|
||||
|
||||
interface Payload {
|
||||
@ -35,7 +34,7 @@ export class GetGroupMsgHistory extends BaseAction<Payload, Response> {
|
||||
if (!payload.message_seq) {
|
||||
msgList = (await this.ctx.ntMsgApi.getAioFirstViewLatestMsgs(peer, +count)).msgList
|
||||
} else {
|
||||
const startMsgId = (await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq))?.MsgId
|
||||
const startMsgId = (await this.ctx.store.getMsgInfoByShortId(+payload.message_seq))?.msgId
|
||||
if (!startMsgId) throw new Error(`消息${payload.message_seq}不存在`)
|
||||
msgList = (await this.ctx.ntMsgApi.getMsgHistory(peer, startMsgId, +count)).msgList
|
||||
}
|
||||
@ -43,7 +42,7 @@ export class GetGroupMsgHistory extends BaseAction<Payload, Response> {
|
||||
if (reverseOrder) msgList.reverse()
|
||||
await Promise.all(
|
||||
msgList.map(async msg => {
|
||||
msg.msgShortId = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
|
||||
msg.msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
|
||||
})
|
||||
)
|
||||
const ob11MsgList = await Promise.all(msgList.map((msg) => OB11Entities.message(this.ctx, msg)))
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -13,11 +12,11 @@ export class MarkMsgAsRead extends BaseAction<Payload, null> {
|
||||
})
|
||||
|
||||
protected async _handle(payload: Payload) {
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
await this.ctx.ntMsgApi.setMsgRead(msg.Peer)
|
||||
await this.ctx.ntMsgApi.setMsgRead(msg.peer)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import { ActionName } from '../types'
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { Peer } from '@/ntqqapi/types/msg'
|
||||
import { ChatType, ElementType, RawMessage, SendMessageElement } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { selfInfo } from '@/common/globalVars'
|
||||
import { convertMessage2List, createSendElements, sendMsg, createPeer, CreatePeerMode } from '../../helper/createMessage'
|
||||
|
||||
@ -57,7 +56,7 @@ export class SendForwardMsg extends BaseAction<Payload, Response> {
|
||||
peerUid: selfInfo.uid
|
||||
}
|
||||
const nodeMsg = await this.ctx.ntMsgApi.sendMsg(peer, sendElements)
|
||||
await this.ctx.sleep(400)
|
||||
await this.ctx.sleep(300)
|
||||
return nodeMsg
|
||||
} catch (e) {
|
||||
this.ctx.logger.warn(e, '克隆转发消息失败,将忽略本条消息', msg)
|
||||
@ -70,19 +69,19 @@ export class SendForwardMsg extends BaseAction<Payload, Response> {
|
||||
chatType: ChatType.friend,
|
||||
peerUid: selfInfo.uid,
|
||||
}
|
||||
let nodeMsgIds: string[] = []
|
||||
const nodeMsgIds: { msgId: string, peer: Peer }[] = []
|
||||
// 先判断一遍是不是id和自定义混用
|
||||
for (const messageNode of messageNodes) {
|
||||
// 一个node表示一个人的消息
|
||||
const nodeId = messageNode.data.id
|
||||
// 有nodeId表示一个子转发消息卡片
|
||||
if (nodeId) {
|
||||
const nodeMsg = await MessageUnique.getMsgIdAndPeerByShortId(+nodeId) || await MessageUnique.getPeerByMsgId(nodeId)
|
||||
const nodeMsg = await this.ctx.store.getMsgInfoByShortId(+nodeId)
|
||||
if (!nodeMsg) {
|
||||
this.ctx.logger.warn('转发消息失败,未找到消息', nodeId)
|
||||
continue
|
||||
}
|
||||
nodeMsgIds.push(nodeMsg.MsgId)
|
||||
nodeMsgIds.push(nodeMsg)
|
||||
}
|
||||
else {
|
||||
// 自定义的消息
|
||||
@ -111,17 +110,16 @@ export class SendForwardMsg extends BaseAction<Payload, Response> {
|
||||
else {
|
||||
sendElementsSplit[splitIndex].push(ele)
|
||||
}
|
||||
this.ctx.logger.info(sendElementsSplit)
|
||||
}
|
||||
// log("分割后的转发节点", sendElementsSplit)
|
||||
this.ctx.logger.info('分割后的转发节点', sendElementsSplit)
|
||||
for (const eles of sendElementsSplit) {
|
||||
const nodeMsg = await sendMsg(this.ctx, selfPeer, eles, [])
|
||||
if (!nodeMsg) {
|
||||
this.ctx.logger.warn('转发节点生成失败', eles)
|
||||
continue
|
||||
}
|
||||
nodeMsgIds.push(nodeMsg.msgId)
|
||||
await this.ctx.sleep(400)
|
||||
nodeMsgIds.push({ msgId: nodeMsg.msgId, peer: selfPeer })
|
||||
await this.ctx.sleep(300)
|
||||
}
|
||||
deleteAfterSentFiles.map(path => unlink(path))
|
||||
} catch (e) {
|
||||
@ -132,31 +130,34 @@ export class SendForwardMsg extends BaseAction<Payload, Response> {
|
||||
|
||||
// 检查srcPeer是否一致,不一致则需要克隆成自己的消息, 让所有srcPeer都变成自己的,使其保持一致才能够转发
|
||||
const nodeMsgArray: RawMessage[] = []
|
||||
let srcPeer: Peer | null = null
|
||||
let srcPeer: Peer
|
||||
let needSendSelf = false
|
||||
for (const msgId of nodeMsgIds) {
|
||||
const nodeMsgPeer = await MessageUnique.getPeerByMsgId(msgId)
|
||||
if (nodeMsgPeer) {
|
||||
const nodeMsg = (await this.ctx.ntMsgApi.getMsgsByMsgId(nodeMsgPeer.Peer, [msgId])).msgList[0]
|
||||
srcPeer = srcPeer ?? { chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid }
|
||||
if (srcPeer.peerUid !== nodeMsg.peerUid) {
|
||||
needSendSelf = true
|
||||
}
|
||||
nodeMsgArray.push(nodeMsg)
|
||||
for (const { msgId, peer } of nodeMsgIds) {
|
||||
const nodeMsg = (await this.ctx.ntMsgApi.getMsgsByMsgId(peer, [msgId])).msgList[0]
|
||||
srcPeer ??= { chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid }
|
||||
if (srcPeer.peerUid !== nodeMsg.peerUid) {
|
||||
needSendSelf = true
|
||||
}
|
||||
nodeMsgArray.push(nodeMsg)
|
||||
}
|
||||
nodeMsgIds = nodeMsgArray.map((msg) => msg.msgId)
|
||||
let retMsgIds: string[] = []
|
||||
if (needSendSelf) {
|
||||
for (const msg of nodeMsgArray) {
|
||||
if (msg.peerUid === selfPeer.peerUid) continue
|
||||
await this.cloneMsg(msg)
|
||||
if (msg.peerUid === selfPeer.peerUid) {
|
||||
retMsgIds.push(msg.msgId)
|
||||
continue
|
||||
}
|
||||
const clonedMsg = await this.cloneMsg(msg)
|
||||
if (clonedMsg) retMsgIds.push(clonedMsg.msgId)
|
||||
}
|
||||
} else {
|
||||
retMsgIds = nodeMsgArray.map(msg => msg.msgId)
|
||||
}
|
||||
if (nodeMsgIds.length === 0) {
|
||||
if (retMsgIds.length === 0) {
|
||||
throw Error('转发消息失败,节点为空')
|
||||
}
|
||||
const returnMsg = await this.ctx.ntMsgApi.multiForwardMsg(srcPeer!, destPeer, nodeMsgIds)
|
||||
returnMsg.msgShortId = MessageUnique.createMsg(destPeer, returnMsg.msgId)
|
||||
const returnMsg = await this.ctx.ntMsgApi.multiForwardMsg(srcPeer!, destPeer, retMsgIds)
|
||||
returnMsg.msgShortId = this.ctx.store.createMsgShortId(destPeer, returnMsg.msgId)
|
||||
return returnMsg
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseAction } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -13,13 +12,13 @@ export class SetEssenceMsg extends BaseAction<Payload, unknown> {
|
||||
if (!payload.message_id) {
|
||||
throw Error('message_id不能为空')
|
||||
}
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
return await this.ctx.ntGroupApi.addGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId
|
||||
msg.peer.peerUid,
|
||||
msg.msgId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { Dict } from 'cosmokit'
|
||||
|
||||
interface Payload {
|
||||
@ -20,9 +19,9 @@ export class FetchEmojiLike extends BaseAction<Payload, Dict> {
|
||||
})
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const msgInfo = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msgInfo = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msgInfo) throw new Error('消息不存在')
|
||||
const { msgSeq } = (await this.ctx.ntMsgApi.getMsgsByMsgId(msgInfo.Peer, [msgInfo.MsgId])).msgList[0]
|
||||
return await this.ctx.ntMsgApi.getMsgEmojiLikesList(msgInfo.Peer, msgSeq, payload.emojiId, payload.emojiType, +payload.count)
|
||||
const { msgSeq } = (await this.ctx.ntMsgApi.getMsgsByMsgId(msgInfo.peer, [msgInfo.msgId])).msgList[0]
|
||||
return await this.ctx.ntMsgApi.getMsgEmojiLikesList(msgInfo.peer, msgSeq, payload.emojiId, payload.emojiType, +payload.count)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { BaseAction, Schema } from '../BaseAction'
|
||||
import { OB11Message } from '@/onebot11/types'
|
||||
import { ActionName } from '../types'
|
||||
import { ChatType, RawMessage } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { OB11Entities } from '@/onebot11/entities'
|
||||
import { filterNullable } from '@/common/utils/misc'
|
||||
|
||||
@ -32,9 +31,9 @@ export class GetFriendMsgHistory extends BaseAction<Payload, Response> {
|
||||
const startMsgId = payload.message_seq ?? payload.message_id
|
||||
let msgList: RawMessage[]
|
||||
if (startMsgId) {
|
||||
const msgInfo = await MessageUnique.getMsgIdAndPeerByShortId(+startMsgId)
|
||||
const msgInfo = await this.ctx.store.getMsgInfoByShortId(+startMsgId)
|
||||
if (!msgInfo) throw new Error(`消息${startMsgId}不存在`)
|
||||
msgList = (await this.ctx.ntMsgApi.getMsgHistory(msgInfo.Peer, msgInfo.MsgId, +payload.count)).msgList
|
||||
msgList = (await this.ctx.ntMsgApi.getMsgHistory(msgInfo.peer, msgInfo.msgId, +payload.count)).msgList
|
||||
} else {
|
||||
const uid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString())
|
||||
if (!uid) throw new Error(`记录${payload.user_id}不存在`)
|
||||
@ -45,7 +44,7 @@ export class GetFriendMsgHistory extends BaseAction<Payload, Response> {
|
||||
if (msgList.length === 0) throw new Error('未找到消息')
|
||||
if (payload.reverseOrder) msgList.reverse()
|
||||
msgList.map(msg => {
|
||||
msg.msgShortId = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
|
||||
msg.msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
|
||||
})
|
||||
const ob11MsgList = await Promise.all(msgList.map(msg => OB11Entities.message(this.ctx, msg)))
|
||||
return { messages: filterNullable(ob11MsgList) }
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ActionName } from '../types'
|
||||
import { BaseAction } from '../BaseAction'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -13,11 +12,11 @@ class DeleteMsg extends BaseAction<Payload, void> {
|
||||
if (!payload.message_id) {
|
||||
throw new Error('参数message_id不能为空')
|
||||
}
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error(`消息${payload.message_id}不存在`)
|
||||
}
|
||||
const data = await this.ctx.ntMsgApi.recallMsg(msg.Peer, [msg.MsgId])
|
||||
const data = await this.ctx.ntMsgApi.recallMsg(msg.peer, [msg.msgId])
|
||||
if (data.result !== 0) {
|
||||
this.ctx.logger.error('delete_msg', payload.message_id, data)
|
||||
throw new Error(`消息撤回失败`)
|
||||
|
@ -2,7 +2,6 @@ import { BaseAction } from '../BaseAction'
|
||||
import { ChatType } from '@/ntqqapi/types'
|
||||
import { ActionName } from '../types'
|
||||
import { Peer } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -26,12 +25,12 @@ abstract class ForwardSingleMsg extends BaseAction<Payload, null> {
|
||||
if (!payload.message_id) {
|
||||
throw Error('message_id不能为空')
|
||||
}
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error(`无法找到消息${payload.message_id}`)
|
||||
}
|
||||
const peer = await this.getTargetPeer(payload)
|
||||
const ret = await this.ctx.ntMsgApi.forwardMsg(msg.Peer, peer, [msg.MsgId])
|
||||
const ret = await this.ctx.ntMsgApi.forwardMsg(msg.peer, peer, [msg.msgId])
|
||||
if (ret.result !== 0) {
|
||||
throw new Error(`转发消息失败 ${ret.errMsg}`)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { BaseAction } from '../BaseAction'
|
||||
import { OB11Message } from '../../types'
|
||||
import { OB11Entities } from '../../entities'
|
||||
import { ActionName } from '../types'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
export interface PayloadType {
|
||||
message_id: number | string
|
||||
@ -17,22 +16,21 @@ class GetMsg extends BaseAction<PayloadType, OB11Message> {
|
||||
if (!payload.message_id) {
|
||||
throw new Error('参数message_id不能为空')
|
||||
}
|
||||
const msgShortId = MessageUnique.getShortIdByMsgId(payload.message_id.toString())
|
||||
const msgIdWithPeer = await MessageUnique.getMsgIdAndPeerByShortId(msgShortId || +payload.message_id)
|
||||
if (!msgIdWithPeer) {
|
||||
const msgInfo = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msgInfo) {
|
||||
throw new Error('消息不存在')
|
||||
}
|
||||
const peer = {
|
||||
guildId: '',
|
||||
peerUid: msgIdWithPeer.Peer.peerUid,
|
||||
chatType: msgIdWithPeer.Peer.chatType
|
||||
peerUid: msgInfo.peer.peerUid,
|
||||
chatType: msgInfo.peer.chatType
|
||||
}
|
||||
const msg = this.adapter.getMsgCache(msgIdWithPeer.MsgId) ?? (await this.ctx.ntMsgApi.getMsgsByMsgId(peer, [msgIdWithPeer.MsgId])).msgList[0]
|
||||
const msg = this.adapter.getMsgCache(msgInfo.msgId) ?? (await this.ctx.ntMsgApi.getMsgsByMsgId(peer, [msgInfo.msgId])).msgList[0]
|
||||
const retMsg = await OB11Entities.message(this.ctx, msg)
|
||||
if (!retMsg) {
|
||||
throw new Error('消息为空')
|
||||
}
|
||||
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgId)!
|
||||
retMsg.message_id = this.ctx.store.createMsgShortId(peer, msg.msgId)
|
||||
retMsg.message_seq = retMsg.message_id
|
||||
retMsg.real_id = retMsg.message_id
|
||||
return retMsg
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ActionName } from '../types'
|
||||
import { BaseAction } from '../BaseAction'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
|
||||
interface Payload {
|
||||
message_id: number | string
|
||||
@ -14,19 +13,19 @@ export class SetMsgEmojiLike extends BaseAction<Payload, unknown> {
|
||||
if (!payload.message_id) {
|
||||
throw Error('message_id不能为空')
|
||||
}
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)
|
||||
const msg = await this.ctx.store.getMsgInfoByShortId(+payload.message_id)
|
||||
if (!msg) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
if (!payload.emoji_id) {
|
||||
throw new Error('emojiId not found')
|
||||
}
|
||||
const msgData = (await this.ctx.ntMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId])).msgList
|
||||
const msgData = (await this.ctx.ntMsgApi.getMsgsByMsgId(msg.peer, [msg.msgId])).msgList
|
||||
if (!msgData || msgData.length == 0 || !msgData[0].msgSeq) {
|
||||
throw new Error('find msg by msgid error')
|
||||
}
|
||||
return await this.ctx.ntMsgApi.setEmojiLike(
|
||||
msg.Peer,
|
||||
msg.peer,
|
||||
msgData[0].msgSeq,
|
||||
payload.emoji_id.toString(),
|
||||
true
|
||||
|
@ -10,15 +10,12 @@ export default class SendLike extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.SendLike
|
||||
|
||||
protected async _handle(payload: Payload): Promise<null> {
|
||||
try {
|
||||
const qq = payload.user_id.toString()
|
||||
const uid: string = await this.ctx.ntUserApi.getUidByUin(qq) || ''
|
||||
const result = await this.ctx.ntUserApi.like(uid, +payload.times || 1)
|
||||
if (result?.result !== 0) {
|
||||
throw Error(result?.errMsg)
|
||||
}
|
||||
} catch (e) {
|
||||
throw `点赞失败 ${e}`
|
||||
const uin = payload.user_id.toString()
|
||||
const uid = await this.ctx.ntUserApi.getUidByUin(uin)
|
||||
if (!uid) throw new Error('无法获取用户信息')
|
||||
const result = await this.ctx.ntUserApi.like(uid, +payload.times || 1)
|
||||
if (result.result !== 0) {
|
||||
throw new Error(result.errMsg)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import {
|
||||
} from '../ntqqapi/types'
|
||||
import { OB11GroupRequestEvent } from './event/request/OB11GroupRequest'
|
||||
import { OB11FriendRequestEvent } from './event/request/OB11FriendRequest'
|
||||
import { MessageUnique } from '../common/utils/messageUnique'
|
||||
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'
|
||||
import { selfInfo } from '../common/globalVars'
|
||||
import { OB11Config, Config as LLOBConfig } from '../common/types'
|
||||
@ -37,7 +36,7 @@ declare module 'cordis' {
|
||||
}
|
||||
|
||||
class OneBot11Adapter extends Service {
|
||||
static inject = ['ntMsgApi', 'ntFileApi', 'ntFileCacheApi', 'ntFriendApi', 'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi']
|
||||
static inject = ['ntMsgApi', 'ntFileApi', 'ntFileCacheApi', 'ntFriendApi', 'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi', 'store']
|
||||
|
||||
public messages: Map<string, RawMessage> = new Map()
|
||||
public startTime = 0
|
||||
@ -190,7 +189,7 @@ class OneBot11Adapter extends Service {
|
||||
chatType: message.chatType,
|
||||
peerUid: message.peerUid
|
||||
}
|
||||
message.msgShortId = MessageUnique.createMsg(peer, message.msgId)
|
||||
message.msgShortId = this.ctx.store.createMsgShortId(peer, message.msgId)
|
||||
this.addMsgCache(message)
|
||||
|
||||
OB11Entities.message(this.ctx, message)
|
||||
@ -227,7 +226,11 @@ class OneBot11Adapter extends Service {
|
||||
}
|
||||
|
||||
private handleRecallMsg(message: RawMessage) {
|
||||
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId)
|
||||
const peer = {
|
||||
peerUid: message.peerUid,
|
||||
chatType: message.chatType
|
||||
}
|
||||
const oriMessageId = this.ctx.store.getShortIdByMsgInfo(peer, message.msgId)
|
||||
if (!oriMessageId) {
|
||||
return
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import {
|
||||
} from '../ntqqapi/types'
|
||||
import { EventType } from './event/OB11BaseEvent'
|
||||
import { encodeCQCode } from './cqcode'
|
||||
import { MessageUnique } from '../common/utils/messageUnique'
|
||||
import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'
|
||||
import { OB11GroupBanEvent } from './event/notice/OB11GroupBanEvent'
|
||||
import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNoticeEvent'
|
||||
@ -178,7 +177,7 @@ export namespace OB11Entities {
|
||||
messageSegment = {
|
||||
type: OB11MessageDataType.reply,
|
||||
data: {
|
||||
id: MessageUnique.createMsg(peer, replyMsg ? replyMsg.msgId : records.msgId).toString()
|
||||
id: ctx.store.createMsgShortId(peer, replyMsg ? replyMsg.msgId : records.msgId).toString()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@ -198,7 +197,7 @@ export namespace OB11Entities {
|
||||
file_size: fileSize,
|
||||
}
|
||||
}
|
||||
MessageUnique.addFileCache({
|
||||
ctx.store.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
msgTime: +msg.msgTime,
|
||||
@ -226,7 +225,7 @@ export namespace OB11Entities {
|
||||
file_size: fileSize,
|
||||
}
|
||||
}
|
||||
MessageUnique.addFileCache({
|
||||
ctx.store.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
msgTime: +msg.msgTime,
|
||||
@ -251,7 +250,7 @@ export namespace OB11Entities {
|
||||
file_size: fileSize,
|
||||
}
|
||||
}
|
||||
MessageUnique.addFileCache({
|
||||
ctx.store.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
msgTime: +msg.msgTime,
|
||||
@ -275,7 +274,7 @@ export namespace OB11Entities {
|
||||
file_size: fileSize,
|
||||
}
|
||||
}
|
||||
MessageUnique.addFileCache({
|
||||
ctx.store.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
msgTime: +msg.msgTime,
|
||||
@ -530,7 +529,7 @@ export namespace OB11Entities {
|
||||
if (!replyMsgList?.length) {
|
||||
return
|
||||
}
|
||||
const shortId = MessageUnique.getShortIdByMsgId(replyMsgList[0].msgId)
|
||||
const shortId = ctx.store.getShortIdByMsgInfo(peer, replyMsgList[0].msgId)
|
||||
return new OB11GroupMsgEmojiLikeEvent(
|
||||
parseInt(msg.peerUid),
|
||||
parseInt(senderUin),
|
||||
@ -581,27 +580,28 @@ export namespace OB11Entities {
|
||||
)
|
||||
}
|
||||
}
|
||||
if (grayTipElement.jsonGrayTipElement?.busiId === '2401') {
|
||||
if (grayTipElement.jsonGrayTipElement?.busiId === '2401' && json.items[2]) {
|
||||
ctx.logger.info('收到群精华消息', json)
|
||||
const searchParams = new URL(json.items[0].jp).searchParams
|
||||
const msgSeq = searchParams.get('msgSeq')
|
||||
const groupCode = searchParams.get('groupCode')
|
||||
if (!groupCode || !msgSeq) return
|
||||
const searchParams = new URL(json.items[2].jp).searchParams
|
||||
const msgSeq = searchParams.get('seq')
|
||||
const groupCode = searchParams.get('gc')
|
||||
const msgRandom = searchParams.get('random')
|
||||
if (!groupCode || !msgSeq || !msgRandom) return
|
||||
const peer = {
|
||||
guildId: '',
|
||||
chatType: ChatType.group,
|
||||
peerUid: groupCode
|
||||
}
|
||||
const essence = await ctx.ntWebApi.findGroupEssenceMsg(groupCode, +msgSeq)
|
||||
if (!essence) return
|
||||
const { msgList } = await ctx.ntMsgApi.queryMsgsWithFilterExBySeq(peer, msgSeq, String(essence.sender_time))
|
||||
const essence = await ctx.ntGroupApi.queryCachedEssenceMsg(groupCode, msgSeq, msgRandom)
|
||||
const { msgList } = await ctx.ntMsgApi.queryMsgsWithFilterExBySeq(peer, msgSeq, '0')
|
||||
const sourceMsg = msgList.find(e => e.msgRandom === msgRandom)
|
||||
if (!sourceMsg) return
|
||||
return new OB11GroupEssenceEvent(
|
||||
parseInt(msg.peerUid),
|
||||
MessageUnique.getShortIdByMsgId(msgList[0].msgId)!,
|
||||
parseInt(msgList[0].senderUin),
|
||||
parseInt(essence.add_digest_uin),
|
||||
ctx.store.getShortIdByMsgInfo(peer, sourceMsg.msgId)!,
|
||||
parseInt(essence.items[0]?.msgSenderUin ?? sourceMsg.senderUin),
|
||||
parseInt(essence.items[0]?.opUin ?? '0'),
|
||||
)
|
||||
// 获取MsgSeq+Peer可获取具体消息
|
||||
}
|
||||
if (grayTipElement.jsonGrayTipElement?.busiId === '2407') {
|
||||
const memberUin = json.items[1].param[0]
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
import { decodeCQCode } from '../cqcode'
|
||||
import { Peer } from '@/ntqqapi/types/msg'
|
||||
import { SendElementEntities } from '@/ntqqapi/entities'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { selfInfo } from '@/common/globalVars'
|
||||
import { uri2local } from '@/common/utils'
|
||||
import { Context } from 'cordis'
|
||||
@ -87,14 +86,14 @@ export async function createSendElements(
|
||||
break
|
||||
case OB11MessageDataType.reply: {
|
||||
if (sendMsg.data?.id) {
|
||||
const replyMsgId = await MessageUnique.getMsgIdAndPeerByShortId(+sendMsg.data.id)
|
||||
const replyMsgId = await ctx.store.getMsgInfoByShortId(+sendMsg.data.id)
|
||||
if (!replyMsgId) {
|
||||
ctx.logger.warn('回复消息不存在', replyMsgId)
|
||||
continue
|
||||
}
|
||||
const replyMsg = (await ctx.ntMsgApi.getMsgsByMsgId(
|
||||
replyMsgId.Peer,
|
||||
[replyMsgId.MsgId!]
|
||||
replyMsgId.peer,
|
||||
[replyMsgId.msgId!]
|
||||
)).msgList[0]
|
||||
if (replyMsg) {
|
||||
sendElements.push(
|
||||
@ -277,7 +276,7 @@ export async function sendMsg(
|
||||
//log('设置消息超时时间', timeout)
|
||||
const returnMsg = await ctx.ntMsgApi.sendMsg(peer, sendElements, timeout)
|
||||
if (returnMsg) {
|
||||
returnMsg.msgShortId = MessageUnique.createMsg(peer, returnMsg.msgId)
|
||||
returnMsg.msgShortId = ctx.store.createMsgShortId(peer, returnMsg.msgId)
|
||||
ctx.logger.info('消息发送', returnMsg.msgShortId)
|
||||
deleteAfterSentFiles.map(path => fsPromise.unlink(path))
|
||||
return returnMsg
|
||||
|
@ -3,7 +3,6 @@ import { OB11FriendRequestEvent } from '../event/request/OB11FriendRequest'
|
||||
import { OB11GroupRequestEvent } from '../event/request/OB11GroupRequest'
|
||||
import { GroupRequestOperateTypes } from '@/ntqqapi/types'
|
||||
import { convertMessage2List, createSendElements, sendMsg, createPeer, CreatePeerMode } from '../helper/createMessage'
|
||||
import { MessageUnique } from '@/common/utils/messageUnique'
|
||||
import { isNullable } from 'cosmokit'
|
||||
import { Context } from 'cordis'
|
||||
|
||||
@ -88,18 +87,18 @@ async function handleMsg(ctx: Context, msg: OB11Message, quickAction: QuickOpera
|
||||
}
|
||||
if (msg.message_type === 'group') {
|
||||
const groupMsgQuickAction = quickAction as QuickOperationGroupMessage
|
||||
const rawMessage = await MessageUnique.getMsgIdAndPeerByShortId(+(msg.message_id ?? 0))
|
||||
const rawMessage = await ctx.store.getMsgInfoByShortId(+(msg.message_id ?? 0))
|
||||
if (!rawMessage) return
|
||||
// handle group msg
|
||||
if (groupMsgQuickAction.delete) {
|
||||
ctx.ntMsgApi.recallMsg(peer, [rawMessage.MsgId]).catch(e => ctx.logger.error(e))
|
||||
ctx.ntMsgApi.recallMsg(peer, [rawMessage.msgId]).catch(e => ctx.logger.error(e))
|
||||
}
|
||||
if (groupMsgQuickAction.kick) {
|
||||
const { msgList } = await ctx.ntMsgApi.getMsgsByMsgId(peer, [rawMessage.MsgId])
|
||||
const { msgList } = await ctx.ntMsgApi.getMsgsByMsgId(peer, [rawMessage.msgId])
|
||||
ctx.ntGroupApi.kickMember(peer.peerUid, [msgList[0].senderUid]).catch(e => ctx.logger.error(e))
|
||||
}
|
||||
if (groupMsgQuickAction.ban) {
|
||||
const { msgList } = await ctx.ntMsgApi.getMsgsByMsgId(peer, [rawMessage.MsgId])
|
||||
const { msgList } = await ctx.ntMsgApi.getMsgsByMsgId(peer, [rawMessage.msgId])
|
||||
ctx.ntGroupApi.banMember(peer.peerUid, [
|
||||
{
|
||||
uid: msgList[0].senderUid,
|
||||
|
Loading…
x
Reference in New Issue
Block a user