Move from global message IDs to local IDs
This commit is contained in:
parent
757badde67
commit
50e27b2e7d
12
README.md
12
README.md
|
@ -1,9 +1,9 @@
|
||||||
# mx-puppet-vk
|
# mx-puppet-vk
|
||||||
This is a Matrix <-> VK bridge based on [mx-puppet-bridge](https://github.com/Sorunome/mx-puppet-bridge) and [VK-IO](https://github.com/negezor/vk-io).
|
This is a Matrix <-> VK bridge based on [mx-puppet-bridge](https://github.com/Sorunome/mx-puppet-bridge) and [VK-IO](https://github.com/negezor/vk-io).
|
||||||
|
|
||||||
It is in early development and should be considered as proof-of-concept. Right now it logs message data when log level includes "info" level.
|
It is in early development. Right now it logs message data when log level includes "info" level.
|
||||||
|
|
||||||
Group chats are not properly tested.
|
Relay mode works too, but we don't recommend it.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```bash
|
```bash
|
||||||
|
@ -25,7 +25,7 @@ Register that one with synapse and start the bridge with `npm run start`.
|
||||||
- [ ] Presence - not possible yet
|
- [ ] Presence - not possible yet
|
||||||
- [ ] Read notifications - not possible yet
|
- [ ] Read notifications - not possible yet
|
||||||
- [x] Message edits
|
- [x] Message edits
|
||||||
- [x] Message redacts - only works in 24 hours after message is sent
|
- [x] Message redacts - works as edit, real redact unavailable without being admin in chat
|
||||||
- VK -> Matrix
|
- VK -> Matrix
|
||||||
- [x] Text content
|
- [x] Text content
|
||||||
- [ ] Forwards
|
- [ ] Forwards
|
||||||
|
@ -49,3 +49,9 @@ Register that one with synapse and start the bridge with `npm run start`.
|
||||||
5. Now, if someone contacts your community, you will be invited to the corresponding room on Matrix.
|
5. Now, if someone contacts your community, you will be invited to the corresponding room on Matrix.
|
||||||
|
|
||||||
Plese note: when community is invited to the group chat as a bot, make sure it has message access. Only chat admins can change bot permissions.
|
Plese note: when community is invited to the group chat as a bot, make sure it has message access. Only chat admins can change bot permissions.
|
||||||
|
|
||||||
|
Bridge doesn't handle being kicked from chat yet.
|
||||||
|
|
||||||
|
### Relay usage
|
||||||
|
|
||||||
|
See [mx-puppet-bridge docs](https://github.com/Sorunome/mx-puppet-bridge#relay-mode)
|
||||||
|
|
|
@ -52,6 +52,7 @@ const protocol: IProtocolInformation = {
|
||||||
presence: false,
|
presence: false,
|
||||||
reply: true,
|
reply: true,
|
||||||
edit: true,
|
edit: true,
|
||||||
|
advancedRelay: true,
|
||||||
},
|
},
|
||||||
id: "vk", // an internal ID for the protocol, all lowercase
|
id: "vk", // an internal ID for the protocol, all lowercase
|
||||||
displayname: "VK", // a human-readable name of the protocol
|
displayname: "VK", // a human-readable name of the protocol
|
||||||
|
|
96
src/vk.ts
96
src/vk.ts
|
@ -81,7 +81,7 @@ export class VkPuppet {
|
||||||
const info = await p.client.api.messages.getConversationsById({ peer_ids: peerId, fields: ["photo_max"] });
|
const info = await p.client.api.messages.getConversationsById({ peer_ids: peerId, fields: ["photo_max"] });
|
||||||
// log.info(info.items[0]);
|
// log.info(info.items[0]);
|
||||||
let response: IRemoteRoom;
|
let response: IRemoteRoom;
|
||||||
switch (info.items[0].peer.type) {
|
switch (info.items[0]?.peer.type || "chat") {
|
||||||
case "user":
|
case "user":
|
||||||
// tslint:disable-next-line: no-shadowed-variable
|
// tslint:disable-next-line: no-shadowed-variable
|
||||||
const userInfo = await p.client.api.users.get({ user_ids: info.items[0].peer.id, fields: ["photo_max"] });
|
const userInfo = await p.client.api.users.get({ user_ids: info.items[0].peer.id, fields: ["photo_max"] });
|
||||||
|
@ -98,8 +98,9 @@ export class VkPuppet {
|
||||||
response = {
|
response = {
|
||||||
puppetId,
|
puppetId,
|
||||||
roomId: peerId.toString(),
|
roomId: peerId.toString(),
|
||||||
name: info.items[0].chat_settings.title,
|
name: info.items[0]?.chat_settings.title || `VK chat №${(peerId - 2000000000).toString()}`,
|
||||||
avatarUrl: info.items[0].chat_settings.photo.photo_200,
|
topic: info.count === 0 ? "To recieve chat name and avatar, puppet needs admin rights on VK side" : null,
|
||||||
|
avatarUrl: info.items[0]?.chat_settings.photo?.photo_200,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -177,7 +178,7 @@ export class VkPuppet {
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
||||||
// tslint:disable-next-line: no-any
|
// tslint:disable-next-line: no-any
|
||||||
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent, event: any) {
|
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent, asUser: ISendingUser | null, event: any) {
|
||||||
// this is called every time we receive a message from matrix and need to
|
// this is called every time we receive a message from matrix and need to
|
||||||
// forward it to the remote protocol.
|
// forward it to the remote protocol.
|
||||||
|
|
||||||
|
@ -186,30 +187,43 @@ export class VkPuppet {
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asUser) {
|
||||||
|
const MAX_NAME_LENGTH = 80;
|
||||||
|
const displayname = (new TextEncoder().encode(asUser.displayname));
|
||||||
|
asUser.displayname = (new TextDecoder().decode(displayname.slice(0, MAX_NAME_LENGTH)));
|
||||||
|
}
|
||||||
// usually you'd send it here to the remote protocol via the client object
|
// usually you'd send it here to the remote protocol via the client object
|
||||||
try {
|
try {
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_ids: Number(room.roomId),
|
||||||
message: data.body,
|
message: asUser ? `${asUser.displayname}: ${data.body}` : data.body,
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!,
|
||||||
|
response[0]["conversation_message_id"].toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending to vk", err.error || err.body || err);
|
log.error("Error sending to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixEdit(room: IRemoteRoom, eventId: string, data: IMessageEvent) {
|
public async handleMatrixEdit(room: IRemoteRoom, eventId: string, data: IMessageEvent, asUser: ISendingUser | null) {
|
||||||
const p = this.puppets[room.puppetId];
|
const p = this.puppets[room.puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asUser) {
|
||||||
|
const MAX_NAME_LENGTH = 80;
|
||||||
|
const displayname = (new TextEncoder().encode(asUser.displayname));
|
||||||
|
asUser.displayname = (new TextDecoder().decode(displayname.slice(0, MAX_NAME_LENGTH)));
|
||||||
|
}
|
||||||
// usually you'd send it here to the remote protocol via the client object
|
// usually you'd send it here to the remote protocol via the client object
|
||||||
try {
|
try {
|
||||||
const response = await p.client.api.messages.edit({
|
const response = await p.client.api.messages.edit({
|
||||||
peer_id: Number(room.roomId),
|
peer_id: Number(room.roomId),
|
||||||
message: data.body,
|
conversation_message_id: Number(eventId),
|
||||||
message_id: Number(eventId),
|
message: asUser ? `${asUser.displayname}: ${data.body}` : data.body,
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
||||||
|
@ -218,18 +232,26 @@ export class VkPuppet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixRedact(room: IRemoteRoom, eventId: string) {
|
public async handleMatrixRedact(room: IRemoteRoom, eventId: string, asUser: ISendingUser | null) {
|
||||||
const p = this.puppets[room.puppetId];
|
const p = this.puppets[room.puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asUser) {
|
||||||
|
const MAX_NAME_LENGTH = 80;
|
||||||
|
const displayname = (new TextEncoder().encode(asUser.displayname));
|
||||||
|
asUser.displayname = (new TextDecoder().decode(displayname.slice(0, MAX_NAME_LENGTH)));
|
||||||
|
}
|
||||||
// usually you'd send it here to the remote protocol via the client object
|
// usually you'd send it here to the remote protocol via the client object
|
||||||
try {
|
try {
|
||||||
await p.client.api.messages.delete({
|
await this.handleMatrixEdit(room, eventId, { body: "[ДАННЫЕ УДАЛЕНЫ]", eventId }, asUser);
|
||||||
|
// broken in chats without admin access
|
||||||
|
/*await p.client.api.messages.delete({
|
||||||
spam: 0,
|
spam: 0,
|
||||||
delete_for_all: 1,
|
delete_for_all: 1,
|
||||||
message_ids: Number(eventId),
|
message_ids: Number(eventId),
|
||||||
});
|
});*/
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending edit to vk", err.error || err.body || err);
|
log.error("Error sending edit to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
|
@ -239,6 +261,7 @@ export class VkPuppet {
|
||||||
room: IRemoteRoom,
|
room: IRemoteRoom,
|
||||||
eventId: string,
|
eventId: string,
|
||||||
data: IMessageEvent,
|
data: IMessageEvent,
|
||||||
|
asUser: ISendingUser | null,
|
||||||
// tslint:disable-next-line: no-any
|
// tslint:disable-next-line: no-any
|
||||||
event: any,
|
event: any,
|
||||||
) {
|
) {
|
||||||
|
@ -246,15 +269,22 @@ export class VkPuppet {
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asUser) {
|
||||||
|
const MAX_NAME_LENGTH = 80;
|
||||||
|
const displayname = (new TextEncoder().encode(asUser.displayname));
|
||||||
|
asUser.displayname = (new TextDecoder().decode(displayname.slice(0, MAX_NAME_LENGTH)));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// log.info("Sending reply", Number(eventId));
|
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_ids: Number(room.roomId),
|
||||||
message: await this.stripReply(data.body),
|
message: asUser ? `${asUser.displayname}: ${await this.stripReply(data.body)}` : await this.stripReply(data.body),
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
reply_to: Number(eventId),
|
forward: `{"peer_id":${Number(room.roomId)},"conversation_message_ids":${Number(eventId)},"is_reply": true}`,
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!,
|
||||||
|
response[0]["conversation_message_id"].toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending to vk", err.error || err.body || err);
|
log.error("Error sending to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
|
@ -274,22 +304,28 @@ export class VkPuppet {
|
||||||
const MAXFILESIZE = 50000000;
|
const MAXFILESIZE = 50000000;
|
||||||
const size = data.info ? data.info.size || 0 : 0;
|
const size = data.info ? data.info.size || 0 : 0;
|
||||||
|
|
||||||
|
if (asUser) {
|
||||||
|
const MAX_NAME_LENGTH = 80;
|
||||||
|
const displayname = (new TextEncoder().encode(asUser.displayname));
|
||||||
|
asUser.displayname = (new TextDecoder().decode(displayname.slice(0, MAX_NAME_LENGTH)));
|
||||||
|
}
|
||||||
|
|
||||||
if (size < MAXFILESIZE) {
|
if (size < MAXFILESIZE) {
|
||||||
try {
|
try {
|
||||||
// log.info("Sending image...");
|
|
||||||
const attachment = await p.client.upload.messagePhoto({
|
const attachment = await p.client.upload.messagePhoto({
|
||||||
peer_id: Number(room.roomId),
|
peer_id: Number(room.roomId),
|
||||||
source: {
|
source: {
|
||||||
value: data.url,
|
value: data.url,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// log.info("Image sent", attachment);
|
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_ids: Number(room.roomId),
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
|
message: asUser ? `${asUser.displayname} sent a photo:` : undefined,
|
||||||
attachment: [`photo${attachment.ownerId}_${attachment.id}`],
|
attachment: [`photo${attachment.ownerId}_${attachment.id}`],
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!,
|
||||||
|
response[0]["conversation_message_id"].toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending to vk", err.error || err.body || err);
|
log.error("Error sending to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
|
@ -323,7 +359,6 @@ export class VkPuppet {
|
||||||
|
|
||||||
if (size < MAXFILESIZE) {
|
if (size < MAXFILESIZE) {
|
||||||
try {
|
try {
|
||||||
// log.info("Sending file...");
|
|
||||||
const attachment = await p.client.upload.messageDocument({
|
const attachment = await p.client.upload.messageDocument({
|
||||||
peer_id: Number(room.roomId),
|
peer_id: Number(room.roomId),
|
||||||
source: {
|
source: {
|
||||||
|
@ -331,21 +366,22 @@ export class VkPuppet {
|
||||||
filename: data.filename,
|
filename: data.filename,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// log.info("File sent", attachment);
|
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_id: Number(room.roomId),
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
|
message: asUser ? `${asUser.displayname} sent a file:` : undefined,
|
||||||
attachment: [`doc${attachment.ownerId}_${attachment.id}`],
|
attachment: [`doc${attachment.ownerId}_${attachment.id}`],
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
try {
|
try {
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_ids: Number(room.roomId),
|
||||||
message: `File ${data.filename} was sent, but VK refused to recieve it. You may download it there:\n${data.url}`,
|
message: `File ${data.filename} was sent, but VK refused to recieve it. You may download it there:\n${data.url}`,
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!,
|
||||||
|
response[0]["conversation_message_id"].toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending to vk", err.error || err.body || err);
|
log.error("Error sending to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
|
@ -353,11 +389,12 @@ export class VkPuppet {
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const response = await p.client.api.messages.send({
|
const response = await p.client.api.messages.send({
|
||||||
peer_id: Number(room.roomId),
|
peer_ids: Number(room.roomId),
|
||||||
message: `File ${data.filename} was sent, but it is too big for VK. You may download it there:\n${data.url}`,
|
message: `File ${data.filename} was sent, but it is too big for VK. You may download it there:\n${data.url}`,
|
||||||
random_id: new Date().getTime(),
|
random_id: new Date().getTime(),
|
||||||
});
|
});
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, response.toString());
|
await this.puppet.eventSync.insert(room, data.eventId!,
|
||||||
|
response[0]["conversation_message_id"].toString());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error sending to vk", err.error || err.body || err);
|
log.error("Error sending to vk", err.error || err.body || err);
|
||||||
}
|
}
|
||||||
|
@ -388,7 +425,8 @@ export class VkPuppet {
|
||||||
return; // Deduping
|
return; // Deduping
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = await this.getSendParams(puppetId, context.peerId, context.senderId, context.id.toString());
|
const params = await this.getSendParams(puppetId, context.peerId, context.senderId,
|
||||||
|
context.conversationMessageId?.toString() || context.id.toString());
|
||||||
|
|
||||||
if (context.hasText) {
|
if (context.hasText) {
|
||||||
if (context.hasReplyMessage) {
|
if (context.hasReplyMessage) {
|
||||||
|
|
Loading…
Reference in a new issue