Openstatus
www.openstatus.dev
1import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
2import { zValidator } from "@hono/zod-validator";
3import { Hono } from "hono";
4import playwright from "playwright";
5import { z } from "zod";
6
7import { db, eq } from "@openstatus/db";
8import { incidentTable } from "@openstatus/db/src/schema/incidents/incident";
9import { Receiver } from "@upstash/qstash";
10
11import { env } from "./env";
12
13const S3 = new S3Client({
14 region: "auto",
15 endpoint: env.R2_URL,
16 credentials: {
17 accessKeyId: env.R2_ACCESS_KEY,
18 secretAccessKey: env.R2_SECRET_KEY,
19 },
20});
21
22const receiver = new Receiver({
23 currentSigningKey: env.QSTASH_SIGNING_SECRET,
24 nextSigningKey: env.QSTASH_NEXT_SIGNING_SECRET,
25});
26
27const app = new Hono();
28
29app.get("/ping", (c) =>
30 c.json({ ping: "pong", region: process.env.FLY_REGION }, 200),
31);
32
33app.post(
34 "/",
35 zValidator(
36 "json",
37 z.object({
38 url: z.url(),
39 incidentId: z.number(),
40 kind: z.enum(["incident", "recovery"]),
41 }),
42 ),
43 async (c) => {
44 const signature = c.req.header("Upstash-Signature");
45 // if (auth !== `Basic ${env.HEADER_TOKEN}`) {
46 // console.error("Unauthorized");
47 // return c.text("Unauthorized", 401);
48 // }
49
50 const data = c.req.valid("json");
51 const isValid = receiver.verify({
52 signature: signature || "",
53 body: JSON.stringify(data),
54 });
55 if (!isValid) {
56 console.error("Unauthorized");
57 return c.text("Unauthorized", 401);
58 }
59
60 const browser = await playwright.chromium.launch({
61 headless: true, // set this to true
62 });
63
64 try {
65 const page = await browser.newPage();
66 await page.goto(data.url, { waitUntil: "load" });
67 const img = await page.screenshot({ fullPage: true });
68 const id = `${data.incidentId}-${Date.now()}.png`;
69 const url = `https://screenshot.openstat.us/${id}`;
70
71 await S3.send(
72 new PutObjectCommand({
73 Body: img,
74 Bucket: "incident-screenshot",
75 Key: id,
76 ContentType: "image/png",
77 }),
78 );
79
80 if (data.kind === "incident") {
81 await db
82 .update(incidentTable)
83 .set({ incidentScreenshotUrl: url })
84 .where(eq(incidentTable.id, data.incidentId))
85 .run();
86 }
87 if (data.kind === "recovery") {
88 await db
89 .update(incidentTable)
90 .set({ recoveryScreenshotUrl: url })
91 .where(eq(incidentTable.id, data.incidentId))
92 .run();
93 }
94 } catch (e) {
95 console.log("could not take screenshot timeout");
96 if (data.kind === "incident") {
97 await db
98 .update(incidentTable)
99 .set({
100 incidentScreenshotUrl:
101 "https://screenshot.openstat.us/err-connection-timed-out.jpg",
102 })
103 .where(eq(incidentTable.id, data.incidentId))
104 .run();
105 }
106 //
107 console.log(e);
108 }
109
110 return c.text("Screenshot saved");
111 },
112);
113
114export default app;