import { TcService, TcDbService, InboxStruct, call } from 'tailchat-server-sdk'; import type { WXPusherUserDocument, WXPusherUserModel, } from '../models/wxpusher-user'; import got from 'got'; import type { TcContext } from 'tailchat-server-sdk'; /** * wxpusher * * Add support for wxpusher to notify user */ interface WxpusherService extends TcService, TcDbService {} class WxpusherService extends TcService { get serviceName() { return 'plugin:com.msgbyte.wxpusher'; } get appToken() { return process.env.WXPUSHER_APP_TOKEN; } /** * 返回服务是否可用 */ get serverAvailable(): boolean { return Boolean(this.appToken); } onInit() { this.registerLocalDb(require('../models/wxpusher-user').default); this.registerAvailableAction(() => this.serverAvailable); if (!this.serverAvailable) { console.warn( '[plugin:com.msgbyte.wxpusher] require env: WXPUSHER_APP_TOKEN' ); return; } this.registerEventListener( 'chat.inbox.append', async (inboxItem: InboxStruct, ctx) => { if (inboxItem.type === 'message') { const userId = inboxItem.userId; const message = inboxItem.payload; let title = 'new'; const senderInfo = await call(ctx).getUserInfo(message.messageAuthor); if (message.groupId) { const [groupInfo] = await Promise.all([ call(ctx).getGroupInfo(message.groupId), ]); title = `[群组] ${groupInfo.name} 的 ${senderInfo.nickname}`; // 因为wxpusher插件仅适用于中国大陆,因此仅需要中文即可 } else { title = `[私信] ${senderInfo.nickname}`; // 因为wxpusher插件仅适用于中国大陆,因此仅需要中文即可 } const content = `${senderInfo.nickname}: ${ message.messagePlainContent ?? message.messageSnippet }`; // 优先使用去节点的内容 try { await this.sendMessage(userId, [title, content].join('\n')); } catch (err) { console.error(err); } } } ); this.registerAction('getWXPusherUserId', this.getWXPusherUserId); this.registerAction('createQRCode', this.createQRCode); this.registerAction('callback', this.callback, { params: { action: 'string', data: 'any', }, }); this.registerAuthWhitelist(['/callback']); } async getWXPusherUserId(ctx: TcContext) { const userId = ctx.meta.userId; return await this.findUserWxpusherUid(userId); } async createQRCode(ctx: TcContext) { const userId = ctx.meta.userId; const json = await got .post('https://wxpusher.zjiecode.com/api/fun/create/qrcode', { json: { appToken: this.appToken, // 必填,appToken,前面有说明,应用的标志 extra: userId, // 必填,二维码携带的参数,最长64位 validTime: 1800, // 可选,二维码的有效期,默认30分钟,最长30天,单位是秒 }, }) .json(); return json; } async callback( ctx: TcContext<{ action: string; data: any; }> ) { const { action, data } = ctx.params; if (action === 'app_subscribe') { this.logger.info('data', data); // Reference: https://wxpusher.zjiecode.com/docs/#/?id=subscribe-callback const userId = data.extra; const wxpusherUserId = data.uid; const record = await this.adapter.model.findOne({ userId }); if (!record) { // 新增 await this.adapter.model.create({ userId, wxpusherUserId, }); } else { record.wxpusherUserId = wxpusherUserId; await record.save(); } } return true; } /** * 查找wxpusher的用户id */ async findUserWxpusherUid(userId: string): Promise { const user = await this.adapter.model.findOne({ userId }); if (!user) { return null; } const wxpusherUserId = user.wxpusherUserId; return wxpusherUserId; } /** * 发送消息 */ async sendMessage(userId: string, content: string) { const uid = await this.findUserWxpusherUid(userId); if (!uid) { console.warn('This user not bind wxpusher, skip!'); return; } await got.post('https://wxpusher.zjiecode.com/api/send/message', { json: { appToken: this.appToken, content, contentType: 1, //内容类型 1表示文字 2表示html(只发送body标签内部的数据即可,不包括body标签) 3表示markdown uids: [uid], }, }); } } export default WxpusherService;