-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathindex.js
131 lines (113 loc) · 3.92 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
const { WASMagic } = require("../../");
const { Transform, Writable, pipeline } = require("node:stream");
const express = require("express");
const app = express();
const maxAcceptNonPngBytes = 1024 * 1024 * 100; // 100MB
async function init() {
// Only initialize WASMagic once, though we are running it in the user thread,
// if this was a production service, it would use `cluster` for this web
// application
const magic = await WASMagic.create();
app.post("/file", (req, res) => {
let bufs = [];
let curSize = 0;
let isDetected = false;
let detectedMime;
const detect = new Transform({
transform(chunk, encoding, cb) {
// Once we've detected the mime type, we'll just start forwarding the
// data through
if (isDetected) {
this.push(chunk);
return cb();
}
bufs.push(chunk);
curSize += chunk.length;
// Once we receive over 1KB, we can try and get the mime type of the upload
if (curSize >= 1024) {
const recieved = Buffer.concat(bufs);
detectedMime = magic.detect(recieved);
console.log("Got a:", detectedMime);
isDetected = true;
// Send everything we've received to the next stream in the pipe,
// we're doing this now so we can change the behavior based on the
// detected type. Technically, we could operate on the buffers here,
// but in this example it's showing how you can stack further streams
// in the pipeline. This would be the first time those streams receive
// data
this.push(recieved);
// Don't need this anymore, so we can discard it
bufs = undefined;
}
cb();
},
});
let processedBytes = 0;
const start = process.hrtime.bigint();
const doSomething = new Writable({
write(chunk, encoding, cb) {
processedBytes += chunk.length;
if (detectedMime === "image/png") {
// Do something special with our png? Stream it out to a png
// processor?
return cb();
}
// If we've received too much of something we don't want, let's just
// hang up on them
if (processedBytes >= maxAcceptNonPngBytes) {
const end = process.hrtime.bigint();
const time = Number(end - start) / 1000000;
const bytesSecond = processedBytes / (time / 1000);
console.log(
`We don't want a ${detectedMime}. Hanging up.
Bytes Processed: ${processedBytes}
Duration: ${time}ms
Bytes / Second: ${bytesSecond}`,
);
// Even though this is in the write method of our stream, it will
// immediately end the processing of the incoming POST and throw a
// 'ERR_STREAM_PREMATURE_CLOSE' Error
req.destroy();
}
// Otherwise do nothing, the bytes received go into the ether
cb();
},
});
console.log("\nIncoming file!");
// Kick off reading the upload stream
pipeline(req, detect, doSomething, (err) => {
const end = process.hrtime.bigint();
const time = Number(end - start) / 1000000;
const bytesSecond = processedBytes / (time / 1000);
if (err) {
switch (err.code) {
case "ERR_STREAM_PREMATURE_CLOSE":
console.log("Closed the stream, nothing else to do");
break;
default:
res.status(500).json(err);
}
return;
}
let msg;
if (detectedMime === "image/png") {
msg = "Processed image/png";
} else {
msg = `Ignored ${detectedMime}`;
res.status(400);
}
console.log(`${msg}
Bytes Processed: ${processedBytes}
Duration: ${time}ms
Bytes / Second: ${bytesSecond}`);
res.send(msg);
});
});
app.listen(3000, () => {
console.log("Server listening on 3000");
});
}
init().catch((err) => {
console.error(err);
process.exit(1);
});