Skip to content

Commit 493390d

Browse files
committed
starting work on file upload directly to hub (no project involved) for use in doc editing
1 parent 1b4a22a commit 493390d

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Support user uploading a blob directly from their browser to the CoCalc database,
3+
mainly for markdown documents. This is meant to be very similar to how GitHub
4+
allows for attaching files to github issue comments.
5+
6+
7+
*/
8+
9+
// Note that github has a 10MB limit -- https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files
10+
const MAX_BLOB_SIZE_MB = 10;
11+
12+
// some throttling -- note that after a bit, most blobs end up longterm
13+
// cloud storage and are never accessed.
14+
// this is just a limit to prevent abuse, and it's done on a per-hub
15+
// basis using an in-memory data structure.
16+
const MAX_BLOBS_SIZE_MB_PER_USER_PER_DAY = 250;
17+
18+
import { Router } from "express";
19+
import { database } from "../database";
20+
import { is_valid_uuid_string } from "@cocalc/util/misc";
21+
import { database_is_working } from "@cocalc/hub/hub_register";
22+
import { callback2 } from "@cocalc/util/async-utils";
23+
import { getLogger } from "@cocalc/hub/logger";
24+
25+
const logger = getLogger("hub:servers:app:blobs");
26+
export default function init(router: Router) {
27+
// return uuid-indexed blobs (mainly used for graphics)
28+
router.post("/blobs", async (req, res) => {
29+
logger.debug(`${JSON.stringify(req.query)}, ${req.path}`);
30+
const uuid = `${req.query.uuid}`;
31+
if (!is_valid_uuid_string(uuid)) {
32+
res.status(404).send(`invalid uuid=${uuid}`);
33+
return;
34+
}
35+
if (!database_is_working()) {
36+
res.status(404).send("can't get blob -- not connected to database");
37+
return;
38+
}
39+
40+
try {
41+
const data = await callback2(database.get_blob, { uuid });
42+
if (data == null) {
43+
res.status(404).send(`blob ${uuid} not found`);
44+
} else {
45+
const filename = req.path.slice(req.path.lastIndexOf("/") + 1);
46+
if (req.query.download != null) {
47+
// tell browser to download the link as a file instead
48+
// of displaying it in browser
49+
res.attachment(filename);
50+
} else {
51+
res.type(filename);
52+
}
53+
res.send(data);
54+
}
55+
} catch (err) {
56+
logger.error(`internal error ${err} getting blob ${uuid}`);
57+
res.status(500).send(`internal error: ${err}`);
58+
}
59+
});
60+
}

src/packages/hub/servers/app/blobs.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import { database_is_working } from "@cocalc/hub/hub_register";
55
import { callback2 } from "@cocalc/util/async-utils";
66
import { getLogger } from "@cocalc/hub/logger";
77

8+
const logger = getLogger("hub:servers:app:blobs");
89
export default function init(router: Router) {
9-
const winston = getLogger("get-blob");
10-
1110
// return uuid-indexed blobs (mainly used for graphics)
1211
router.get("/blobs/*", async (req, res) => {
13-
winston.debug(`${JSON.stringify(req.query)}, ${req.path}`);
12+
logger.debug(`${JSON.stringify(req.query)}, ${req.path}`);
1413
const uuid = `${req.query.uuid}`;
1514
if (!is_valid_uuid_string(uuid)) {
1615
res.status(404).send(`invalid uuid=${uuid}`);
@@ -37,7 +36,7 @@ export default function init(router: Router) {
3736
res.send(data);
3837
}
3938
} catch (err) {
40-
winston.error(`internal error ${err} getting blob ${uuid}`);
39+
logger.error(`internal error ${err} getting blob ${uuid}`);
4140
res.status(500).send(`internal error: ${err}`);
4241
}
4342
});

src/packages/hub/servers/express-app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import initProxy from "../proxy";
2020
import initAPI from "./app/api";
2121
import initAppRedirect from "./app/app-redirect";
2222
import initBlobs from "./app/blobs";
23+
import initBlobUpload from "./app/blob-upload";
2324
import initStripeWebhook from "./app/webhooks/stripe";
2425
import initCustomize from "./app/customize";
2526
import { setupInstrumentation, initMetricsEndpoint } from "./app/metrics";
@@ -124,6 +125,7 @@ export default async function init(opts: Options): Promise<{
124125
});
125126

126127
initBlobs(router);
128+
initBlobUpload(router);
127129
initStripeWebhook(router);
128130
initSetCookies(router);
129131
initCustomize(router, opts.isPersonal);

0 commit comments

Comments
 (0)