Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support image and file messages #82

Merged
merged 13 commits into from
Jul 28, 2021
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
61 changes: 51 additions & 10 deletions src/appservice-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
FileUploadOpts,
} from 'matrix-appservice-bridge'

import { Message } from 'wechaty'
import { MessageType } from 'wechaty-puppet'

import {
log,
} from './config'
Expand Down Expand Up @@ -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()
: '',
Expand All @@ -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()}`)
Expand Down Expand Up @@ -251,4 +285,11 @@ export class AppserviceManager extends Manager {
return this.bridge.getIntent(userId).uploadContent(content, opts)
}

public async mxcUrlToHttp (
mxcUrl: string,
): Promise<string> {
// also can use getHttpUriForMxc(this.baseUrl, mxcUrl, width, height, resizeMethod, allowDirectLinks);
return this.bridge.getIntent().client.mxcUrlToHttp(mxcUrl)
lprintf marked this conversation as resolved.
Show resolved Hide resolved
}

}
36 changes: 33 additions & 3 deletions src/matrix-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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)
Expand All @@ -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<string|number|Message|Contact|FileBox|MiniProgram|UrlLink> {
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
}

}
13 changes: 6 additions & 7 deletions src/middle-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Room as WechatyRoom,
Contact as WechatyUser,
Wechaty,
Message,
} from 'wechaty'

import {
Expand Down Expand Up @@ -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<void>
/**
* Send message from user to the bridge consumer
*/
public async directMessageToMatrixConsumer (text: string, from: WechatyUser): Promise<void>

public async directMessageToMatrixConsumer (
text: string,
message: string | Message,
from: WechatyUser | Wechaty,
): Promise<void> {
const text = typeof (message) === 'string' ? message : message.text()
log.verbose('MiddleManager', 'directMessageToMatrixConsumer("%s", "%s")',
text,
from
Expand All @@ -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)
Expand All @@ -512,7 +511,7 @@ export class MiddleManager extends Manager {
}

await this.appserviceManager.sendMessage(
text,
message,
matrixRoom,
matrixUser,
)
Expand Down
12 changes: 5 additions & 7 deletions src/wechaty-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export class WechatyManager extends Manager {
): Promise<void> {
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,
Expand Down Expand Up @@ -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 (
Expand All @@ -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,
)
Expand Down