mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-11-14 23:41: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 * 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 { 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 log = new Log("SkypePuppet:client");
|
||||||
|
|
||||||
const ID_TIMEOUT = 60 * 1000;
|
const ID_TIMEOUT = 60000;
|
||||||
|
|
||||||
export class Client extends EventEmitter {
|
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 api: skypeHttp.Api;
|
||||||
private handledIds: ExpireSet<string>;
|
private handledIds: ExpireSet<string>;
|
||||||
private contacts: Map<String, SkypeContact | null> = new Map();
|
|
||||||
private conversations: Map<String, skypeHttp.Conversation | null> = new Map();
|
|
||||||
constructor(
|
constructor(
|
||||||
private loginUsername: string,
|
private loginUsername: string,
|
||||||
private password: string,
|
private password: string,
|
||||||
|
private state?: SkypeContext.Json,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.handledIds = new ExpireSet(ID_TIMEOUT);
|
this.handledIds = new ExpireSet(ID_TIMEOUT);
|
||||||
@ -38,7 +40,15 @@ export class Client extends EventEmitter {
|
|||||||
return "8:" + this.api.context.username;
|
return "8:" + this.api.context.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get getState(): SkypeContext.Json {
|
||||||
|
return this.api.getState();
|
||||||
|
}
|
||||||
|
|
||||||
public async connect() {
|
public async connect() {
|
||||||
|
if (this.state) {
|
||||||
|
try {
|
||||||
|
this.api = await skypeHttp.connect({ state: this.state, verbose: true });
|
||||||
|
} catch (err) {
|
||||||
this.api = await skypeHttp.connect({
|
this.api = await skypeHttp.connect({
|
||||||
credentials: {
|
credentials: {
|
||||||
username: this.loginUsername,
|
username: this.loginUsername,
|
||||||
@ -46,6 +56,16 @@ export class Client extends EventEmitter {
|
|||||||
},
|
},
|
||||||
verbose: true,
|
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) => {
|
this.api.on("event", (evt: skypeHttp.events.EventMessage) => {
|
||||||
if (!evt || !evt.resource) {
|
if (!evt || !evt.resource) {
|
||||||
@ -86,6 +106,7 @@ export class Client extends EventEmitter {
|
|||||||
|
|
||||||
this.api.on("error", (err: Error) => {
|
this.api.on("error", (err: Error) => {
|
||||||
log.error("An error occured", err);
|
log.error("An error occured", err);
|
||||||
|
this.emit("error", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.api.listen();
|
await this.api.listen();
|
||||||
@ -177,7 +198,7 @@ export class Client extends EventEmitter {
|
|||||||
}
|
}
|
||||||
return await Util.DownloadFile(url, {
|
return await Util.DownloadFile(url, {
|
||||||
cookies: this.api.context.cookies,
|
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(
|
public async sendDocument(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
opts: SkypeNewMediaMessage
|
opts: SkypeNewMediaMessage,
|
||||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
return await this.api.sendDocument(opts, conversationId);
|
return await this.api.sendDocument(opts, conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendImage(
|
public async sendImage(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
opts: SkypeNewMediaMessage
|
opts: SkypeNewMediaMessage,
|
||||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
): Promise<skypeHttp.Api.SendMessageResult> {
|
||||||
return await this.api.sendImage(opts, conversationId);
|
return await this.api.sendImage(opts, conversationId);
|
||||||
}
|
}
|
||||||
|
11
src/index.ts
11
src/index.ts
@ -61,7 +61,6 @@ const protocol: IProtocolInformation = {
|
|||||||
image: true,
|
image: true,
|
||||||
audio: true,
|
audio: true,
|
||||||
file: true,
|
file: true,
|
||||||
// presence: true, // we want to be able to send presence
|
|
||||||
edit: true,
|
edit: true,
|
||||||
globalNamespace: true,
|
globalNamespace: true,
|
||||||
},
|
},
|
||||||
@ -101,7 +100,17 @@ async function run() {
|
|||||||
puppet.on("file", skype.handleMatrixFile.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.setGetDmRoomIdHook(skype.getDmRoom.bind(skype));
|
||||||
|
puppet.setListUsersHook(skype.listUsers.bind(skype));
|
||||||
|
puppet.setListRoomsHook(skype.listRooms.bind(skype));
|
||||||
puppet.setGetUserIdsInRoomHook(skype.getUserIdsInRoom.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> => {
|
puppet.setGetDataFromStrHook(async (str: string): Promise<IRetData> => {
|
||||||
const retData = {
|
const retData = {
|
||||||
success: false,
|
success: false,
|
||||||
|
94
src/skype.ts
94
src/skype.ts
@ -12,7 +12,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
PuppetBridge, IRemoteUser, IRemoteRoom, IReceiveParams, IMessageEvent, IFileEvent, Log, MessageDeduplicator, Util,
|
||||||
ExpireSet,
|
ExpireSet, IRetList,
|
||||||
} 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";
|
||||||
@ -23,6 +23,8 @@ import * as escapeHtml from "escape-html";
|
|||||||
|
|
||||||
const log = new Log("SkypePuppet:skype");
|
const log = new Log("SkypePuppet:skype");
|
||||||
|
|
||||||
|
const ROOM_TYPE_DM = 8;
|
||||||
|
|
||||||
interface ISkypePuppet {
|
interface ISkypePuppet {
|
||||||
client: Client;
|
client: Client;
|
||||||
data: any;
|
data: any;
|
||||||
@ -53,12 +55,11 @@ export class Skype {
|
|||||||
|
|
||||||
public getRoomParams(puppetId: number, conversation: skypeHttp.Conversation): IRemoteRoom {
|
public getRoomParams(puppetId: number, conversation: skypeHttp.Conversation): IRemoteRoom {
|
||||||
const roomType = Number(conversation.id.split(":")[0]);
|
const roomType = Number(conversation.id.split(":")[0]);
|
||||||
let roomId = conversation.id;
|
const isDirect = roomType === ROOM_TYPE_DM;
|
||||||
const isDirect = roomType === 8;
|
|
||||||
if (isDirect) {
|
if (isDirect) {
|
||||||
return {
|
return {
|
||||||
puppetId,
|
puppetId,
|
||||||
roomId: `dm-${puppetId}-${roomId}`,
|
roomId: `dm-${puppetId}-${conversation.id}`,
|
||||||
isDirect: true,
|
isDirect: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -76,7 +77,7 @@ export class Skype {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
puppetId,
|
puppetId,
|
||||||
roomId,
|
roomId: conversation.id,
|
||||||
name,
|
name,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
};
|
};
|
||||||
@ -84,7 +85,6 @@ export class Skype {
|
|||||||
|
|
||||||
public async getSendParams(puppetId: number, resource: skypeHttp.resources.Resource): Promise<IReceiveParams | null> {
|
public async getSendParams(puppetId: number, resource: skypeHttp.resources.Resource): Promise<IReceiveParams | null> {
|
||||||
const roomType = Number(resource.conversation.split(":")[0]);
|
const roomType = Number(resource.conversation.split(":")[0]);
|
||||||
let roomId = resource.conversation;
|
|
||||||
const p = this.puppets[puppetId];
|
const p = this.puppets[puppetId];
|
||||||
const contact = await p.client.getContact(resource.from.raw);
|
const contact = await p.client.getContact(resource.from.raw);
|
||||||
const conversation = await p.client.getConversation({
|
const conversation = await p.client.getConversation({
|
||||||
@ -95,18 +95,26 @@ export class Skype {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
user: await this.getUserParams(puppetId, contact),
|
user: this.getUserParams(puppetId, contact),
|
||||||
room: await this.getRoomParams(puppetId, conversation),
|
room: this.getRoomParams(puppetId, conversation),
|
||||||
eventId: (resource as any).clientId || resource.native.clientmessageid || resource.id, // tslint:disable-line no-any
|
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) {
|
public async startClient(puppetId: number) {
|
||||||
const p = this.puppets[puppetId];
|
const p = this.puppets[puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
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;
|
const client = p.client;
|
||||||
client.on("text", async (resource: skypeHttp.resources.TextResource) => {
|
client.on("text", async (resource: skypeHttp.resources.TextResource) => {
|
||||||
try {
|
try {
|
||||||
@ -150,8 +158,28 @@ export class Skype {
|
|||||||
log.error("Error while handling presence event", err);
|
log.error("Error while handling presence event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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 client.connect();
|
||||||
await this.puppet.setUserId(puppetId, client.username);
|
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) {
|
public async newPuppet(puppetId: number, data: any) {
|
||||||
@ -203,6 +231,54 @@ export class Skype {
|
|||||||
return this.getRoomParams(room.puppetId, conversation);
|
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> {
|
public async getUserIdsInRoom(room: IRemoteRoom): Promise<Set<string> | null> {
|
||||||
const p = this.puppets[room.puppetId];
|
const p = this.puppets[room.puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
|
Loading…
Reference in New Issue
Block a user