-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
54 lines (43 loc) · 1.61 KB
/
app.js
File metadata and controls
54 lines (43 loc) · 1.61 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
// app.js — minimal S3 presigner for your ESP32
import express from "express";
import crypto from "node:crypto";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const app = express();
app.use(express.json());
const {
AWS_REGION,
BUCKET_NAME,
URL_TTL_SECONDS = "900"
} = process.env;
if (!AWS_REGION || !BUCKET_NAME) {
console.warn("Missing env AWS_REGION or BUCKET_NAME — set them in Railway.");
}
const s3 = new S3Client({ region: AWS_REGION });
function sanitize(s, max = 64) {
return String(s || "").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, max);
}
// GET /presign?device=devA&session=S42&seq=3
app.get("/presign", async (req, res) => {
try {
const now = new Date().toISOString().replace(/[:.]/g, "-");
const device = sanitize(req.query.device || "device");
const session = sanitize(req.query.session || crypto.randomUUID());
const seq = String(parseInt(req.query.seq || "1", 10)).padStart(4, "0");
const key = `sessions/${session}/${now}__${device}__P${seq}.wav`;
const cmd = new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: key,
ContentType: "audio/wav"
});
const url = await getSignedUrl(s3, cmd, { expiresIn: parseInt(URL_TTL_SECONDS, 10) });
res.json({ url, bucket: BUCKET_NAME, key, contentType: "audio/wav" });
} catch (e) {
console.error(e);
res.status(500).json({ error: "presign_failed" });
}
});
// health check
app.get("/", (_req, res) => res.send("ok"));
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Presigner up on :${port}`));