mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-11-14 23:41:40 +00:00
file handling
This commit is contained in:
parent
1cab823bbe
commit
79dc0295cf
@ -11,10 +11,11 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Log, ExpireSet, IRemoteRoom } from "mx-puppet-bridge";
|
import { Log, ExpireSet, IRemoteRoom, Util } from "mx-puppet-bridge";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as skypeHttp from "skype-http";
|
import * as skypeHttp from "skype-http";
|
||||||
import { Contact as SkypeContact } from "skype-http/dist/lib/types/contact";
|
import { Contact as SkypeContact } from "skype-http/dist/lib/types/contact";
|
||||||
|
import { NewMediaMessage as SkypeNewMediaMessage } from "skype-http/dist/lib/interfaces/api/api";
|
||||||
|
|
||||||
const log = new Log("SkypePuppet:client");
|
const log = new Log("SkypePuppet:client");
|
||||||
|
|
||||||
@ -168,9 +169,50 @@ export class Client extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async downloadFile(url: string): Promise<Buffer> {
|
||||||
|
if (!url.includes("/views/imgpsh_fullsize_anim")) {
|
||||||
|
url = url + "/views/imgpsh_fullsize_anim";
|
||||||
|
}
|
||||||
|
return await Util.DownloadFile(url, {
|
||||||
|
cookies: this.api.context.cookies,
|
||||||
|
headers: { Authorization: 'skype_token ' + this.api.context.skypeToken.value },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async sendMessage(conversationId: string, msg: string): Promise<skypeHttp.Api.SendMessageResult> {
|
public async sendMessage(conversationId: string, msg: string): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
return await this.api.sendMessage({
|
return await this.api.sendMessage({
|
||||||
textContent: msg,
|
textContent: msg,
|
||||||
}, conversationId);
|
}, conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async sendEdit(conversationId: string, messageId: string, msg: string) {
|
||||||
|
return await this.api.sendEdit({
|
||||||
|
textContent: msg,
|
||||||
|
}, conversationId, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendDelete(conversationId: string, messageId: string) {
|
||||||
|
return await this.api.sendDelete(conversationId, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendAudio(
|
||||||
|
conversationId: string,
|
||||||
|
opts: SkypeNewMediaMessage,
|
||||||
|
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
|
return await this.api.sendAudio(opts, conversationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendDocument(
|
||||||
|
conversationId: string,
|
||||||
|
opts: SkypeNewMediaMessage
|
||||||
|
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
|
return await this.api.sendDocument(opts, conversationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendImage(
|
||||||
|
conversationId: string,
|
||||||
|
opts: SkypeNewMediaMessage
|
||||||
|
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
|
return await this.api.sendImage(opts, conversationId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
10
src/index.ts
10
src/index.ts
@ -58,8 +58,11 @@ if (options.help) {
|
|||||||
|
|
||||||
const protocol: IProtocolInformation = {
|
const protocol: IProtocolInformation = {
|
||||||
features: {
|
features: {
|
||||||
// file: true, // no need for the others as we auto-detect types anyways
|
image: true,
|
||||||
|
audio: true,
|
||||||
|
file: true,
|
||||||
// presence: true, // we want to be able to send presence
|
// presence: true, // we want to be able to send presence
|
||||||
|
edit: true,
|
||||||
globalNamespace: true,
|
globalNamespace: true,
|
||||||
},
|
},
|
||||||
id: "skype",
|
id: "skype",
|
||||||
@ -91,6 +94,11 @@ async function run() {
|
|||||||
puppet.on("puppetNew", skype.newPuppet.bind(skype));
|
puppet.on("puppetNew", skype.newPuppet.bind(skype));
|
||||||
puppet.on("puppetDelete", skype.deletePuppet.bind(skype));
|
puppet.on("puppetDelete", skype.deletePuppet.bind(skype));
|
||||||
puppet.on("message", skype.handleMatrixMessage.bind(skype));
|
puppet.on("message", skype.handleMatrixMessage.bind(skype));
|
||||||
|
puppet.on("edit", skype.handleMatrixEdit.bind(skype));
|
||||||
|
puppet.on("redact", skype.handleMatrixRedact.bind(skype));
|
||||||
|
puppet.on("image", skype.handleMatrixImage.bind(skype));
|
||||||
|
puppet.on("audio", skype.handleMatrixAudio.bind(skype));
|
||||||
|
puppet.on("file", skype.handleMatrixFile.bind(skype));
|
||||||
puppet.setCreateUserHook(skype.createUser.bind(skype));
|
puppet.setCreateUserHook(skype.createUser.bind(skype));
|
||||||
puppet.setCreateRoomHook(skype.createRoom.bind(skype));
|
puppet.setCreateRoomHook(skype.createRoom.bind(skype));
|
||||||
puppet.setGetUserIdsInRoomHook(skype.getUserIdsInRoom.bind(skype));
|
puppet.setGetUserIdsInRoomHook(skype.getUserIdsInRoom.bind(skype));
|
||||||
|
162
src/skype.ts
162
src/skype.ts
@ -11,11 +11,13 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator,
|
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
||||||
|
ExpireSet,
|
||||||
} from "mx-puppet-bridge";
|
} from "mx-puppet-bridge";
|
||||||
import { Client } from "./client";
|
import { Client } from "./client";
|
||||||
import * as skypeHttp from "skype-http";
|
import * as skypeHttp from "skype-http";
|
||||||
import { Contact as SkypeContact } from "skype-http/dist/lib/types/contact";
|
import { Contact as SkypeContact } from "skype-http/dist/lib/types/contact";
|
||||||
|
import { NewMediaMessage as SkypeNewMediaMessage } from "skype-http/dist/lib/interfaces/api/api";
|
||||||
import * as decodeHtml from "decode-html";
|
import * as decodeHtml from "decode-html";
|
||||||
import * as escapeHtml from "escape-html";
|
import * as escapeHtml from "escape-html";
|
||||||
|
|
||||||
@ -24,6 +26,7 @@ const log = new Log("SkypePuppet:skype");
|
|||||||
interface ISkypePuppet {
|
interface ISkypePuppet {
|
||||||
client: Client;
|
client: Client;
|
||||||
data: any;
|
data: any;
|
||||||
|
deletedMessages: ExpireSet<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISkypePuppets {
|
interface ISkypePuppets {
|
||||||
@ -94,7 +97,7 @@ export class Skype {
|
|||||||
return {
|
return {
|
||||||
user: await this.getUserParams(puppetId, contact),
|
user: await this.getUserParams(puppetId, contact),
|
||||||
room: await this.getRoomParams(puppetId, conversation),
|
room: await this.getRoomParams(puppetId, conversation),
|
||||||
eventId: (resource as any).clientId, // tslint:disable-line no-any
|
eventId: (resource as any).clientId || resource.native.clientmessageid || resource.id, // tslint:disable-line no-any
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +130,7 @@ export class Skype {
|
|||||||
});
|
});
|
||||||
client.on("file", async (resource: skypeHttp.resources.FileResource) => {
|
client.on("file", async (resource: skypeHttp.resources.FileResource) => {
|
||||||
try {
|
try {
|
||||||
|
await this.handleSkypeFile(puppetId, resource);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling file event", err);
|
log.error("Error while handling file event", err);
|
||||||
}
|
}
|
||||||
@ -148,9 +151,11 @@ export class Skype {
|
|||||||
await this.deletePuppet(puppetId);
|
await this.deletePuppet(puppetId);
|
||||||
}
|
}
|
||||||
const client = new Client(data.username, data.password);
|
const client = new Client(data.username, data.password);
|
||||||
|
const TWO_MIN = 120000;
|
||||||
this.puppets[puppetId] = {
|
this.puppets[puppetId] = {
|
||||||
client,
|
client,
|
||||||
data,
|
data,
|
||||||
|
deletedMessages: new ExpireSet(TWO_MIN),
|
||||||
};
|
};
|
||||||
await this.startClient(puppetId);
|
await this.startClient(puppetId);
|
||||||
}
|
}
|
||||||
@ -213,6 +218,7 @@ export class Skype {
|
|||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
log.info("Received message from matrix");
|
||||||
const conversation = await p.client.getConversation(room);
|
const conversation = await p.client.getConversation(room);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
log.warn(`Room ${room.roomId} not found!`);
|
log.warn(`Room ${room.roomId} not found!`);
|
||||||
@ -227,10 +233,99 @@ export class Skype {
|
|||||||
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||||
this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
|
this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
|
||||||
const ret = await p.client.sendMessage(conversation.id, msg);
|
const ret = await p.client.sendMessage(conversation.id, msg);
|
||||||
const eventId = ret && ret.clientMessageId;
|
const dedupeId = ret && ret.clientMessageId;
|
||||||
this.messageDeduplicator.unlock(dedupeKey, p.client.username, eventId);
|
const eventId = ret && ret.MessageId;
|
||||||
|
this.messageDeduplicator.unlock(dedupeKey, p.client.username, dedupeId);
|
||||||
if (eventId) {
|
if (eventId) {
|
||||||
await this.puppet.eventStore.insert(room.puppetId, data.eventId!, eventId);
|
await this.puppet.eventSync.insert(room.puppetId, data.eventId!, eventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixEdit(room: IRemoteRoom, eventId: string, data: IMessageEvent) {
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("Received edit from matrix");
|
||||||
|
const conversation = await p.client.getConversation(room);
|
||||||
|
if (!conversation) {
|
||||||
|
log.warn(`Room ${room.roomId} not found!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let msg: string;
|
||||||
|
if (data.formattedBody) {
|
||||||
|
msg = data.formattedBody;
|
||||||
|
} else {
|
||||||
|
msg = escapeHtml(data.body);
|
||||||
|
}
|
||||||
|
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||||
|
this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
|
||||||
|
await p.client.sendEdit(conversation.id, eventId, msg);
|
||||||
|
const newEventId = "";
|
||||||
|
this.messageDeduplicator.unlock(dedupeKey, p.client.username, newEventId);
|
||||||
|
if (newEventId) {
|
||||||
|
await this.puppet.eventSync.insert(room.puppetId, data.eventId!, newEventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixRedact(room: IRemoteRoom, eventId: string) {
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("Received edit from matrix");
|
||||||
|
const conversation = await p.client.getConversation(room);
|
||||||
|
if (!conversation) {
|
||||||
|
log.warn(`Room ${room.roomId} not found!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.deletedMessages.add(eventId);
|
||||||
|
await p.client.sendDelete(conversation.id, eventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixImage(room: IRemoteRoom, data: IFileEvent) {
|
||||||
|
await this.handleMatrixFile(room, data, "sendImage");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixAudio(room: IRemoteRoom, data: IFileEvent) {
|
||||||
|
await this.handleMatrixFile(room, data, "sendAudio");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixFile(room: IRemoteRoom, data: IFileEvent, method?: string) {
|
||||||
|
if (!method) {
|
||||||
|
method = "sendDocument";
|
||||||
|
}
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("Received file from matrix");
|
||||||
|
const conversation = await p.client.getConversation(room);
|
||||||
|
if (!conversation) {
|
||||||
|
log.warn(`Room ${room.roomId} not found!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const buffer = await Util.DownloadFile(data.url);
|
||||||
|
const opts: SkypeNewMediaMessage = {
|
||||||
|
file: buffer,
|
||||||
|
name: data.filename,
|
||||||
|
};
|
||||||
|
if (data.info) {
|
||||||
|
if (data.info.w) {
|
||||||
|
opts.width = data.info.w;
|
||||||
|
}
|
||||||
|
if (data.info.h) {
|
||||||
|
opts.height = data.info.h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||||
|
this.messageDeduplicator.lock(dedupeKey, p.client.username, `file:${data.filename}`);
|
||||||
|
const ret = await p.client[method](conversation.id, opts);
|
||||||
|
const dedupeId = ret && ret.clientMessageId;
|
||||||
|
const eventId = ret && ret.MessageId;
|
||||||
|
this.messageDeduplicator.unlock(dedupeKey, p.client.username, dedupeId);
|
||||||
|
if (eventId) {
|
||||||
|
await this.puppet.eventSync.insert(room.puppetId, data.eventId!, eventId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,28 +345,71 @@ export class Skype {
|
|||||||
log.warn("Couldn't generate params");
|
log.warn("Couldn't generate params");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let msg = resource.content;
|
||||||
|
let emote = false;
|
||||||
|
if (resource.native && resource.native.skypeemoteoffset) {
|
||||||
|
emote = true;
|
||||||
|
msg = msg.substr(Number(resource.native.skypeemoteoffset));
|
||||||
|
}
|
||||||
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
||||||
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, resource.content)) {
|
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, msg)) {
|
||||||
|
log.silly("normal message dedupe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!rich) {
|
if (!rich) {
|
||||||
await this.puppet.sendMessage(params, {
|
await this.puppet.sendMessage(params, {
|
||||||
body: resource.content,
|
body: msg,
|
||||||
|
emote,
|
||||||
});
|
});
|
||||||
} else if (resource.native && resource.native.skypeeditedid) {
|
} else if (resource.native && resource.native.skypeeditedid) {
|
||||||
if (resource.content) {
|
if (resource.content) {
|
||||||
await this.puppet.sendEdit(params, resource.native.skypeeditedid, {
|
await this.puppet.sendEdit(params, resource.native.skypeeditedid, {
|
||||||
body: resource.content,
|
body: msg,
|
||||||
formattedBody: resource.content,
|
formattedBody: msg,
|
||||||
|
emote,
|
||||||
});
|
});
|
||||||
|
} else if (p.deletedMessages.has(resource.native.skypeeditedid)) {
|
||||||
|
log.silly("normal message redact dedupe");
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
await this.puppet.sendRedact(params, resource.native.skypeeditedid);
|
await this.puppet.sendRedact(params, resource.native.skypeeditedid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await this.puppet.sendMessage(params, {
|
await this.puppet.sendMessage(params, {
|
||||||
body: resource.content,
|
body: msg,
|
||||||
formattedBody: resource.content,
|
formattedBody: msg,
|
||||||
|
emote,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handleSkypeFile(puppetId: number, resource: skypeHttp.resources.FileResource) {
|
||||||
|
const p = this.puppets[puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("Got new skype file");
|
||||||
|
log.silly(resource);
|
||||||
|
const params = await this.getSendParams(puppetId, resource);
|
||||||
|
if (!params) {
|
||||||
|
log.warn("Couldn't generate params");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filename = resource.original_file_name;
|
||||||
|
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
||||||
|
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, `file:${filename}`)) {
|
||||||
|
log.silly("file message dedupe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resource.native && resource.native.skypeeditedid && !resource.uri) {
|
||||||
|
if (p.deletedMessages.has(resource.native.skypeeditedid)) {
|
||||||
|
log.silly("file message redact dedupe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.puppet.sendRedact(params, resource.native.skypeeditedid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const buffer = await p.client.downloadFile(resource.uri);
|
||||||
|
await this.puppet.sendFileDetect(params, buffer, filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user