Aether/server/src/imap/ImapController.ts

69 lines
1.9 KiB
TypeScript

import EventEmitter from 'events';
import Log from '../Log';
import ImapConnection, { ConnectionProperties } from './ImapConnection';
export const DEFAULT_CONNECTIONS = 6;
export default class ImapController {
readonly event: EventEmitter = new EventEmitter();
private address: string;
private connected: boolean = false;
private connections: ImapConnection[] = [];
private awaitingIdle: ((conn: ImapConnection) => void)[] = [];
constructor(connectionProps: ConnectionProperties, connectionCount: number = DEFAULT_CONNECTIONS) {
this.address = connectionProps.user;
for (let i = 0; i < connectionCount; i++) this.connections.push(new ImapConnection(connectionProps));
this.connections.forEach(conn => conn.event.on('idle',
() => this.event.emit('idle', conn)));
this.event.on('idle', (conn: ImapConnection) => {
if (this.awaitingIdle.length <= 0) return;
this.awaitingIdle[0](conn);
this.awaitingIdle.splice(0, 1);
});
}
async connect() {
await Promise.all(this.connections.map(async (conn, i) => {
Log.perfStart(`Connection ${i + 1} for ${this.address}`);
await conn.connect();
Log.perfEnd(`Connection ${i + 1} for ${this.address}`);
}));
this.connected = true;
}
async get(path?: string): Promise<ImapConnection> {
if (!this.connected) throw new Error('Tried to access a box when the connections aren\'t connected.');
if (path === undefined) return this.connections[Math.floor(Math.random() * 100000) % this.connections.length];
for (let conn of this.connections) {
if (conn.getOpenBox() === path) {
return conn;
}
}
for (let conn of this.connections) {
if (conn.getOpenBox() === null) {
await conn.openBox(path);
return conn;
}
}
for (let conn of this.connections) {
if (!conn.isIdle()) continue;
await conn.openBox(path);
return conn;
}
return new Promise((resolve) =>
this.awaitingIdle.push((conn: ImapConnection) =>
conn.openBox(path).then(() => resolve(conn))));
}
}