mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-11-14 15:31: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.
|
||||
*/
|
||||
|
||||
import { Log, ExpireSet, IRemoteRoom } from "mx-puppet-bridge";
|
||||
import { Log, ExpireSet, IRemoteRoom, Util } from "mx-puppet-bridge";
|
||||
import { EventEmitter } from "events";
|
||||
import * as skypeHttp from "skype-http";
|
||||
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");
|
||||
|
||||
@ -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> {
|
||||
return await this.api.sendMessage({
|
||||
textContent: msg,
|
||||
}, 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 = {
|
||||
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
|
||||
edit: true,
|
||||
globalNamespace: true,
|
||||
},
|
||||
id: "skype",
|
||||
@ -91,6 +94,11 @@ async function run() {
|
||||
puppet.on("puppetNew", skype.newPuppet.bind(skype));
|
||||
puppet.on("puppetDelete", skype.deletePuppet.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.setCreateRoomHook(skype.createRoom.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.
|
||||
*/
|
||||
import {
|
||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator,
|
||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
||||
ExpireSet,
|
||||
} from "mx-puppet-bridge";
|
||||
import { Client } from "./client";
|
||||
import * as skypeHttp from "skype-http";
|
||||
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 escapeHtml from "escape-html";
|
||||
|
||||
@ -24,6 +26,7 @@ const log = new Log("SkypePuppet:skype");
|
||||
interface ISkypePuppet {
|
||||
client: Client;
|
||||
data: any;
|
||||
deletedMessages: ExpireSet<string>;
|
||||
}
|
||||
|
||||
interface ISkypePuppets {
|
||||
@ -94,7 +97,7 @@ export class Skype {
|
||||
return {
|
||||
user: await this.getUserParams(puppetId, contact),
|
||||
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) => {
|
||||
try {
|
||||
|
||||
await this.handleSkypeFile(puppetId, resource);
|
||||
} catch (err) {
|
||||
log.error("Error while handling file event", err);
|
||||
}
|
||||
@ -148,9 +151,11 @@ export class Skype {
|
||||
await this.deletePuppet(puppetId);
|
||||
}
|
||||
const client = new Client(data.username, data.password);
|
||||
const TWO_MIN = 120000;
|
||||
this.puppets[puppetId] = {
|
||||
client,
|
||||
data,
|
||||
deletedMessages: new ExpireSet(TWO_MIN),
|
||||
};
|
||||
await this.startClient(puppetId);
|
||||
}
|
||||
@ -213,6 +218,7 @@ export class Skype {
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
log.info("Received message from matrix");
|
||||
const conversation = await p.client.getConversation(room);
|
||||
if (!conversation) {
|
||||
log.warn(`Room ${room.roomId} not found!`);
|
||||
@ -227,10 +233,99 @@ export class Skype {
|
||||
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||
this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
|
||||
const ret = await p.client.sendMessage(conversation.id, msg);
|
||||
const eventId = ret && ret.clientMessageId;
|
||||
this.messageDeduplicator.unlock(dedupeKey, p.client.username, eventId);
|
||||
const dedupeId = ret && ret.clientMessageId;
|
||||
const eventId = ret && ret.MessageId;
|
||||
this.messageDeduplicator.unlock(dedupeKey, p.client.username, dedupeId);
|
||||
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");
|
||||
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}`;
|
||||
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;
|
||||
}
|
||||
if (!rich) {
|
||||
await this.puppet.sendMessage(params, {
|
||||
body: resource.content,
|
||||
body: msg,
|
||||
emote,
|
||||
});
|
||||
} else if (resource.native && resource.native.skypeeditedid) {
|
||||
if (resource.content) {
|
||||
await this.puppet.sendEdit(params, resource.native.skypeeditedid, {
|
||||
body: resource.content,
|
||||
formattedBody: resource.content,
|
||||
body: msg,
|
||||
formattedBody: msg,
|
||||
emote,
|
||||
});
|
||||
} else if (p.deletedMessages.has(resource.native.skypeeditedid)) {
|
||||
log.silly("normal message redact dedupe");
|
||||
return;
|
||||
} else {
|
||||
await this.puppet.sendRedact(params, resource.native.skypeeditedid);
|
||||
}
|
||||
} else {
|
||||
await this.puppet.sendMessage(params, {
|
||||
body: resource.content,
|
||||
formattedBody: resource.content,
|
||||
body: msg,
|
||||
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