mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-12-27 17:11:40 +00:00
add message parsers
This commit is contained in:
parent
19020890e1
commit
416df718bd
13
package-lock.json
generated
13
package-lock.json
generated
@ -2123,6 +2123,11 @@
|
||||
"type-fest": "^0.8.0"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
|
||||
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
|
||||
},
|
||||
"htmlencode": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/htmlencode/-/htmlencode-0.0.4.tgz",
|
||||
@ -2858,6 +2863,14 @@
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"node-html-parser": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.2.13.tgz",
|
||||
"integrity": "sha512-RTG5oDk3nh1oXQGYtQQa9w0v9LjltgzzO1tv3cpXzb9M/UkpFIZ5v4osx3OYAcnWx/ETBXjxs2cgtD9fhn6Bjw==",
|
||||
"requires": {
|
||||
"he": "1.1.1"
|
||||
}
|
||||
},
|
||||
"noop-logger": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"events": "^3.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"mx-puppet-bridge": "0.0.35-1",
|
||||
"node-html-parser": "^1.2.13",
|
||||
"skype-http": "git://github.com/Sorunome/skype-http#10555125f46307bbff93a8c4779889f4100669d2",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "^3.7.4"
|
||||
|
@ -45,9 +45,11 @@ export class Client extends EventEmitter {
|
||||
}
|
||||
|
||||
public async connect() {
|
||||
if (this.state) {
|
||||
let connectedWithAuth = false;
|
||||
if (this.state && false) {
|
||||
try {
|
||||
this.api = await skypeHttp.connect({ state: this.state, verbose: true });
|
||||
connectedWithAuth = true;
|
||||
} catch (err) {
|
||||
this.api = await skypeHttp.connect({
|
||||
credentials: {
|
||||
@ -56,6 +58,7 @@ export class Client extends EventEmitter {
|
||||
},
|
||||
verbose: true,
|
||||
});
|
||||
connectedWithAuth = false;
|
||||
}
|
||||
} else {
|
||||
this.api = await skypeHttp.connect({
|
||||
@ -65,6 +68,7 @@ export class Client extends EventEmitter {
|
||||
},
|
||||
verbose: true,
|
||||
});
|
||||
connectedWithAuth = false;
|
||||
}
|
||||
|
||||
this.api.on("event", (evt: skypeHttp.events.EventMessage) => {
|
||||
@ -109,21 +113,17 @@ export class Client extends EventEmitter {
|
||||
this.emit("error", err);
|
||||
});
|
||||
|
||||
const contacts = await this.api.getContacts();
|
||||
for (const contact of contacts) {
|
||||
this.contacts.set(contact.mri, contact);
|
||||
}
|
||||
const conversations = await this.api.getConversations();
|
||||
for (const conversation of conversations) {
|
||||
this.conversations.set(conversation.id, conversation);
|
||||
}
|
||||
|
||||
await this.api.listen();
|
||||
await this.api.setStatus("Online");
|
||||
|
||||
try {
|
||||
const contacts = await this.api.getContacts();
|
||||
for (const contact of contacts) {
|
||||
this.contacts.set(contact.mri, contact);
|
||||
}
|
||||
const conversations = await this.api.getConversations();
|
||||
for (const conversation of conversations) {
|
||||
this.conversations.set(conversation.id, conversation);
|
||||
}
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async disconnect() {
|
||||
|
66
src/matrixmessageparser.ts
Normal file
66
src/matrixmessageparser.ts
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2020 mx-puppet-skype
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Parser from "node-html-parser";
|
||||
import * as escapeHtml from "escape-html";
|
||||
|
||||
export class MatrixMessageParser {
|
||||
public parse(msg: string): string {
|
||||
const nodes = Parser.parse(`<wrap>${msg}</wrap>`, {
|
||||
lowerCaseTagName: true,
|
||||
pre: true,
|
||||
});
|
||||
return this.walkNode(nodes);
|
||||
}
|
||||
|
||||
private walkChildNodes(node: Parser.Node): string {
|
||||
return node.childNodes.map((node) => this.walkNode(node)).join("");
|
||||
}
|
||||
|
||||
private escape(s: string): string {
|
||||
return s;
|
||||
}
|
||||
|
||||
private walkNode(node: Parser.Node): string {
|
||||
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
|
||||
return this.escape((node as Parser.TextNode).text);
|
||||
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
|
||||
const nodeHtml = node as Parser.HTMLElement;
|
||||
switch (nodeHtml.tagName) {
|
||||
case "em":
|
||||
case "i":
|
||||
return `<i raw_pre="_" raw_post="_">${this.walkChildNodes(nodeHtml)}</i>`;
|
||||
case "strong":
|
||||
case "b":
|
||||
return `<b raw_pre="*" raw_post="*">${this.walkChildNodes(nodeHtml)}</b>`;
|
||||
case "del":
|
||||
return `<s raw_pre="~" raw_post="~">${this.walkChildNodes(nodeHtml)}</s>`;
|
||||
case "code":
|
||||
return `<pre raw_pre="{code}" raw_post="{code}">${this.walkChildNodes(nodeHtml)}</pre>`;
|
||||
case "a": {
|
||||
const href = nodeHtml.attributes.href;
|
||||
const inner = this.walkChildNodes(nodeHtml);
|
||||
return `<a href="${escapeHtml(href)}">${inner}</a>`;
|
||||
}
|
||||
case "wrap":
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
default:
|
||||
if (!nodeHtml.tagName) {
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
}
|
||||
return `<${nodeHtml.tagName}>${this.walkChildNodes(nodeHtml)}</${nodeHtml.tagName}>`;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
45
src/skype.ts
45
src/skype.ts
@ -10,6 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
||||
ExpireSet, IRetList,
|
||||
@ -20,6 +21,8 @@ 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";
|
||||
import { MatrixMessageParser } from "./matrixmessageparser";
|
||||
import { SkypeMessageParser } from "./skypemessageparser";
|
||||
|
||||
const log = new Log("SkypePuppet:skype");
|
||||
|
||||
@ -38,10 +41,14 @@ interface ISkypePuppets {
|
||||
export class Skype {
|
||||
private puppets: ISkypePuppets = {};
|
||||
private messageDeduplicator: MessageDeduplicator;
|
||||
private matrixMessageParser: MatrixMessageParser;
|
||||
private skypeMessageParser: SkypeMessageParser;
|
||||
constructor(
|
||||
private puppet: PuppetBridge,
|
||||
) {
|
||||
this.messageDeduplicator = new MessageDeduplicator();
|
||||
this.matrixMessageParser = new MatrixMessageParser();
|
||||
this.skypeMessageParser = new SkypeMessageParser();
|
||||
}
|
||||
|
||||
public getUserParams(puppetId: number, contact: SkypeContact): IRemoteUser {
|
||||
@ -160,8 +167,8 @@ export class Skype {
|
||||
});
|
||||
const MINUTE = 60000;
|
||||
client.on("error", async (err: Error) => {
|
||||
await this.puppet.sendStatusMessage(puppetId, "Error:" + err);
|
||||
await this.puppet.sendStatusMessage(puppetId, "Reconnecting in a minute... " + err.message);
|
||||
await this.puppet.sendStatusMessage(puppetId, "Error: " + err);
|
||||
await this.puppet.sendStatusMessage(puppetId, "Reconnecting in a minute... ");
|
||||
setTimeout(async () => {
|
||||
await this.stopClient(puppetId);
|
||||
await this.startClient(puppetId);
|
||||
@ -175,7 +182,7 @@ export class Skype {
|
||||
await this.puppet.sendStatusMessage(puppetId, "connected");
|
||||
} catch (err) {
|
||||
log.error("Failed to connect", err);
|
||||
await this.puppet.sendStatusMessage(puppetId, "Failed to connect, reconnecting in a minute... " + err.message);
|
||||
await this.puppet.sendStatusMessage(puppetId, "Failed to connect, reconnecting in a minute... " + err);
|
||||
setTimeout(async () => {
|
||||
await this.startClient(puppetId);
|
||||
}, MINUTE);
|
||||
@ -310,7 +317,7 @@ export class Skype {
|
||||
}
|
||||
let msg: string;
|
||||
if (data.formattedBody) {
|
||||
msg = data.formattedBody;
|
||||
msg = this.matrixMessageParser.parse(data.formattedBody);
|
||||
} else {
|
||||
msg = escapeHtml(data.body);
|
||||
}
|
||||
@ -338,7 +345,7 @@ export class Skype {
|
||||
}
|
||||
let msg: string;
|
||||
if (data.formattedBody) {
|
||||
msg = data.formattedBody;
|
||||
msg = this.matrixMessageParser.parse(data.formattedBody);
|
||||
} else {
|
||||
msg = escapeHtml(data.body);
|
||||
}
|
||||
@ -440,18 +447,20 @@ export class Skype {
|
||||
log.silly("normal message dedupe");
|
||||
return;
|
||||
}
|
||||
if (!rich) {
|
||||
await this.puppet.sendMessage(params, {
|
||||
let sendMsg: IMessageEvent;
|
||||
if (rich) {
|
||||
sendMsg = this.skypeMessageParser.parse(msg);
|
||||
} else {
|
||||
sendMsg = {
|
||||
body: msg,
|
||||
emote,
|
||||
});
|
||||
} else if (resource.native && resource.native.skypeeditedid) {
|
||||
};
|
||||
}
|
||||
if (emote) {
|
||||
sendMsg.emote = true;
|
||||
}
|
||||
if (resource.native && resource.native.skypeeditedid) {
|
||||
if (resource.content) {
|
||||
await this.puppet.sendEdit(params, resource.native.skypeeditedid, {
|
||||
body: msg,
|
||||
formattedBody: msg,
|
||||
emote,
|
||||
});
|
||||
await this.puppet.sendEdit(params, resource.native.skypeeditedid, sendMsg);
|
||||
} else if (p.deletedMessages.has(resource.native.skypeeditedid)) {
|
||||
log.silly("normal message redact dedupe");
|
||||
return;
|
||||
@ -459,11 +468,7 @@ export class Skype {
|
||||
await this.puppet.sendRedact(params, resource.native.skypeeditedid);
|
||||
}
|
||||
} else {
|
||||
await this.puppet.sendMessage(params, {
|
||||
body: msg,
|
||||
formattedBody: msg,
|
||||
emote,
|
||||
});
|
||||
await this.puppet.sendMessage(params, sendMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
100
src/skypemessageparser.ts
Normal file
100
src/skypemessageparser.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright 2020 mx-puppet-skype
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Parser from "node-html-parser";
|
||||
import * as decodeHtml from "decode-html";
|
||||
import * as escapeHtml from "escape-html";
|
||||
import { IMessageEvent } from "mx-puppet-bridge";
|
||||
|
||||
export class SkypeMessageParser {
|
||||
public parse(msg: string): IMessageEvent {
|
||||
const nodes = Parser.parse(`<wrap>${msg}</wrap>`, {
|
||||
lowerCaseTagName: true,
|
||||
pre: true,
|
||||
});
|
||||
return this.walkNode(nodes);
|
||||
}
|
||||
|
||||
private walkChildNodes(node: Parser.Node): IMessageEvent {
|
||||
return node.childNodes.map((node) => this.walkNode(node)).reduce((acc, curr) => {
|
||||
return {
|
||||
body: acc.body + curr.body,
|
||||
formattedBody: acc.formattedBody! + curr.formattedBody!,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private escape(s: string): IMessageEvent {
|
||||
return {
|
||||
body: decodeHtml(s),
|
||||
formattedBody: s.replace("\n", "<br>"),
|
||||
};
|
||||
}
|
||||
|
||||
private walkNode(node: Parser.Node): IMessageEvent {
|
||||
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
|
||||
return this.escape((node as Parser.TextNode).text);
|
||||
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
|
||||
const nodeHtml = node as Parser.HTMLElement;
|
||||
switch (nodeHtml.tagName) {
|
||||
case "i": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
return {
|
||||
body: `_${child.body}_`,
|
||||
formattedBody: `<em>${child.formattedBody}</em>`,
|
||||
};
|
||||
}
|
||||
case "b": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
return {
|
||||
body: `*${child.body}*`,
|
||||
formattedBody: `<strong>${child.formattedBody}</strong>`,
|
||||
};
|
||||
}
|
||||
case "s": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
return {
|
||||
body: `~${child.body}~`,
|
||||
formattedBody: `<del>${child.formattedBody}</del>`,
|
||||
};
|
||||
}
|
||||
case "pre": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
return {
|
||||
body: `{code}${child.body}{code}`,
|
||||
formattedBody: `<code>${child.formattedBody}</code>`,
|
||||
};
|
||||
}
|
||||
case "a": {
|
||||
const href = nodeHtml.attributes.href;
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
return {
|
||||
body: child.body === href ? href : `[${child.body}](${href})`,
|
||||
formattedBody: `<a href="${escapeHtml(href)}">${child.formattedBody}</a>`,
|
||||
};
|
||||
}
|
||||
case "e_m":
|
||||
return {
|
||||
body: "",
|
||||
formattedBody: "",
|
||||
};
|
||||
default:
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
}
|
||||
}
|
||||
return {
|
||||
body: "",
|
||||
formattedBody: "",
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user