CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/util/db-schema/blobs.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Table } from "./types";
7
8
// Note that github has a 10MB limit --
9
// https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files
10
// All code in cocalc (frontend, etc.) should use this,
11
// rather than copying or defining their own!
12
export const MAX_BLOB_SIZE = 10000000;
13
14
// some throttling -- note that after a bit, most blobs end up longterm
15
// cloud storage and are never accessed. This is mainly a limit to
16
// prevent abuse.
17
export const MAX_BLOB_SIZE_PER_PROJECT_PER_DAY = {
18
licensed: 100 * MAX_BLOB_SIZE,
19
unlicensed: 10 * MAX_BLOB_SIZE,
20
};
21
22
Table({
23
name: "blobs",
24
fields: {
25
id: {
26
type: "uuid",
27
desc: "The uuid of this blob, which is a uuid derived from the Sha1 hash of the blob content.",
28
},
29
blob: {
30
type: "Buffer",
31
desc: "The actual blob content",
32
},
33
expire: {
34
type: "timestamp",
35
desc: "When to expire this blob (when delete_expired is called on the database).",
36
},
37
created: {
38
type: "timestamp",
39
desc: "When the blob was created.",
40
},
41
project_id: {
42
// I'm not really sure why we record a project associated to the blob, rather
43
// than something else (e.g., account_id). However, it's useful for abuse, since
44
// if abuse happened with a project, we could easily delete all corresponding blobs,
45
// and also it's a good tag for throttling.
46
type: "string",
47
desc: "The uuid of the project that created the blob.",
48
},
49
last_active: {
50
type: "timestamp",
51
desc: "When the blob was last pulled from the database.",
52
},
53
count: {
54
type: "number",
55
desc: "How many times the blob has been pulled from the database.",
56
},
57
size: {
58
type: "number",
59
desc: "The size in bytes of the blob.",
60
},
61
gcloud: {
62
type: "string",
63
desc: "name of a bucket that contains the actual blob, if available.",
64
},
65
backup: {
66
type: "boolean",
67
desc: "if true, then this blob was saved to an offsite backup",
68
},
69
compress: {
70
type: "string",
71
desc: "optional compression used: 'gzip' or 'zlib'",
72
},
73
},
74
rules: {
75
desc: "Table that stores blobs mainly generated as output of Sage worksheets.",
76
primary_key: "id",
77
// these indices speed up the search been done in 'copy_all_blobs_to_gcloud'
78
// less important to make this query fast, but we want to avoid thrashing cache
79
pg_indexes: ["((expire IS NULL))", "((gcloud IS NULL))", "last_active"],
80
user_query: {
81
get: {
82
async instead_of_query(database, opts, cb): Promise<void> {
83
const obj: any = Object.assign({}, opts.query);
84
if (obj == null || obj.id == null) {
85
cb("id must be specified");
86
return;
87
}
88
database.get_blob({
89
uuid: obj.id,
90
cb(err, blob) {
91
if (err) {
92
cb(err);
93
} else {
94
cb(undefined, { id: obj.id, blob });
95
}
96
},
97
});
98
},
99
fields: {
100
id: null,
101
blob: null,
102
},
103
},
104
set: {
105
// NOTE: we put "as any" for fields below because ttl is not an actual field but
106
// it is allowed for set queries and determine the expire field. I would rather
107
// do this (which *is* supported by the backend) then not restrict the fields keys
108
// for other schema entries. Alternatively, we could have a special kind of field
109
// above that is "virtual", but that requires writing more code in the backend. We'll
110
// do that if necessary.
111
fields: {
112
id: true,
113
blob: true,
114
project_id: "project_write",
115
ttl: 0,
116
} as any,
117
required_fields: {
118
id: true,
119
blob: true,
120
project_id: true,
121
},
122
async instead_of_change(
123
database,
124
_old_value,
125
new_val,
126
_account_id,
127
cb,
128
): Promise<void> {
129
database.save_blob({
130
uuid: new_val.id,
131
blob: new_val.blob,
132
ttl: new_val.ttl,
133
project_id: new_val.project_id,
134
check: true, // can't trust the user!
135
cb,
136
});
137
},
138
},
139
},
140
},
141
});
142
143