-
-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathbrowsershot.js
More file actions
144 lines (119 loc) · 4.56 KB
/
Copy pathbrowsershot.js
File metadata and controls
144 lines (119 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
const fs = require('fs');
const { execSync } = require('child_process');
const chromium = require('@sparticuz/chromium');
const { S3 } = require("@aws-sdk/client-s3");
exports.handle = async function (event) {
if (event.warming) {
return;
}
// sparticuz/chromium specific settings.
// https://github.com/Sparticuz/chromium#usage
// Use legacy headless mode.
chromium.setHeadlessMode = true;
// Disable webgl.
chromium.setGraphicsMode = false;
// Add custom fonts to chromium.
const fontsFileNames = fs.readdirSync('/var/task/fonts/');
for (const fontFileName of fontsFileNames) {
await chromium.font(`/var/task/fonts/${fontFileName}`);
}
// Constant file where we write out options.
const options = '/tmp/browsershot.js';
event.options = event.options || {};
// If there's a path, the developer is saving something to
// a file. We'll write a constant path and let the PHP
// side handle writing to the developer's disk.
if (event.options.path) {
event.options.path = '/tmp/browsershot';
}
// If arbitrary HTML should be rendered, store the passed
// HTML in a temporary file and use the path as the URL.
if (event._html) {
fs.writeFileSync('/tmp/index.html', event._html);
event.url = 'file:///tmp/index.html';
} else if (event.options.s3Source) {
// If the source is S3, then download the file into a temporary file to be used as the URL.
const s3 = new S3({
region: event.options.s3Source.region,
accessKeyId: event.options.s3Source.key,
secretAccessKey: event.options.s3Source.secret,
});
const params = {
Bucket: event.options.s3Source.bucket,
Key: event.options.s3Source.path,
}
const result = await s3.getObject(params);
const fileContents = await streamToString(result.Body);
fs.writeFileSync('/tmp/index.html', fileContents);
event.url = 'file:///tmp/index.html';
}
// Get the executable path from the chrome layer.
event.options.executablePath = await chromium.executablePath();
// Combine the developers args with the ones from the layer.
event.options.args = [
...(event.options.args || []),
...chromium.args,
];
// Write the options to disk
fs.writeFileSync(options, JSON.stringify(event));
// Exec spatie's browser command.
let result = execSync(`node ./browser.cjs '-f file://${options}'`, {
// Set maxBuffer to 100 MB
maxBuffer: 1024 * 1024 * 100
});
// Delete puppeteer profiles from temp directory to free up space
fs.readdirSync('/tmp').forEach(file => {
if (file.startsWith('puppeteer_dev_chrome_profile')) {
fs.rm(`/tmp/${file}`, { recursive: true });
}
});
// If there was a path, then read the file and return it.
if (event.options.path) {
let contents = fs.readFileSync(event.options.path);
fs.unlinkSync(event.options.path);
// If the file destination is S3, then write
// the file and return the ETag as confirmation.
if (event.options.s3) {
const accessKeyId = event.options.s3.key;
const secretAccessKey = event.options.s3.secret;
const s3 = new S3({
region: event.options.s3.region,
accessKeyId: event.options.s3.key,
secretAccessKey: event.options.s3.secret,
});
let type;
switch (event.options.type) {
case "png":
type = 'image/png';
break;
case "jpeg":
type = 'image/jpeg';
break;
default:
type = 'application/pdf';
}
const params = {
Bucket: event.options.s3.bucket,
Key: event.options.s3.path,
Body: contents,
ContentType: type,
}
const result = await s3.putObject(params);
return result.ETag;
}
return new Buffer.from(contents).toString('base64');
}
// Otherwise, return the string.
return result.toString();
};
/**
* Read a stream into a string.
*/
const streamToString = function(stream) {
return new Promise((resolve, reject) => {
const chunks = [];
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', reject);
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
};