import { TypedEventEmitter } from '@secret-agent/commons/eventUtils';
import IConnectionTransport from '@secret-agent/interfaces/IConnectionTransport';
import Log from '@secret-agent/commons/Logger';
import { DevtoolsSession } from './DevtoolsSession';
const { log } = Log(module);
export class Connection extends TypedEventEmitter<{ disconnected: void }> {
public readonly rootSession: DevtoolsSession;
public isClosed = false;
private lastId = 0;
private sessionsById = new Map<string, DevtoolsSession>();
constructor(readonly transport: IConnectionTransport) {
super();
transport.onMessageFn = this.onMessage.bind(this);
transport.onCloseFns.push(this.onClosed);
this.rootSession = new DevtoolsSession(this, 'browser', '');
this.sessionsById.set('', this.rootSession);
}
public sendMessage(message: object): number {
this.lastId += 1;
const id = this.lastId;
this.transport.send(JSON.stringify({ ...message, id }));
return id;
}
public getSession(sessionId: string): DevtoolsSession | undefined {
return this.sessionsById.get(sessionId);
}
public dispose(): void {
this.onClosed();
this.transport.close();
}
private onMessage(message: string): void {
const timestamp = new Date();
const object = JSON.parse(message);
object.timestamp = timestamp;
const devtoolsSessionId = object.params?.sessionId;
if (object.method === 'Target.attachedToTarget') {
const session = new DevtoolsSession(this, object.params.targetInfo.type, devtoolsSessionId);
this.sessionsById.set(devtoolsSessionId, session);
}
if (object.method === 'Target.detachedFromTarget') {
const session = this.sessionsById.get(devtoolsSessionId);
if (session) {
session.onClosed();
this.sessionsById.delete(devtoolsSessionId);
}
}
const devtoolsSession = this.sessionsById.get(object.sessionId || '');
if (devtoolsSession) {
devtoolsSession.onMessage(object);
} else {
log.warn('MessageWithUnknownSession', { sessionId: null, message: object });
}
}
private onClosed(): void {
if (this.isClosed) return;
this.isClosed = true;
for (const [id, session] of this.sessionsById) {
session.onClosed();
this.sessionsById.delete(id);
}
this.transport.onMessageFn = null;
this.emit('disconnected');
}
}