-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
156 lines (131 loc) · 3.34 KB
/
server.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import Fastify from "fastify";
import puppeteer from "puppeteer";
import {
S3Client,
HeadObjectCommand,
PutObjectCommand,
DeleteObjectCommand,
} from "@aws-sdk/client-s3";
const HOST = "https://changelog.com";
const FASTIFY = Fastify({ logger: true });
const S3 = new S3Client();
const CHROME = await puppeteer.launch({
args: ["--no-sandbox", "--font-render-hinting=none"],
});
async function getSnap(url) {
let page = null;
try {
page = await CHROME.newPage();
await page.setCacheEnabled(false);
await page.setViewport({ width: 1200, height: 630 });
const response = await page.goto(url, { waitUntil: "networkidle2" });
if (response.status() != 200) {
throw new Error(`!200 OK: ${response.status()}`);
}
return await page.screenshot({ fullPage: false });
} finally {
if (page) {
await page.close();
}
}
}
async function storeSnap(key, data) {
try {
const command = new PutObjectCommand({
Bucket: process.env.BUCKET_NAME,
Key: key,
Body: data,
ContentType: "image/jpeg",
});
await S3.send(command);
} catch (error) {
console.error("Error uploading image", error);
throw error;
}
}
async function deleteSnap(key) {
try {
const command = new DeleteObjectCommand({
Bucket: process.env.BUCKET_NAME,
Key: key,
});
await S3.send(command);
} catch (error) {
console.error("Error deleting image", error);
throw error;
}
}
async function isSnapStored(key) {
try {
const command = new HeadObjectCommand({
Bucket: process.env.BUCKET_NAME,
Key: key,
});
await S3.send(command);
return true;
} catch (error) {
if (error.name === "NotFound") {
return false;
} else {
throw error;
}
}
}
function fileFromPath(path) {
return path.replace("/", "").replace(/\//g, "-");
}
function badRequest(reply) {
return reply.code(400).send({ message: "Bad Request", statusCode: 400 });
}
function ok(reply) {
return reply.code(200).send({ message: "OK", statusCode: 200 });
}
function notFound(reply) {
return reply.code(404).send({ message: "Not Found", statusCode: 404 });
}
FASTIFY.get("/", async function (_request, reply) {
reply.redirect(HOST);
});
FASTIFY.get("*", async function (request, reply) {
try {
const path = request.url;
const file = fileFromPath(path);
if (await isSnapStored(file)) {
const url = [
process.env.AWS_ENDPOINT_URL_S3,
process.env.BUCKET_NAME,
file,
].join("/");
return reply.redirect(302, url);
} else {
const snap = await getSnap(`${HOST}${path}`);
await storeSnap(file, snap);
return reply.type("image/jpg").send(snap);
}
} catch (error) {
FASTIFY.log.error(error);
return notFound(reply);
}
});
FASTIFY.delete("/", async function (request, reply) {
return ok(reply);
});
FASTIFY.delete("*", async function (request, reply) {
const path = request.url;
const file = fileFromPath(path);
const token = request.headers["x-snap-token"] || "NO_TOKEN";
if (token == process.env.AUTH_TOKEN) {
if (await isSnapStored(file)) {
await deleteSnap(file);
}
return ok(reply);
} else {
return badRequest(reply);
}
});
try {
await FASTIFY.listen({ host: "0.0.0.0", port: 3000 });
} catch (error) {
FASTIFY.log.error(error);
process.exit(1);
}