diff --git a/package.json b/package.json index dcd8bac..0447f63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-appservice-wechaty", - "version": "0.8.30", + "version": "0.8.32", "description": "Matrix Application Services Bridge for Wechat", "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", diff --git a/src/appservice-manager.ts b/src/appservice-manager.ts index 6530292..f23d606 100644 --- a/src/appservice-manager.ts +++ b/src/appservice-manager.ts @@ -11,6 +11,9 @@ import { FileUploadOpts, } from 'matrix-appservice-bridge' +import { Message } from 'wechaty' +import { MessageType } from 'wechaty-puppet' + import { log, } from './config' @@ -110,12 +113,13 @@ export class AppserviceManager extends Manager { } public async sendMessage ( - withText : string, + message : string | Message, inRoom : MatrixRoom, fromUser? : MatrixUser, ) { + const text = typeof (message) === 'string' ? message : message.text() log.verbose('AppserviceManager', 'sendMessage(%s%s%s)', - withText.substr(0, 100), + text.substr(0, 100), inRoom ? ', ' + inRoom.getId() : '', @@ -124,18 +128,48 @@ export class AppserviceManager extends Manager { : '', ) - try { - let matrixUserId - - if (fromUser) { - matrixUserId = fromUser && fromUser.getId() + const intent = this.bridge.getIntent(fromUser && fromUser.getId()) + + if (typeof (message) !== 'string') { + switch (message.type()) { + case MessageType.Unknown: + break + case MessageType.Audio: + break + case MessageType.Contact: // image in ipad protocol is Emoticon + break + case MessageType.Emoticon: case MessageType.Image: case MessageType.Attachment: + // image in web protocol is Image, in ipad protocol is Emoticon + try { + const file = await message.toFileBox() + const buffer = await file.toBuffer() + // XXX It is recommended to use a digital summary to construct the file name to avoid repeated uploads. + // digital summary consuming too much computing resources, use the url to lable it is better. + const url = await intent.uploadContent(buffer, { + name: file.name, + type: file.mimeType === 'emoticon' ? 'image/gif' : file.mimeType, + }) + await intent.sendMessage( + inRoom.getId(), + { + body: file.name, + info: {}, + msgtype: message.type() === MessageType.Attachment ? 'm.file' : 'm.image', + url: url, + } + ) + } catch (e) { + log.error(`AppserviceManager', 'sendMessage() rejection from ${fromUser ? fromUser.getId() : 'BOT'} to room ${inRoom.getId()}`) + throw e + } + return } + } - const intent = this.bridge.getIntent(matrixUserId) - + try { await intent.sendText( inRoom.getId(), - withText, + text, ) } catch (e) { log.error(`AppserviceManager', 'sendMessage() rejection from ${fromUser ? fromUser.getId() : 'BOT'} to room ${inRoom.getId()}`) @@ -251,4 +285,11 @@ export class AppserviceManager extends Manager { return this.bridge.getIntent(userId).uploadContent(content, opts) } + public async mxcUrlToHttp ( + mxcUrl: string, + ): Promise { + // also can use getHttpUriForMxc(this.baseUrl, mxcUrl, width, height, resizeMethod, allowDirectLinks); + return this.bridge.getIntent().client.mxcUrlToHttp(mxcUrl) + } + } diff --git a/src/matrix-handler.ts b/src/matrix-handler.ts index 2c5d43b..06d9592 100644 --- a/src/matrix-handler.ts +++ b/src/matrix-handler.ts @@ -18,6 +18,7 @@ import { DialogManager } from './dialog-manager' import { MiddleManager } from './middle-manager' import { WechatyManager } from './wechaty-manager' import { UserManager } from './user-manager' +import { Contact, FileBox, Message, MiniProgram, UrlLink } from 'wechaty' export class MatrixHandler { @@ -306,7 +307,9 @@ export class MatrixHandler { // superEvent.sender(), // FIXME: should be consumer // ) - await wechatyRoom.say(superEvent.event.content!.body as string || 'undefined') + const message = await this.superEvent2Message(superEvent) + // XXX removing the overload declarations may be a better choice. + await wechatyRoom.say(message as any) } catch (e) { log.error('MatrixHandler', 'processGroupMessage() rejection: %s', e.message) @@ -327,8 +330,35 @@ export class MatrixHandler { // const contact = await this.wechatyManager // .wechatyContact(service, user) - const text = superEvent.event.content!.body - await contact.say(text + '') + const message = await this.superEvent2Message(superEvent) + // XXX removing the overload declarations may be a better choice. + await contact.say(message as any) + } + + protected async superEvent2Message ( + superEvent: SuperEvent, + ):Promise { + const content = superEvent.event.content! + let mxcUrl = '' + let httpsUrl = '' + const body = superEvent.text() + let message : string|number|Message|Contact|FileBox|MiniProgram|UrlLink + = body + switch (content.msgtype) { + case 'm.text': + break + case 'm.image': case 'm.file': + mxcUrl = content.url as string + httpsUrl = await this.appserviceManager.mxcUrlToHttp(mxcUrl) + // XXX can't show Animation well in wechat. + message = FileBox.fromUrl( + httpsUrl, + body.indexOf('.') > -1 || content.msgtype !== 'm.image' + ? body + : `${mxcUrl.split('/').pop()}.gif`, + ) + } + return message } } diff --git a/src/middle-manager.ts b/src/middle-manager.ts index 9fb8f34..3d67ed5 100644 --- a/src/middle-manager.ts +++ b/src/middle-manager.ts @@ -2,6 +2,7 @@ import { Room as WechatyRoom, Contact as WechatyUser, Wechaty, + Message, } from 'wechaty' import { @@ -478,17 +479,13 @@ export class MiddleManager extends Manager { /** * Send message from service bot to the bridge consumer - */ - public async directMessageToMatrixConsumer (text: string, from: Wechaty): Promise - /** * Send message from user to the bridge consumer */ - public async directMessageToMatrixConsumer (text: string, from: WechatyUser): Promise - public async directMessageToMatrixConsumer ( - text: string, + message: string | Message, from: WechatyUser | Wechaty, ): Promise { + const text = typeof (message) === 'string' ? message : message.text() log.verbose('MiddleManager', 'directMessageToMatrixConsumer("%s", "%s")', text, from @@ -498,11 +495,13 @@ export class MiddleManager extends Manager { let matrixUser if (from instanceof WechatyUser) { + // receive messages from wecahty users(your friends) matrixRoom = await this.matrixRoom(from) matrixUser = await this.matrixUser(from) } else if (from instanceof Wechaty) { + // xxx This block will not be called on the code now, send message (the messages said by your self on other device) const consumerId = this.wechatyManager.matrixConsumerId(from) matrixRoom = await this.adminRoom(consumerId) @@ -512,7 +511,7 @@ export class MiddleManager extends Manager { } await this.appserviceManager.sendMessage( - text, + message, matrixRoom, matrixUser, ) diff --git a/src/wechaty-manager.ts b/src/wechaty-manager.ts index 1ea97ec..94b97d6 100644 --- a/src/wechaty-manager.ts +++ b/src/wechaty-manager.ts @@ -271,7 +271,7 @@ export class WechatyManager extends Manager { ): Promise { log.verbose('WechatyManager', 'onMessage("%s") from "%s" to "%s" with age "%s" (timestamp: "%s")', message, - message.from()!.id, + message.talker()!.id, (message.to() || message.room())!.id, message.age(), (message as any).payload.timestamp, @@ -305,12 +305,12 @@ export class WechatyManager extends Manager { // forMatrixConsumer.getId(), ) - const from = onWechatyMessage.from() + const from = onWechatyMessage.talker() if (!from) { throw new Error('can not found from contact for wechat message') } - await this.middleManager.directMessageToMatrixConsumer(onWechatyMessage.text(), from) + await this.middleManager.directMessageToMatrixConsumer(onWechatyMessage, from) } async processRoomMessage ( @@ -324,18 +324,16 @@ export class WechatyManager extends Manager { if (!room) { throw new Error('no room') } - const from = onWechatyMessage.from() + const from = onWechatyMessage.talker() if (!from) { throw new Error('no from') } - const text = onWechatyMessage.text() - const matrixRoom = await this.middleManager.matrixRoom(room) const matrixUser = await this.middleManager.matrixUser(from) await this.appserviceManager.sendMessage( - text, + onWechatyMessage, matrixRoom, matrixUser, )