UNPKG

koishi-plugin-adapter-iirose

Version:
544 lines (487 loc) 16.5 kB
import { h, Universal } from 'koishi'; import { comparePassword } from '../utils/password'; import { MessageType } from '.'; import { IIROSE_Bot } from '../bot/bot'; import { clearMsg } from './clearMsg'; import { parseAvatar } from '../utils/utils'; export const decoderMessage = async (obj: MessageType, bot: IIROSE_Bot) => { // 定义会话列表 for (const key in obj) { switch (key) { case 'publicMessage': { if (!obj.publicMessage) return; obj.publicMessage.message = await clearMsg(obj.publicMessage.message, bot); const data = obj.publicMessage; // 引用 let quotePayload: Universal.Message | undefined = undefined; if (data.replyMessage && data.replyMessage.length > 0) { const quoteInfo = data.replyMessage[0]; const processedQuoteContent = await clearMsg(quoteInfo.message, bot); const quotedSession = bot.sessionCache.findQuote({ username: quoteInfo.username, content: processedQuoteContent, }); if (quotedSession) { quotePayload = { messageId: quotedSession.event.message.id, content: quotedSession.content, timestamp: quotedSession.timestamp, elements: quotedSession.elements, user: { id: quotedSession.author.id, name: quotedSession.author.name, avatar: parseAvatar(quotedSession.author.avatar), nickname: quotedSession.author.nickname, }, channel: { id: quotedSession.channelId, type: 0, }, guild: { id: quotedSession.guildId, }, }; } } let uid = bot.ctx.config.uid; let guildId = bot.ctx.config.roomId; if (bot.ctx.config.smStart && comparePassword(bot.ctx.config.smPassword, 'ec3a4ac482b483ac02d26e440aa0a948d309c822')) { uid = bot.ctx.config.smUid; guildId = bot.ctx.config.smRoom; } const event = { type: 'message', platform: 'iirose', selfId: uid, timestamp: Number(data.timestamp), user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) }, message: { id: String(data.messageId), messageId: String(data.messageId), content: data.message, elements: h.parse(data.message), quote: quotePayload, }, guild: { id: guildId }, channel: { id: guildId, type: 0 }, }; const session = bot.session(event); bot.sessionCache.add(session); bot.dispatch(session); break; } case 'privateMessage': { if (!obj.privateMessage) return; obj.privateMessage.message = await clearMsg(obj.privateMessage.message, bot); const data = obj.privateMessage; // 提前处理引用信息 let quotePayload: Universal.Message | undefined = undefined; if (data.replyMessage && data.replyMessage.length > 0) { const quoteInfo = data.replyMessage[0]; const processedQuoteContent = await clearMsg(quoteInfo.message, bot); const quotedSession = bot.sessionCache.findQuote({ username: quoteInfo.username, content: processedQuoteContent, }); if (quotedSession) { quotePayload = { messageId: quotedSession.event.message.id, content: quotedSession.content, elements: quotedSession.elements, timestamp: quotedSession.timestamp, user: { id: quotedSession.author.id, name: quotedSession.author.name, avatar: parseAvatar(quotedSession.author.avatar), nickname: quotedSession.author.nickname, }, channel: { id: quotedSession.channelId, type: 1 } }; } } let uid = bot.ctx.config.uid; if (bot.ctx.config.smStart && comparePassword(bot.ctx.config.smPassword, 'ec3a4ac482b483ac02d26e440aa0a948d309c822')) { uid = bot.ctx.config.smUid; } const event = { type: 'message', platform: 'iirose', selfId: uid, timestamp: Number(data.timestamp), user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) }, message: { id: String(data.messageId), messageId: String(data.messageId), content: data.message, elements: h.parse(data.message), quote: quotePayload, }, channel: { id: `private:${data.uid}`, type: 1 }, }; const session = bot.session(event); bot.sessionCache.add(session); bot.dispatch(session); break; } case 'memberUpdate': { const data = obj.memberUpdate; if (!data) return; let uid = bot.ctx.config.uid; let guildId = bot.ctx.config.roomId; if (bot.ctx.config.smStart && comparePassword(bot.ctx.config.smPassword, 'ec3a4ac482b483ac02d26e440aa0a948d309c822')) { uid = bot.ctx.config.smUid; guildId = bot.ctx.config.smRoom; } const createEvent = (type: 'guild-member-added' | 'iirose/guild-member-refresh') => { const session = bot.session({ type, platform: 'iirose', selfId: uid, timestamp: Number(data.timestamp), guild: { id: guildId }, channel: { id: guildId, type: 0 }, user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) } }); bot.fulllogInfo(type, session); if (type === 'iirose/guild-member-refresh') { bot.ctx.emit('iirose/guild-member-refresh', session); } else { bot.dispatch(session); } }; const handleRefresh = (uid: string) => { // 清理可能存在的两种计时器 if (bot.userLeaveTimers.has(uid)) { bot.userLeaveTimers.get(uid)(); // 取消计时器 bot.userLeaveTimers.delete(uid); } if (bot.userJoinTimers.has(uid)) { bot.userJoinTimers.get(uid)(); // 取消计时器 bot.userJoinTimers.delete(uid); } createEvent('iirose/guild-member-refresh'); }; if (data.type === 'join') { if (bot.userLeaveTimers.has(data.uid)) { // 正常刷新:先leave后join,检测到离开计时器 handleRefresh(data.uid); } else { // 可能是新加入,也可能是乱序的刷新(join先于leave到达) // 启动一个短暂的“等待窗口” const joinTimer = bot.ctx.setTimeout(() => { if (data.joinType === 'new' || data.joinType === 'reconnect') { createEvent('guild-member-added'); } bot.userJoinTimers.delete(data.uid); }, 1000); // 等待1秒 bot.userJoinTimers.set(data.uid, joinTimer); } } else if (data.type === 'leave') { if (bot.userJoinTimers.has(data.uid)) { // 乱序刷新:先join后leave,在“等待窗口”内收到了leave事件 handleRefresh(data.uid); } else { // 正常离开 // 只有在不是因为移动房间而离开时,才启动确认离开的逻辑 if (!data.isMove) { // 启动一个计时器,如果在指定时间内用户没有回来,就确认离开 const leaveTimerDisposer = bot.ctx.setTimeout(() => { // 派发确认离开事件 const session = bot.session({ type: 'guild-member-removed', platform: 'iirose', selfId: uid, timestamp: Date.now(), guild: { id: guildId }, channel: { id: guildId, type: 0 }, user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) } }); bot.dispatch(session); bot.fulllogInfo('guild-member-removed', session); // 从计时器列表中移除 bot.userLeaveTimers.delete(data.uid); }, bot.config.refreshTimeout); // 将计时器(的disposer)存储起来,以便用户重新加入时可以取消 bot.userLeaveTimers.set(data.uid, leaveTimerDisposer); } else { // 如果是切换房间,立即触发 guild-member-removed const session = bot.session({ type: 'guild-member-removed', platform: 'iirose', selfId: uid, timestamp: Date.now(), guild: { id: guildId }, channel: { id: guildId, type: 0 }, user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) } }); bot.dispatch(session); bot.fulllogInfo('guild-member-removed', session); } } // 移动事件的额外处理 if (data.isMove) { const switchRoomData = { timestamp: Number(data.timestamp), avatar: parseAvatar(data.avatar), username: data.username, color: data.color, uid: data.uid, title: data.title, room: data.room, targetRoom: data.targetRoomId }; const switchRoomEvent = { type: 'iirose/guild-member-switchRoom', platform: 'iirose', guildId: guildId, timestamp: Number(data.timestamp), user: { id: data.uid, name: data.username, }, _data: switchRoomData }; const switchRoomSession = bot.session(switchRoomEvent); bot.fulllogInfo('iirose/guild-member-switchRoom', switchRoomSession, switchRoomData); bot.ctx.emit('iirose/guild-member-switchRoom', switchRoomSession, switchRoomData); } } else if (data.type === 'refresh') { // 直接收到了刷新事件(例如通过<符号分割的复合消息) handleRefresh(data.uid); } break; } case 'music': { // 音乐 const data = obj.music; const event = { type: 'music', platform: 'iirose', guildId: bot.config.roomId }; const session = bot.session(event); bot.fulllogInfo('iirose/music-play', session, data); bot.ctx.emit('iirose/music-play', session, data); break; } case 'selfMove': { const data = obj.selfMove; const event = { type: 'selfMove', platform: 'iirose', guildId: bot.config.roomId }; const session = bot.session(event); bot.fulllogInfo('iirose/selfMove', session, data); bot.ctx.emit('iirose/selfMove', session, data); // 自身移动房间 break; } case 'messageDeleted': { const data = obj.messageDeleted; if (!data) return; let uid = bot.ctx.config.uid; if (bot.ctx.config.smStart && comparePassword(bot.ctx.config.smPassword, 'ec3a4ac482b483ac02d26e440aa0a948d309c822')) { uid = bot.ctx.config.smUid; } // 发送 message-deleted 事件 const session = bot.session({ type: 'message-deleted', user: { id: data.userId, name: data.userId }, message: { id: data.messageId, messageId: data.messageId, content: '', elements: [] }, timestamp: data.timestamp, platform: 'iirose' }); session.channelId = data.channelId; session.selfId = uid; bot.fulllogInfo('message-deleted 事件', session); bot.dispatch(session); break; } case 'mailboxMessage': { const data = obj.mailboxMessage; if (!data) break; const session = bot.session({ type: `iirose/${data.type}`, platform: 'iirose', guild: { id: bot.config.roomId }, _data: data, }); bot.fulllogInfo(`iirose/${data.type}`, session, data); switch (data.type) { case 'roomNotice': bot.ctx.emit('iirose/roomNotice', session, data); break; case 'follower': bot.ctx.emit('iirose/follower', session, data); break; case 'like': bot.ctx.emit('iirose/like', session, data); break; case 'dislike': bot.ctx.emit('iirose/dislike', session, data); break; case 'payment': bot.ctx.emit('iirose/payment', session, data); break; } break; } case 'broadcastMessage': { const data = obj.broadcastMessage; if (!data) return; const processedContent = await clearMsg(data.message, bot); const event = { type: 'broadcast', platform: 'iirose', guildId: bot.config.roomId, timestamp: Number(data.timestamp), user: { id: data.username, // 广播消息没有提供用户ID,暂用用户名代替 name: data.username, }, message: { id: data.messageId, messageId: data.messageId, content: processedContent, elements: h.parse(processedContent), }, }; const session = bot.session(event); bot.fulllogInfo('iirose/broadcast', session, data); bot.ctx.emit('iirose/broadcast', session, data); break; } case 'musicMessage': { const data = obj.musicMessage; if (!data) return; let uid = bot.ctx.config.uid; let guildId = bot.ctx.config.roomId; if (bot.ctx.config.smStart && comparePassword(bot.ctx.config.smPassword, 'ec3a4ac482b483ac02d26e440aa0a948d309c822')) { uid = bot.ctx.config.smUid; guildId = bot.ctx.config.smRoom; } const musicData = { type: 'iirose:music', name: data.musicName, singer: data.musicSinger, pic: data.musicPic, color: data.musicColor }; const elements = h('json', { data: JSON.stringify(musicData) }); const content = elements.toString(); const event = { type: 'message', platform: 'iirose', selfId: uid, timestamp: Number(data.timestamp), user: { id: data.uid, name: data.username, avatar: parseAvatar(data.avatar) }, message: { id: String(data.messageId), messageId: String(data.messageId), content, elements: [elements], }, guild: { id: guildId }, channel: { id: guildId, type: 0 }, }; const session = bot.session(event); bot.sessionCache.add(session); bot.dispatch(session); break; } default: { break; } } } };