@browserless.io/browserless 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +41 -3
- package/assets/debugger.png +0 -0
- package/bin/scaffold/src/hello-world.http.ts +3 -2
- package/build/browserless.d.ts +5 -4
- package/build/browserless.js +15 -11
- package/build/browsers/chrome.cdp.d.ts +2 -2
- package/build/browsers/chrome.cdp.js +2 -2
- package/build/browsers/chrome.playwright.d.ts +2 -2
- package/build/browsers/chrome.playwright.js +2 -2
- package/build/browsers/chromium.cdp.d.ts +4 -4
- package/build/browsers/chromium.cdp.js +49 -32
- package/build/browsers/chromium.playwright.d.ts +4 -4
- package/build/browsers/chromium.playwright.js +14 -13
- package/build/browsers/firefox.playwright.d.ts +4 -4
- package/build/browsers/firefox.playwright.js +14 -13
- package/build/browsers/index.d.ts +24 -8
- package/build/browsers/index.js +20 -15
- package/build/browsers/webkit.playwright.d.ts +4 -4
- package/build/browsers/webkit.playwright.js +14 -13
- package/build/config.d.ts +3 -0
- package/build/config.js +3 -0
- package/build/file-system.d.ts +2 -3
- package/build/file-system.js +2 -2
- package/build/index.js +7 -7
- package/build/limiter.d.ts +2 -3
- package/build/limiter.js +11 -11
- package/build/logger.d.ts +16 -9
- package/build/logger.js +32 -16
- package/build/monitoring.d.ts +2 -3
- package/build/monitoring.js +4 -4
- package/build/router.d.ts +1 -3
- package/build/router.js +21 -22
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/management/http/static.get.js +3 -3
- package/build/routes/management/tests/management.spec.js +9 -0
- package/build/server.d.ts +1 -3
- package/build/server.js +33 -30
- package/build/shared/content.http.d.ts +1 -1
- package/build/shared/content.http.js +4 -1
- package/build/shared/download.http.js +9 -9
- package/build/shared/function.http.js +2 -2
- package/build/shared/json-protocol.http.d.ts +3 -3
- package/build/shared/json-protocol.http.js +2 -2
- package/build/shared/json-version.http.d.ts +3 -3
- package/build/shared/json-version.http.js +2 -2
- package/build/shared/pdf.http.d.ts +1 -1
- package/build/shared/pdf.http.js +6 -4
- package/build/shared/performance.http.js +1 -0
- package/build/shared/scrape.http.d.ts +1 -1
- package/build/shared/scrape.http.js +4 -1
- package/build/shared/screenshot.http.d.ts +1 -1
- package/build/shared/screenshot.http.js +4 -1
- package/build/shared/utils/function/handler.js +7 -7
- package/build/shared/utils/performance/child.js +4 -4
- package/build/shared/utils/performance/main.d.ts +1 -1
- package/build/shared/utils/performance/main.js +5 -7
- package/build/shared/utils/performance/types.d.ts +2 -1
- package/build/utils.d.ts +1 -1
- package/build/utils.js +6 -2
- package/package.json +18 -15
- package/scripts/install-debugger.js +55 -15
- package/src/browserless.ts +21 -12
- package/src/browsers/chrome.cdp.ts +2 -5
- package/src/browsers/chrome.playwright.ts +2 -5
- package/src/browsers/chromium.cdp.ts +84 -35
- package/src/browsers/chromium.playwright.ts +26 -13
- package/src/browsers/firefox.playwright.ts +28 -13
- package/src/browsers/index.ts +24 -16
- package/src/browsers/webkit.playwright.ts +28 -13
- package/src/config.ts +4 -0
- package/src/file-system.ts +2 -7
- package/src/index.ts +7 -7
- package/src/limiter.ts +13 -11
- package/src/logger.ts +39 -18
- package/src/monitoring.ts +6 -8
- package/src/router.ts +20 -20
- package/src/routes/management/http/static.get.ts +3 -5
- package/src/routes/management/tests/management.spec.ts +15 -0
- package/src/server.ts +43 -30
- package/src/shared/content.http.ts +5 -1
- package/src/shared/download.http.ts +9 -9
- package/src/shared/function.http.ts +2 -2
- package/src/shared/json-protocol.http.ts +8 -3
- package/src/shared/json-version.http.ts +8 -4
- package/src/shared/pdf.http.ts +6 -4
- package/src/shared/performance.http.ts +1 -0
- package/src/shared/scrape.http.ts +5 -1
- package/src/shared/screenshot.http.ts +4 -1
- package/src/shared/utils/function/handler.ts +7 -7
- package/src/shared/utils/performance/child.ts +4 -4
- package/src/shared/utils/performance/main.ts +5 -6
- package/src/shared/utils/performance/types.ts +2 -1
- package/src/utils.ts +7 -2
- package/static/docs/swagger.json +10 -10
- package/static/docs/swagger.min.json +9 -9
- package/static/function/client.js +1646 -2917
- package/static/function/index.html +1646 -2917
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserServerOptions,
|
|
3
3
|
Config,
|
|
4
|
+
Logger,
|
|
4
5
|
Request,
|
|
5
6
|
ServerError,
|
|
6
|
-
createLogger,
|
|
7
7
|
} from '@browserless.io/browserless';
|
|
8
8
|
import playwright, { Page } from 'playwright-core';
|
|
9
9
|
import { Duplex } from 'stream';
|
|
@@ -15,25 +15,28 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
15
15
|
protected config: Config;
|
|
16
16
|
protected userDataDir: string | null;
|
|
17
17
|
protected running = false;
|
|
18
|
+
protected logger: Logger;
|
|
18
19
|
protected proxy = httpProxy.createProxyServer();
|
|
19
20
|
protected browser: playwright.BrowserServer | null = null;
|
|
20
21
|
protected browserWSEndpoint: string | null = null;
|
|
21
|
-
protected debug = createLogger('browsers:chromium:playwright');
|
|
22
22
|
protected executablePath = playwright.chromium.executablePath();
|
|
23
23
|
|
|
24
24
|
constructor({
|
|
25
25
|
config,
|
|
26
26
|
userDataDir,
|
|
27
|
+
logger,
|
|
27
28
|
}: {
|
|
28
29
|
config: Config;
|
|
30
|
+
logger: Logger;
|
|
29
31
|
userDataDir: ChromiumPlaywright['userDataDir'];
|
|
30
32
|
}) {
|
|
31
33
|
super();
|
|
32
34
|
|
|
33
35
|
this.userDataDir = userDataDir;
|
|
34
36
|
this.config = config;
|
|
37
|
+
this.logger = logger;
|
|
35
38
|
|
|
36
|
-
this.
|
|
39
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
protected cleanListeners() {
|
|
@@ -44,7 +47,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
44
47
|
|
|
45
48
|
public close = async (): Promise<void> => {
|
|
46
49
|
if (this.browser) {
|
|
47
|
-
this.
|
|
50
|
+
this.logger.info(
|
|
51
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
52
|
+
);
|
|
48
53
|
this.emit('close');
|
|
49
54
|
this.cleanListeners();
|
|
50
55
|
this.browser.close();
|
|
@@ -57,18 +62,22 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
57
62
|
public pages = async (): Promise<[]> => [];
|
|
58
63
|
|
|
59
64
|
public getPageId = (): string => {
|
|
60
|
-
throw new ServerError(
|
|
65
|
+
throw new ServerError(
|
|
66
|
+
`#getPageId is not yet supported with ${this.constructor.name}.`,
|
|
67
|
+
);
|
|
61
68
|
};
|
|
62
69
|
|
|
63
70
|
public makeLiveURL = (): void => {
|
|
64
71
|
throw new ServerError(
|
|
65
|
-
`Live URLs are not yet supported with this
|
|
72
|
+
`Live URLs are not yet supported with ${this.constructor.name}. In the future this will be at "${this.config.getExternalAddress()}"`,
|
|
66
73
|
);
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
public newPage = async (): Promise<Page> => {
|
|
70
77
|
if (!this.browser || !this.browserWSEndpoint) {
|
|
71
|
-
throw new ServerError(
|
|
78
|
+
throw new ServerError(
|
|
79
|
+
`${this.constructor.name} hasn't been launched yet!`,
|
|
80
|
+
);
|
|
72
81
|
}
|
|
73
82
|
const browser = await playwright.chromium.connect(this.browserWSEndpoint);
|
|
74
83
|
return await browser.newPage();
|
|
@@ -77,7 +86,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
77
86
|
public launch = async (
|
|
78
87
|
options: BrowserServerOptions = {},
|
|
79
88
|
): Promise<playwright.BrowserServer> => {
|
|
80
|
-
this.
|
|
89
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
81
90
|
|
|
82
91
|
this.browser = await playwright.chromium.launchServer({
|
|
83
92
|
...options,
|
|
@@ -91,7 +100,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
91
100
|
|
|
92
101
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
93
102
|
|
|
94
|
-
this.
|
|
103
|
+
this.logger.info(
|
|
104
|
+
`${this.constructor.name} is running on ${browserWSEndpoint}`,
|
|
105
|
+
);
|
|
95
106
|
this.running = true;
|
|
96
107
|
this.browserWSEndpoint = browserWSEndpoint;
|
|
97
108
|
|
|
@@ -118,7 +129,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
118
129
|
};
|
|
119
130
|
|
|
120
131
|
public proxyPageWebSocket = async () => {
|
|
121
|
-
|
|
132
|
+
this.logger.warn(`${this.constructor.name} Not yet implemented`);
|
|
122
133
|
};
|
|
123
134
|
|
|
124
135
|
public proxyWebSocket = async (
|
|
@@ -134,8 +145,8 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
134
145
|
}
|
|
135
146
|
socket.once('close', resolve);
|
|
136
147
|
|
|
137
|
-
this.
|
|
138
|
-
`Proxying ${req.parsed.href} to
|
|
148
|
+
this.logger.info(
|
|
149
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
139
150
|
);
|
|
140
151
|
|
|
141
152
|
// Delete headers known to cause issues
|
|
@@ -152,7 +163,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
152
163
|
target: this.browserWSEndpoint,
|
|
153
164
|
},
|
|
154
165
|
(error) => {
|
|
155
|
-
this.
|
|
166
|
+
this.logger.error(
|
|
167
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
168
|
+
);
|
|
156
169
|
this.close();
|
|
157
170
|
return reject(error);
|
|
158
171
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserServerOptions,
|
|
3
3
|
Config,
|
|
4
|
+
Logger,
|
|
4
5
|
Request,
|
|
5
6
|
ServerError,
|
|
6
|
-
createLogger,
|
|
7
7
|
} from '@browserless.io/browserless';
|
|
8
8
|
import playwright, { Page } from 'playwright-core';
|
|
9
9
|
import { Duplex } from 'stream';
|
|
@@ -15,24 +15,27 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
15
15
|
protected config: Config;
|
|
16
16
|
protected userDataDir: string | null;
|
|
17
17
|
protected running = false;
|
|
18
|
+
protected logger: Logger;
|
|
18
19
|
protected proxy = httpProxy.createProxyServer();
|
|
19
20
|
protected browser: playwright.BrowserServer | null = null;
|
|
20
21
|
protected browserWSEndpoint: string | null = null;
|
|
21
|
-
protected debug = createLogger('browsers:firefox:playwright');
|
|
22
22
|
|
|
23
23
|
constructor({
|
|
24
24
|
config,
|
|
25
25
|
userDataDir,
|
|
26
|
+
logger,
|
|
26
27
|
}: {
|
|
27
28
|
config: Config;
|
|
29
|
+
logger: Logger;
|
|
28
30
|
userDataDir: FirefoxPlaywright['userDataDir'];
|
|
29
31
|
}) {
|
|
30
32
|
super();
|
|
31
33
|
|
|
32
34
|
this.userDataDir = userDataDir;
|
|
33
35
|
this.config = config;
|
|
36
|
+
this.logger = logger;
|
|
34
37
|
|
|
35
|
-
this.
|
|
38
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
protected cleanListeners() {
|
|
@@ -43,7 +46,9 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
43
46
|
|
|
44
47
|
public close = async (): Promise<void> => {
|
|
45
48
|
if (this.browser) {
|
|
46
|
-
this.
|
|
49
|
+
this.logger.trace(
|
|
50
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
51
|
+
);
|
|
47
52
|
this.emit('close');
|
|
48
53
|
this.cleanListeners();
|
|
49
54
|
this.browser.close();
|
|
@@ -56,21 +61,27 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
56
61
|
public pages = async (): Promise<[]> => [];
|
|
57
62
|
|
|
58
63
|
public getPageId = (): string => {
|
|
59
|
-
throw new ServerError(
|
|
64
|
+
throw new ServerError(
|
|
65
|
+
`#getPageId is not yet supported with ${this.constructor.name}.`,
|
|
66
|
+
);
|
|
60
67
|
};
|
|
61
68
|
|
|
62
69
|
public makeLiveURL = (): void => {
|
|
63
|
-
throw new ServerError(
|
|
70
|
+
throw new ServerError(
|
|
71
|
+
`Live URLs are not yet supported with ${this.constructor.name}.`,
|
|
72
|
+
);
|
|
64
73
|
};
|
|
65
74
|
|
|
66
75
|
public newPage = async (): Promise<Page> => {
|
|
67
|
-
throw new ServerError(
|
|
76
|
+
throw new ServerError(
|
|
77
|
+
`Can't create new page with ${this.constructor.name}`,
|
|
78
|
+
);
|
|
68
79
|
};
|
|
69
80
|
|
|
70
81
|
public launch = async (
|
|
71
82
|
options: BrowserServerOptions = {},
|
|
72
83
|
): Promise<playwright.BrowserServer> => {
|
|
73
|
-
this.
|
|
84
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
74
85
|
|
|
75
86
|
this.browser = await playwright.firefox.launchServer({
|
|
76
87
|
...options,
|
|
@@ -83,7 +94,9 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
83
94
|
|
|
84
95
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
85
96
|
|
|
86
|
-
this.
|
|
97
|
+
this.logger.info(
|
|
98
|
+
`${this.constructor.name} is running on ${browserWSEndpoint}`,
|
|
99
|
+
);
|
|
87
100
|
this.browserWSEndpoint = browserWSEndpoint;
|
|
88
101
|
this.running = true;
|
|
89
102
|
|
|
@@ -110,7 +123,7 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
110
123
|
};
|
|
111
124
|
|
|
112
125
|
public proxyPageWebSocket = async () => {
|
|
113
|
-
|
|
126
|
+
this.logger.warn(`Not yet implemented in ${this.constructor.name}`);
|
|
114
127
|
};
|
|
115
128
|
|
|
116
129
|
public proxyWebSocket = async (
|
|
@@ -126,8 +139,8 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
126
139
|
}
|
|
127
140
|
socket.once('close', resolve);
|
|
128
141
|
|
|
129
|
-
this.
|
|
130
|
-
`Proxying ${req.parsed.href} to
|
|
142
|
+
this.logger.info(
|
|
143
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
131
144
|
);
|
|
132
145
|
|
|
133
146
|
// Delete headers known to cause issues
|
|
@@ -144,7 +157,9 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
144
157
|
target: this.browserWSEndpoint,
|
|
145
158
|
},
|
|
146
159
|
(error) => {
|
|
147
|
-
this.
|
|
160
|
+
this.logger.error(
|
|
161
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
162
|
+
);
|
|
148
163
|
this.close();
|
|
149
164
|
return reject(error);
|
|
150
165
|
},
|
package/src/browsers/index.ts
CHANGED
|
@@ -17,13 +17,13 @@ import {
|
|
|
17
17
|
FirefoxPlaywright,
|
|
18
18
|
HTTPManagementRoutes,
|
|
19
19
|
Hooks,
|
|
20
|
+
Logger,
|
|
20
21
|
NotFound,
|
|
21
22
|
Request,
|
|
22
23
|
ServerError,
|
|
23
24
|
WebkitPlaywright,
|
|
24
25
|
availableBrowsers,
|
|
25
26
|
convertIfBase64,
|
|
26
|
-
createLogger,
|
|
27
27
|
exists,
|
|
28
28
|
generateDataDir,
|
|
29
29
|
makeExternalURL,
|
|
@@ -38,7 +38,7 @@ export class BrowserManager {
|
|
|
38
38
|
protected browsers: Map<BrowserInstance, BrowserlessSession> = new Map();
|
|
39
39
|
protected launching: Map<string, Promise<unknown>> = new Map();
|
|
40
40
|
protected timers: Map<string, number> = new Map();
|
|
41
|
-
protected
|
|
41
|
+
protected log = new Logger('browser-manager');
|
|
42
42
|
protected chromeBrowsers = [ChromiumCDP, ChromeCDP];
|
|
43
43
|
protected playwrightBrowserNames = [
|
|
44
44
|
ChromiumPlaywright.name,
|
|
@@ -52,14 +52,14 @@ export class BrowserManager {
|
|
|
52
52
|
protected hooks: Hooks,
|
|
53
53
|
) {}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
protected browserIsChrome = (b: BrowserInstance) =>
|
|
56
56
|
this.chromeBrowsers.some((chromeBrowser) => b instanceof chromeBrowser);
|
|
57
57
|
|
|
58
58
|
protected removeUserDataDir = async (userDataDir: string | null) => {
|
|
59
59
|
if (userDataDir && (await exists(userDataDir))) {
|
|
60
|
-
this.
|
|
60
|
+
this.log.info(`Deleting data directory "${userDataDir}"`);
|
|
61
61
|
await deleteAsync(userDataDir, { force: true }).catch((err) => {
|
|
62
|
-
this.
|
|
62
|
+
this.log.error(
|
|
63
63
|
`Error cleaning up user-data-dir "${err}" at ${userDataDir}`,
|
|
64
64
|
);
|
|
65
65
|
});
|
|
@@ -75,7 +75,7 @@ export class BrowserManager {
|
|
|
75
75
|
* and modifies URLs to set them to the appropriate addresses configured.
|
|
76
76
|
* When both Chrome and Chromium are installed, defaults to Chromium.
|
|
77
77
|
*/
|
|
78
|
-
public getProtocolJSON = async (): Promise<object> => {
|
|
78
|
+
public getProtocolJSON = async (logger: Logger): Promise<object> => {
|
|
79
79
|
const Browser = (await availableBrowsers).find((InstalledBrowser) =>
|
|
80
80
|
this.chromeBrowsers.some(
|
|
81
81
|
(ChromeBrowser) => InstalledBrowser === ChromeBrowser,
|
|
@@ -87,6 +87,7 @@ export class BrowserManager {
|
|
|
87
87
|
const browser = new Browser({
|
|
88
88
|
blockAds: false,
|
|
89
89
|
config: this.config,
|
|
90
|
+
logger,
|
|
90
91
|
userDataDir: null,
|
|
91
92
|
});
|
|
92
93
|
await browser.launch();
|
|
@@ -110,8 +111,8 @@ export class BrowserManager {
|
|
|
110
111
|
* and modifies URLs to set them to the appropriate addresses configured.
|
|
111
112
|
* When both Chrome and Chromium are installed, defaults to Chromium.
|
|
112
113
|
*/
|
|
113
|
-
public getVersionJSON = async (): Promise<CDPJSONPayload> => {
|
|
114
|
-
this.
|
|
114
|
+
public getVersionJSON = async (logger: Logger): Promise<CDPJSONPayload> => {
|
|
115
|
+
this.log.info(`Launching Chromium to generate /json/version results`);
|
|
115
116
|
const Browser = (await availableBrowsers).find((InstalledBrowser) =>
|
|
116
117
|
this.chromeBrowsers.some(
|
|
117
118
|
(ChromeBrowser) => InstalledBrowser === ChromeBrowser,
|
|
@@ -124,6 +125,7 @@ export class BrowserManager {
|
|
|
124
125
|
const browser = new Browser({
|
|
125
126
|
blockAds: false,
|
|
126
127
|
config: this.config,
|
|
128
|
+
logger,
|
|
127
129
|
userDataDir: null,
|
|
128
130
|
});
|
|
129
131
|
await browser.launch();
|
|
@@ -214,7 +216,7 @@ export class BrowserManager {
|
|
|
214
216
|
.filter((_) => _ !== null) as Array<CDPJSONPayload>;
|
|
215
217
|
};
|
|
216
218
|
|
|
217
|
-
|
|
219
|
+
protected generateSessionJson = async (
|
|
218
220
|
browser: BrowserInstance,
|
|
219
221
|
session: BrowserlessSession,
|
|
220
222
|
) => {
|
|
@@ -267,18 +269,18 @@ export class BrowserManager {
|
|
|
267
269
|
session: BrowserlessSession,
|
|
268
270
|
): Promise<void> => {
|
|
269
271
|
const cleanupACtions: Array<() => Promise<void>> = [];
|
|
270
|
-
this.
|
|
272
|
+
this.log.info(`${session.numbConnected} Client(s) are currently connected`);
|
|
271
273
|
|
|
272
274
|
// Don't close if there's clients still connected
|
|
273
275
|
if (session.numbConnected > 0) {
|
|
274
276
|
return;
|
|
275
277
|
}
|
|
276
278
|
|
|
277
|
-
this.
|
|
279
|
+
this.log.info(`Closing browser session`);
|
|
278
280
|
cleanupACtions.push(() => browser.close());
|
|
279
281
|
|
|
280
282
|
if (session.isTempDataDir) {
|
|
281
|
-
this.
|
|
283
|
+
this.log.info(
|
|
282
284
|
`Deleting "${session.userDataDir}" user-data-dir and session from memory`,
|
|
283
285
|
);
|
|
284
286
|
this.browsers.delete(browser);
|
|
@@ -302,7 +304,9 @@ export class BrowserManager {
|
|
|
302
304
|
public complete = async (browser: BrowserInstance): Promise<void> => {
|
|
303
305
|
const session = this.browsers.get(browser);
|
|
304
306
|
if (!session) {
|
|
305
|
-
this.
|
|
307
|
+
this.log.info(
|
|
308
|
+
`Couldn't locate session for browser, proceeding with close`,
|
|
309
|
+
);
|
|
306
310
|
return browser.close();
|
|
307
311
|
}
|
|
308
312
|
|
|
@@ -321,6 +325,7 @@ export class BrowserManager {
|
|
|
321
325
|
public getBrowserForRequest = async (
|
|
322
326
|
req: Request,
|
|
323
327
|
router: BrowserHTTPRoute | BrowserWebsocketRoute,
|
|
328
|
+
logger: Logger,
|
|
324
329
|
): Promise<BrowserInstance> => {
|
|
325
330
|
const { browser: Browser } = router;
|
|
326
331
|
const blockAds = parseBooleanParam(
|
|
@@ -344,7 +349,7 @@ export class BrowserManager {
|
|
|
344
349
|
if (found) {
|
|
345
350
|
const [browser, session] = found;
|
|
346
351
|
++session.numbConnected;
|
|
347
|
-
this.debug(`Located browser with ID ${id}`);
|
|
352
|
+
this.log.debug(`Located browser with ID ${id}`);
|
|
348
353
|
return browser;
|
|
349
354
|
}
|
|
350
355
|
|
|
@@ -387,6 +392,8 @@ export class BrowserManager {
|
|
|
387
392
|
const found = allPages.flat().find((b) => b.id === id);
|
|
388
393
|
|
|
389
394
|
if (found) {
|
|
395
|
+
const session = this.browsers.get(found.browser)!;
|
|
396
|
+
++session.numbConnected;
|
|
390
397
|
return found.browser;
|
|
391
398
|
}
|
|
392
399
|
|
|
@@ -446,6 +453,7 @@ export class BrowserManager {
|
|
|
446
453
|
const browser = new Browser({
|
|
447
454
|
blockAds,
|
|
448
455
|
config: this.config,
|
|
456
|
+
logger,
|
|
449
457
|
userDataDir,
|
|
450
458
|
});
|
|
451
459
|
|
|
@@ -477,7 +485,7 @@ export class BrowserManager {
|
|
|
477
485
|
};
|
|
478
486
|
|
|
479
487
|
public shutdown = async (): Promise<void> => {
|
|
480
|
-
this.
|
|
488
|
+
this.log.info(`Closing down browser instances`);
|
|
481
489
|
const sessions = Array.from(this.browsers);
|
|
482
490
|
await Promise.all(sessions.map(([b]) => b.close()));
|
|
483
491
|
const timers = Array.from(this.timers);
|
|
@@ -486,7 +494,7 @@ export class BrowserManager {
|
|
|
486
494
|
this.browsers = new Map();
|
|
487
495
|
this.timers = new Map();
|
|
488
496
|
await this.stop();
|
|
489
|
-
this.
|
|
497
|
+
this.log.info(`Shutdown complete`);
|
|
490
498
|
};
|
|
491
499
|
|
|
492
500
|
/**
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserServerOptions,
|
|
3
3
|
Config,
|
|
4
|
+
Logger,
|
|
4
5
|
Request,
|
|
5
6
|
ServerError,
|
|
6
|
-
createLogger,
|
|
7
7
|
} from '@browserless.io/browserless';
|
|
8
8
|
import playwright, { Page } from 'playwright-core';
|
|
9
9
|
import { Duplex } from 'stream';
|
|
@@ -18,21 +18,24 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
18
18
|
protected proxy = httpProxy.createProxyServer();
|
|
19
19
|
protected browser: playwright.BrowserServer | null = null;
|
|
20
20
|
protected browserWSEndpoint: string | null = null;
|
|
21
|
-
protected
|
|
21
|
+
protected logger: Logger;
|
|
22
22
|
|
|
23
23
|
constructor({
|
|
24
24
|
config,
|
|
25
25
|
userDataDir,
|
|
26
|
+
logger,
|
|
26
27
|
}: {
|
|
27
28
|
config: Config;
|
|
29
|
+
logger: Logger;
|
|
28
30
|
userDataDir: WebkitPlaywright['userDataDir'];
|
|
29
31
|
}) {
|
|
30
32
|
super();
|
|
31
33
|
|
|
32
34
|
this.userDataDir = userDataDir;
|
|
33
35
|
this.config = config;
|
|
36
|
+
this.logger = logger;
|
|
34
37
|
|
|
35
|
-
this.
|
|
38
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
protected cleanListeners() {
|
|
@@ -43,7 +46,9 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
43
46
|
|
|
44
47
|
public close = async (): Promise<void> => {
|
|
45
48
|
if (this.browser) {
|
|
46
|
-
this.
|
|
49
|
+
this.logger.info(
|
|
50
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
51
|
+
);
|
|
47
52
|
this.emit('close');
|
|
48
53
|
this.cleanListeners();
|
|
49
54
|
this.browser.close();
|
|
@@ -56,21 +61,27 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
56
61
|
public pages = async (): Promise<[]> => [];
|
|
57
62
|
|
|
58
63
|
public getPageId = (): string => {
|
|
59
|
-
throw new ServerError(
|
|
64
|
+
throw new ServerError(
|
|
65
|
+
`#getPageId is not yet supported with ${this.constructor.name}.`,
|
|
66
|
+
);
|
|
60
67
|
};
|
|
61
68
|
|
|
62
69
|
public makeLiveURL = (): void => {
|
|
63
|
-
throw new ServerError(
|
|
70
|
+
throw new ServerError(
|
|
71
|
+
`Live URLs are not yet supported with ${this.constructor.name}.`,
|
|
72
|
+
);
|
|
64
73
|
};
|
|
65
74
|
|
|
66
75
|
public newPage = async (): Promise<Page> => {
|
|
67
|
-
throw new ServerError(
|
|
76
|
+
throw new ServerError(
|
|
77
|
+
`Can't create new page with ${this.constructor.name}`,
|
|
78
|
+
);
|
|
68
79
|
};
|
|
69
80
|
|
|
70
81
|
public launch = async (
|
|
71
82
|
options: BrowserServerOptions = {},
|
|
72
83
|
): Promise<playwright.BrowserServer> => {
|
|
73
|
-
this.
|
|
84
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
74
85
|
|
|
75
86
|
this.browser = await playwright.webkit.launchServer({
|
|
76
87
|
...options,
|
|
@@ -83,7 +94,9 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
83
94
|
|
|
84
95
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
85
96
|
|
|
86
|
-
this.
|
|
97
|
+
this.logger.info(
|
|
98
|
+
`${this.constructor.name} is running on ${browserWSEndpoint}`,
|
|
99
|
+
);
|
|
87
100
|
this.browserWSEndpoint = browserWSEndpoint;
|
|
88
101
|
this.running = true;
|
|
89
102
|
|
|
@@ -110,7 +123,7 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
110
123
|
};
|
|
111
124
|
|
|
112
125
|
public proxyPageWebSocket = async () => {
|
|
113
|
-
|
|
126
|
+
this.logger.warn(`Not yet implemented`);
|
|
114
127
|
};
|
|
115
128
|
|
|
116
129
|
public proxyWebSocket = async (
|
|
@@ -126,8 +139,8 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
126
139
|
}
|
|
127
140
|
socket.once('close', resolve);
|
|
128
141
|
|
|
129
|
-
this.
|
|
130
|
-
`Proxying ${req.parsed.href} to
|
|
142
|
+
this.logger.info(
|
|
143
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
131
144
|
);
|
|
132
145
|
|
|
133
146
|
// Delete headers known to cause issues
|
|
@@ -144,7 +157,9 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
144
157
|
target: this.browserWSEndpoint,
|
|
145
158
|
},
|
|
146
159
|
(error) => {
|
|
147
|
-
this.
|
|
160
|
+
this.logger.error(
|
|
161
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
162
|
+
);
|
|
148
163
|
this.close();
|
|
149
164
|
return reject(error);
|
|
150
165
|
},
|
package/src/config.ts
CHANGED
|
@@ -148,6 +148,7 @@ export class Config extends EventEmitter {
|
|
|
148
148
|
'30000'
|
|
149
149
|
);
|
|
150
150
|
protected static = process.env.STATIC ?? path.join(__dirname, '..', 'static');
|
|
151
|
+
protected debuggerDir = path.join(this.static, 'debugger');
|
|
151
152
|
protected retries = +(process.env.RETRIES ?? '5');
|
|
152
153
|
protected allowFileProtocol = !!parseEnvVars(false, 'ALLOW_FILE_PROTOCOL');
|
|
153
154
|
protected allowGet = !!parseEnvVars(false, 'ALLOW_GET', 'ENABLE_API_GET');
|
|
@@ -187,6 +188,7 @@ export class Config extends EventEmitter {
|
|
|
187
188
|
public getQueued = (): number => this.queued;
|
|
188
189
|
public getTimeout = (): number => this.timeout;
|
|
189
190
|
public getStatic = (): string => this.static;
|
|
191
|
+
public getDebuggerDir = (): string => this.debuggerDir;
|
|
190
192
|
public getRetries = (): number => this.retries;
|
|
191
193
|
public getAllowFileProtocol = (): boolean => this.allowFileProtocol;
|
|
192
194
|
public getCPULimit = (): number => this.maxCpu;
|
|
@@ -198,6 +200,8 @@ export class Config extends EventEmitter {
|
|
|
198
200
|
public getTimeoutAlertURL = () => this.timeoutAlertURL;
|
|
199
201
|
public getErrorAlertURL = () => this.errorAlertURL;
|
|
200
202
|
|
|
203
|
+
public hasDebugger = (): Promise<boolean> => exists(this.debuggerDir);
|
|
204
|
+
|
|
201
205
|
/**
|
|
202
206
|
* If true, allows GET style calls on our browser-based APIs, using
|
|
203
207
|
* ?body=JSON format.
|
package/src/file-system.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Config,
|
|
3
|
-
createLogger,
|
|
4
|
-
decrypt,
|
|
5
|
-
encrypt,
|
|
6
|
-
} from '@browserless.io/browserless';
|
|
1
|
+
import { Config, Logger, decrypt, encrypt } from '@browserless.io/browserless';
|
|
7
2
|
import { readFile, writeFile } from 'fs/promises';
|
|
8
3
|
import { EventEmitter } from 'events';
|
|
9
4
|
|
|
10
5
|
export class FileSystem extends EventEmitter {
|
|
11
6
|
protected fsMap: Map<string, string[]> = new Map();
|
|
12
7
|
protected currentAESKey: Buffer;
|
|
13
|
-
protected
|
|
8
|
+
protected logger = new Logger('file-system');
|
|
14
9
|
|
|
15
10
|
constructor(protected config: Config) {
|
|
16
11
|
super();
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Browserless,
|
|
1
|
+
import { Browserless, Logger } from '@browserless.io/browserless';
|
|
2
2
|
|
|
3
3
|
(async () => {
|
|
4
4
|
const browserless = new Browserless();
|
|
5
|
-
const
|
|
5
|
+
const logger = new Logger('index.js');
|
|
6
6
|
browserless.start();
|
|
7
7
|
|
|
8
8
|
process
|
|
@@ -15,27 +15,27 @@ import { Browserless, createLogger } from '@browserless.io/browserless';
|
|
|
15
15
|
process.exit(1);
|
|
16
16
|
})
|
|
17
17
|
.once('SIGTERM', async () => {
|
|
18
|
-
|
|
18
|
+
logger.info(`SIGTERM received, saving and closing down`);
|
|
19
19
|
await browserless.stop();
|
|
20
20
|
process.exit(0);
|
|
21
21
|
})
|
|
22
22
|
.once('SIGINT', async () => {
|
|
23
|
-
|
|
23
|
+
logger.info(`SIGINT received, saving and closing down`);
|
|
24
24
|
await browserless.stop();
|
|
25
25
|
process.exit(0);
|
|
26
26
|
})
|
|
27
27
|
.once('SIGHUP', async () => {
|
|
28
|
-
|
|
28
|
+
logger.info(`SIGHUP received, saving and closing down`);
|
|
29
29
|
await browserless.stop();
|
|
30
30
|
process.exit(0);
|
|
31
31
|
})
|
|
32
32
|
.once('SIGUSR2', async () => {
|
|
33
|
-
|
|
33
|
+
logger.info(`SIGUSR2 received, saving and closing down`);
|
|
34
34
|
await browserless.stop();
|
|
35
35
|
process.exit(0);
|
|
36
36
|
})
|
|
37
37
|
.once('exit', () => {
|
|
38
|
-
|
|
38
|
+
logger.info(`Process is finished, exiting`);
|
|
39
39
|
process.exit(0);
|
|
40
40
|
});
|
|
41
41
|
})();
|