mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-12-27 17:11:40 +00:00
state handling
This commit is contained in:
parent
5bc2c64859
commit
251775e93f
@ -16,19 +16,21 @@ 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";
|
||||
import { Context as SkypeContext } from "skype-http/dist/lib/interfaces/api/context";
|
||||
|
||||
const log = new Log("SkypePuppet:client");
|
||||
|
||||
const ID_TIMEOUT = 60 * 1000;
|
||||
const ID_TIMEOUT = 60000;
|
||||
|
||||
export class Client extends EventEmitter {
|
||||
public contacts: Map<string, SkypeContact | null> = new Map();
|
||||
public conversations: Map<string, skypeHttp.Conversation | null> = new Map();
|
||||
private api: skypeHttp.Api;
|
||||
private handledIds: ExpireSet<string>;
|
||||
private contacts: Map<String, SkypeContact | null> = new Map();
|
||||
private conversations: Map<String, skypeHttp.Conversation | null> = new Map();
|
||||
constructor(
|
||||
private loginUsername: string,
|
||||
private password: string,
|
||||
private state?: SkypeContext.Json,
|
||||
) {
|
||||
super();
|
||||
this.handledIds = new ExpireSet(ID_TIMEOUT);
|
||||
@ -38,14 +40,32 @@ export class Client extends EventEmitter {
|
||||
return "8:" + this.api.context.username;
|
||||
}
|
||||
|
||||
public get getState(): SkypeContext.Json {
|
||||
return this.api.getState();
|
||||
}
|
||||
|
||||
public async connect() {
|
||||
this.api = await skypeHttp.connect({
|
||||
credentials: {
|
||||
username: this.loginUsername,
|
||||
password: this.password,
|
||||
},
|
||||
verbose: true,
|
||||
});
|
||||
if (this.state) {
|
||||
try {
|
||||
this.api = await skypeHttp.connect({ state: this.state, verbose: true });
|
||||
} catch (err) {
|
||||
this.api = await skypeHttp.connect({
|
||||
credentials: {
|
||||
username: this.loginUsername,
|
||||
password: this.password,
|
||||
},
|
||||
verbose: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.api = await skypeHttp.connect({
|
||||
credentials: {
|
||||
username: this.loginUsername,
|
||||
password: this.password,
|
||||
},
|
||||
verbose: true,
|
||||
});
|
||||
}
|
||||
|
||||
this.api.on("event", (evt: skypeHttp.events.EventMessage) => {
|
||||
if (!evt || !evt.resource) {
|
||||
@ -86,6 +106,7 @@ export class Client extends EventEmitter {
|
||||
|
||||
this.api.on("error", (err: Error) => {
|
||||
log.error("An error occured", err);
|
||||
this.emit("error", err);
|
||||
});
|
||||
|
||||
await this.api.listen();
|
||||
@ -116,7 +137,7 @@ export class Client extends EventEmitter {
|
||||
return this.contacts.get(fullId) || null;
|
||||
}
|
||||
if (hasStart) {
|
||||
id = id.substr(id.indexOf(":")+1);
|
||||
id = id.substr(id.indexOf(":") + 1);
|
||||
}
|
||||
try {
|
||||
const rawContact = await this.api.getContact(id);
|
||||
@ -177,7 +198,7 @@ export class Client extends EventEmitter {
|
||||
}
|
||||
return await Util.DownloadFile(url, {
|
||||
cookies: this.api.context.cookies,
|
||||
headers: { Authorization: 'skype_token ' + this.api.context.skypeToken.value },
|
||||
headers: { Authorization: "skype_token " + this.api.context.skypeToken.value },
|
||||
});
|
||||
}
|
||||
|
||||
@ -206,14 +227,14 @@ export class Client extends EventEmitter {
|
||||
|
||||
public async sendDocument(
|
||||
conversationId: string,
|
||||
opts: SkypeNewMediaMessage
|
||||
opts: SkypeNewMediaMessage,
|
||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||
return await this.api.sendDocument(opts, conversationId);
|
||||
}
|
||||
|
||||
public async sendImage(
|
||||
conversationId: string,
|
||||
opts: SkypeNewMediaMessage
|
||||
opts: SkypeNewMediaMessage,
|
||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||
return await this.api.sendImage(opts, conversationId);
|
||||
}
|
||||
|
11
src/index.ts
11
src/index.ts
@ -61,7 +61,6 @@ const protocol: IProtocolInformation = {
|
||||
image: true,
|
||||
audio: true,
|
||||
file: true,
|
||||
// presence: true, // we want to be able to send presence
|
||||
edit: true,
|
||||
globalNamespace: true,
|
||||
},
|
||||
@ -101,7 +100,17 @@ async function run() {
|
||||
puppet.on("file", skype.handleMatrixFile.bind(skype));
|
||||
puppet.setCreateUserHook(skype.createUser.bind(skype));
|
||||
puppet.setCreateRoomHook(skype.createRoom.bind(skype));
|
||||
puppet.setGetDmRoomIdHook(skype.getDmRoom.bind(skype));
|
||||
puppet.setListUsersHook(skype.listUsers.bind(skype));
|
||||
puppet.setListRoomsHook(skype.listRooms.bind(skype));
|
||||
puppet.setGetUserIdsInRoomHook(skype.getUserIdsInRoom.bind(skype));
|
||||
puppet.setGetDescHook(async (puppetId: number, data: any): Promise<string> => {
|
||||
let s = "Skype";
|
||||
if (data.username) {
|
||||
s += ` as \`${data.username.substr("8:".length)}\``;
|
||||
}
|
||||
return s;
|
||||
});
|
||||
puppet.setGetDataFromStrHook(async (str: string): Promise<IRetData> => {
|
||||
const retData = {
|
||||
success: false,
|
||||
|
100
src/skype.ts
100
src/skype.ts
@ -12,7 +12,7 @@ limitations under the License.
|
||||
*/
|
||||
import {
|
||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
||||
ExpireSet,
|
||||
ExpireSet, IRetList,
|
||||
} from "mx-puppet-bridge";
|
||||
import { Client } from "./client";
|
||||
import * as skypeHttp from "skype-http";
|
||||
@ -23,6 +23,8 @@ import * as escapeHtml from "escape-html";
|
||||
|
||||
const log = new Log("SkypePuppet:skype");
|
||||
|
||||
const ROOM_TYPE_DM = 8;
|
||||
|
||||
interface ISkypePuppet {
|
||||
client: Client;
|
||||
data: any;
|
||||
@ -53,12 +55,11 @@ export class Skype {
|
||||
|
||||
public getRoomParams(puppetId: number, conversation: skypeHttp.Conversation): IRemoteRoom {
|
||||
const roomType = Number(conversation.id.split(":")[0]);
|
||||
let roomId = conversation.id;
|
||||
const isDirect = roomType === 8;
|
||||
const isDirect = roomType === ROOM_TYPE_DM;
|
||||
if (isDirect) {
|
||||
return {
|
||||
puppetId,
|
||||
roomId: `dm-${puppetId}-${roomId}`,
|
||||
roomId: `dm-${puppetId}-${conversation.id}`,
|
||||
isDirect: true,
|
||||
};
|
||||
}
|
||||
@ -76,7 +77,7 @@ export class Skype {
|
||||
}
|
||||
return {
|
||||
puppetId,
|
||||
roomId,
|
||||
roomId: conversation.id,
|
||||
name,
|
||||
avatarUrl,
|
||||
};
|
||||
@ -84,7 +85,6 @@ export class Skype {
|
||||
|
||||
public async getSendParams(puppetId: number, resource: skypeHttp.resources.Resource): Promise<IReceiveParams | null> {
|
||||
const roomType = Number(resource.conversation.split(":")[0]);
|
||||
let roomId = resource.conversation;
|
||||
const p = this.puppets[puppetId];
|
||||
const contact = await p.client.getContact(resource.from.raw);
|
||||
const conversation = await p.client.getConversation({
|
||||
@ -95,18 +95,26 @@ export class Skype {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
user: await this.getUserParams(puppetId, contact),
|
||||
room: await this.getRoomParams(puppetId, conversation),
|
||||
user: this.getUserParams(puppetId, contact),
|
||||
room: this.getRoomParams(puppetId, conversation),
|
||||
eventId: (resource as any).clientId || resource.native.clientmessageid || resource.id, // tslint:disable-line no-any
|
||||
};
|
||||
}
|
||||
|
||||
public async stopClient(puppetId: number) {
|
||||
const p = this.puppets[puppetId];
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
await p.client.disconnect();
|
||||
}
|
||||
|
||||
public async startClient(puppetId: number) {
|
||||
const p = this.puppets[puppetId];
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
p.client = new Client(p.data.username, p.data.password);
|
||||
p.client = new Client(p.data.username, p.data.password, p.data.state);
|
||||
const client = p.client;
|
||||
client.on("text", async (resource: skypeHttp.resources.TextResource) => {
|
||||
try {
|
||||
@ -124,7 +132,7 @@ export class Skype {
|
||||
});
|
||||
client.on("location", async (resource: skypeHttp.resources.RichTextLocationResource) => {
|
||||
try {
|
||||
|
||||
|
||||
} catch (err) {
|
||||
log.error("Error while handling location event", err);
|
||||
}
|
||||
@ -150,8 +158,28 @@ export class Skype {
|
||||
log.error("Error while handling presence event", err);
|
||||
}
|
||||
});
|
||||
await client.connect();
|
||||
await this.puppet.setUserId(puppetId, client.username);
|
||||
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);
|
||||
setTimeout(async () => {
|
||||
await this.stopClient(puppetId);
|
||||
await this.startClient(puppetId);
|
||||
}, MINUTE);
|
||||
});
|
||||
try {
|
||||
await client.connect();
|
||||
await this.puppet.setUserId(puppetId, client.username);
|
||||
p.data.state = client.getState;
|
||||
await this.puppet.setPuppetData(puppetId, p.data);
|
||||
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);
|
||||
setTimeout(async () => {
|
||||
await this.startClient(puppetId);
|
||||
}, MINUTE);
|
||||
}
|
||||
}
|
||||
|
||||
public async newPuppet(puppetId: number, data: any) {
|
||||
@ -203,6 +231,54 @@ export class Skype {
|
||||
return this.getRoomParams(room.puppetId, conversation);
|
||||
}
|
||||
|
||||
public async getDmRoom(remoteUser: IRemoteUser): Promise<string | null> {
|
||||
const p = this.puppets[remoteUser.puppetId];
|
||||
if (!p) {
|
||||
return null;
|
||||
}
|
||||
const contact = await p.client.getContact(remoteUser.userId);
|
||||
if (!contact) {
|
||||
return null;
|
||||
}
|
||||
return `dm-${remoteUser.puppetId}-${contact.mri}`;
|
||||
}
|
||||
|
||||
public async listUsers(puppetId: number): Promise<IRetList[]> {
|
||||
const p = this.puppets[puppetId];
|
||||
if (!p) {
|
||||
return [];
|
||||
}
|
||||
const reply: IRetList[] = [];
|
||||
for (const [, contact] of p.client.contacts) {
|
||||
if (!contact) {
|
||||
continue;
|
||||
}
|
||||
reply.push({
|
||||
id: contact.mri,
|
||||
name: contact.displayName,
|
||||
});
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
public async listRooms(puppetId: number): Promise<IRetList[]> {
|
||||
const p = this.puppets[puppetId];
|
||||
if (!p) {
|
||||
return [];
|
||||
}
|
||||
const reply: IRetList[] = [];
|
||||
for (const [, conversation] of p.client.conversations) {
|
||||
if (!conversation || conversation.id.startsWith("8:")) {
|
||||
continue;
|
||||
}
|
||||
reply.push({
|
||||
id: conversation.id,
|
||||
name: (conversation.threadProperties && conversation.threadProperties.topic) || "",
|
||||
});
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
public async getUserIdsInRoom(room: IRemoteRoom): Promise<Set<string> | null> {
|
||||
const p = this.puppets[room.puppetId];
|
||||
if (!p) {
|
||||
|
Loading…
Reference in New Issue
Block a user