This repository has been archived by the owner on May 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
132 lines (118 loc) · 3.88 KB
/
index.js
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
const Koa = require("koa");
const puppeteer = require("puppeteer");
const chalk = require("chalk");
const qs = require("koa-qs");
const dotenv = require('dotenv').config();
/**
* Launches Puppeteer.
* We found this hinting mode to be the most reliable
* when working with client fonts.
*/
async function boot() {
const browser = await puppeteer.launch({
args: [
"--no-proxy-server",
"--no-sandbox",
"--font-render-hinting=none"],
pipe: true
});
return browser;
}
/**
* Returns a simple Koa instance, with koa-qs injected.
* On the app instance lies our puppeteer instance.
*/
async function launch() {
const app = new Koa();
qs(app, "first");
app.context.chrome = await boot();
return app;
}
/**
* Helpers to reject, return a successful PDF, an auth failure.
*/
const reject = (response, message) => {
response.type = 'text/plain';
response.body = message;
response.status = 400;
};
const printed = (response, pdf) => {
response.type = 'application/pdf';
response.body = pdf;
response.status = 201;
}
const rendered = (response, htmlOutput) => {
response.type = 'text/html';
response.body = htmlOutput;
response.status = 200;
}
const unauthorized = (response, message) => {
response.type = 'text/plain';
response.body = message;
response.status = 401;
}
/**
* Docs.
*/
const doc = `
Our only route.
Accepts a GET request with the form
http(s?)://service-url?
url={url:base64 string} the URL to render, as a base64 string.
&format={format:string} a paper format. Defaults to "A4".
&range={range:range} the page range to print. Defaults to printing only the first page.
&orientation={orientation:string} either "portrait" or "landscape", defaults to being portrait.
&width={width::dimension+unit} dimensions with units. Is overriden by the "format" parameter.
&height={height:dimension+unit} dimensions with units. Is overriden by the "format" parameter.
&background={background:bool-like} bool-like : pass 0 or 1 as a string, defaults to true
&token={token:string?} optional : if you'd like to compare against a PRINTSERVER_TOKEN env var.
`;
launch().then((app) => {
app.use(async ({ request, response }) => {
if (process.env.PRINTSERVER_TOKEN) {
if (!request.query.token || request.query.token !== process.env.PRINTSERVER_TOKEN) {
return unauthorized(response, `Unauthorized.`);
}
}
if (!request.query.url) {
return reject(response, `Bad request, \n ${doc}`);
}
let outputMode = 'pdf';
if (request.query.output) {
outputMode = request.query.output === 'pdf' ? 'pdf' : 'html';
}
const page = await app.context.chrome.newPage();
const u = Buffer.from(request.query.url, "base64").toString("binary");
await page.setViewport({ width: 1440, height: 900 });
// Wait until all network activity is idle.
// This should be changed if you expect ads or do not control the target page.
await page.goto(u, { waitUntil: 'networkidle0' });
console.log('networkIdle');
if (outputMode === 'pdf') {
let params = {
format: "A4",
landscape: false,
printBackground: true,
pageRanges: "1"
};
if (request.query.format) {
params.format = request.query.format;
} else {
params.width = request.query.width;
params.height = request.query.height;
}
if (request.query.range) {
params.pageRanges = request.query.range;
}
params.landscape = request.query.orientation && request.query.orientation === 'landscape';
params.printBackground = request.query.background && !!parseInt(request.query.background, 10);
return printed(response, await page.pdf(params))
} else {
const html = await page.content();
return rendered(response, html);
}
});
const port = process.env.PRINTSERVER_PORT || 3468;
app.listen(port);
console.log(`Listening on port ${port}`);
});