@@ -13,12 +13,18 @@ module.exports.debrack = debrack
13
13
module . exports . stripLineEndings = stripLineEndings
14
14
module . exports . fullUrlForReq = fullUrlForReq
15
15
module . exports . routeResolvedFile = routeResolvedFile
16
+ module . exports . getQuota = getQuota
17
+ module . exports . overQuota = overQuota
16
18
17
19
const fs = require ( 'fs-extra' )
18
20
const path = require ( 'path' )
21
+ const util = require ( 'util' )
19
22
const $rdf = require ( 'rdflib' )
20
23
const from = require ( 'from2' )
21
24
const url = require ( 'url' )
25
+ const debug = require ( './debug' ) . fs
26
+ const getSize = require ( 'get-folder-size' )
27
+ var ns = require ( 'solid-namespace' ) ( $rdf )
22
28
23
29
/**
24
30
* Returns a fully qualified URL from an Express.js Request object.
@@ -239,3 +245,60 @@ function routeResolvedFile (router, path, file, appendFileName = true) {
239
245
const fullFile = require . resolve ( file )
240
246
router . get ( fullPath , ( req , res ) => res . sendFile ( fullFile ) )
241
247
}
248
+
249
+ /**
250
+ * Returns the number of bytes that the user owning the requested POD
251
+ * may store or Infinity if no limit
252
+ */
253
+
254
+ async function getQuota ( root , serverUri ) {
255
+ const filename = path . join ( root , 'settings/serverSide.ttl' )
256
+ var prefs
257
+ try {
258
+ prefs = await _asyncReadfile ( filename )
259
+ } catch ( error ) {
260
+ debug ( 'Setting no quota. While reading serverSide.ttl, got ' + error )
261
+ return Infinity
262
+ }
263
+ var graph = $rdf . graph ( )
264
+ const storageUri = serverUri + '/'
265
+ try {
266
+ $rdf . parse ( prefs , graph , storageUri , 'text/turtle' )
267
+ } catch ( error ) {
268
+ throw new Error ( 'Failed to parse serverSide.ttl, got ' + error )
269
+ }
270
+ return Number ( graph . anyValue ( $rdf . sym ( storageUri ) , ns . solid ( 'storageQuota' ) ) ) || Infinity
271
+ }
272
+
273
+ /**
274
+ * Returns true of the user has already exceeded their quota, i.e. it
275
+ * will check if new requests should be rejected, which means they
276
+ * could PUT a large file and get away with it.
277
+ */
278
+
279
+ async function overQuota ( root , serverUri ) {
280
+ let quota = await getQuota ( root , serverUri )
281
+ if ( quota === Infinity ) {
282
+ return false
283
+ }
284
+ // TODO: cache this value?
285
+ var size = await actualSize ( root )
286
+ return ( size > quota )
287
+ }
288
+
289
+ /**
290
+ * Returns the number of bytes that is occupied by the actual files in
291
+ * the file system. IMPORTANT NOTE: Since it traverses the directory
292
+ * to find the actual file sizes, this does a costly operation, but
293
+ * neglible for the small quotas we currently allow. If the quotas
294
+ * grow bigger, this will significantly reduce write performance, and
295
+ * so it needs to be rewritten.
296
+ */
297
+
298
+ function actualSize ( root ) {
299
+ return util . promisify ( getSize ) ( root )
300
+ }
301
+
302
+ function _asyncReadfile ( filename ) {
303
+ return util . promisify ( fs . readFile ) ( filename , 'utf-8' )
304
+ }
0 commit comments