2023-06-27 16:06:19 +02:00
|
|
|
import {
|
|
|
|
|
BeforeApplicationShutdown,
|
2023-06-29 10:32:09 +02:00
|
|
|
Injectable,
|
2023-06-27 16:06:19 +02:00
|
|
|
OnModuleInit,
|
|
|
|
|
} from '@nestjs/common'
|
|
|
|
|
import puppeteer, {
|
|
|
|
|
Browser,
|
|
|
|
|
BrowserConnectOptions,
|
|
|
|
|
BrowserLaunchArgumentOptions,
|
|
|
|
|
LaunchOptions,
|
|
|
|
|
} from 'puppeteer'
|
2023-05-26 15:43:14 -05:00
|
|
|
|
|
|
|
|
interface RunnerSession {
|
2023-06-27 16:06:19 +02:00
|
|
|
username: string
|
|
|
|
|
loggedInAt: Date
|
2023-05-26 15:43:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class RunnerService implements OnModuleInit, BeforeApplicationShutdown {
|
2023-06-27 16:06:19 +02:00
|
|
|
private browser?: Browser
|
|
|
|
|
private options: LaunchOptions &
|
|
|
|
|
BrowserLaunchArgumentOptions &
|
|
|
|
|
BrowserConnectOptions = {
|
|
|
|
|
args: ['--disable-setuid-sandbox', '--no-sandbox'],
|
|
|
|
|
headless: 'new',
|
|
|
|
|
}
|
|
|
|
|
private session: RunnerSession | null = null
|
|
|
|
|
|
|
|
|
|
private async init() {
|
|
|
|
|
try {
|
|
|
|
|
if (!this.browser) {
|
|
|
|
|
this.browser = await puppeteer.launch(this.options)
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw new PuppeteerBrowserLaunchError(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async onModuleInit() {
|
|
|
|
|
await this.init()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async beforeApplicationShutdown() {
|
|
|
|
|
try {
|
|
|
|
|
if (this.browser && this.browser.isConnected()) {
|
|
|
|
|
await this.browser.close()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('error shutting down browser', error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getBrowser(): Promise<Browser> {
|
|
|
|
|
await this.init()
|
|
|
|
|
if (!this.browser) {
|
|
|
|
|
throw new Error('Browser not initialized')
|
|
|
|
|
}
|
|
|
|
|
return this.browser
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getSession(): Promise<RunnerSession | null> {
|
|
|
|
|
return this.session
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public startSession(username: string) {
|
|
|
|
|
if (this.session && this.session.username !== username) {
|
|
|
|
|
throw new RunnerNewSessionError(new Error('Session already started'))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.session?.username === username) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.session = {
|
|
|
|
|
username,
|
|
|
|
|
loggedInAt: new Date(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public endSession() {
|
|
|
|
|
this.session = null
|
|
|
|
|
}
|
2023-05-26 15:43:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class RunnerError extends Error {
|
2023-06-27 16:06:19 +02:00
|
|
|
constructor(error: Error) {
|
|
|
|
|
super(error.message)
|
|
|
|
|
this.stack = error.stack
|
|
|
|
|
}
|
2023-05-26 15:43:14 -05:00
|
|
|
}
|
|
|
|
|
export class PuppeteerError extends RunnerError {}
|
|
|
|
|
export class PuppeteerBrowserLaunchError extends PuppeteerError {}
|
|
|
|
|
export class PuppeteerNewPageError extends PuppeteerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerNewSessionError extends RunnerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerLogoutError extends RunnerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerLoginNavigationError extends RunnerError {}
|
|
|
|
|
export class RunnerLoginUsernameInputError extends RunnerError {}
|
|
|
|
|
export class RunnerLoginPasswordInputError extends RunnerError {}
|
|
|
|
|
export class RunnerLoginSubmitError extends RunnerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerNavigationMonthError extends RunnerError {}
|
|
|
|
|
export class RunnerNavigationDayError extends RunnerError {}
|
|
|
|
|
export class RunnerNavigationSelectionError extends RunnerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerCourtSelectionError extends RunnerError {}
|
|
|
|
|
export class NoCourtAvailableError extends Error {}
|
|
|
|
|
|
|
|
|
|
export class RunnerOpponentSearchError extends RunnerError {}
|
|
|
|
|
export class RunnerOpponentSearchInputError extends RunnerError {}
|
|
|
|
|
export class RunnerOpponentSearchNetworkError extends RunnerError {}
|
|
|
|
|
export class RunnerOpponentSearchSelectionError extends RunnerError {}
|
|
|
|
|
|
|
|
|
|
export class RunnerReservationConfirmButtonError extends RunnerError {}
|
2023-06-27 16:06:19 +02:00
|
|
|
export class RunnerReservationConfirmSubmitError extends RunnerError {}
|