Skip to content

Commit 74094e3

Browse files
committed
Added the storage manager to allow to limit the storage
1 parent 6eb0cd0 commit 74094e3

File tree

13 files changed

+439
-25
lines changed

13 files changed

+439
-25
lines changed

lib/manager/v2/fileSystem/FileSystem.js

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3+
var stream_1 = require("stream");
34
var LockScope_1 = require("../../../resource/lock/LockScope");
45
var LockType_1 = require("../../../resource/lock/LockType");
56
var LockKind_1 = require("../../../resource/lock/LockKind");
@@ -154,10 +155,21 @@ var FileSystem = (function () {
154155
this.emit('before-create', ctx, path, { type: type, createIntermediates: createIntermediates });
155156
issuePrivilegeCheck(this, ctx, path, 'canWrite', callback, function () {
156157
var go = function () {
157-
_this._create(path, {
158-
context: ctx,
159-
type: type
160-
}, callback);
158+
ctx.server.options.storageManager.evaluateCreate(ctx, _this, path, type, function (size) {
159+
ctx.server.options.storageManager.reserve(ctx, _this, size, function (reserved) {
160+
if (!reserved)
161+
return callback(Errors_1.Errors.InsufficientStorage);
162+
_this._create(path, {
163+
context: ctx,
164+
type: type
165+
}, function (e) {
166+
if (e)
167+
ctx.server.options.storageManager.reserve(ctx, _this, -size, function () { return callback(e); });
168+
else
169+
callback();
170+
});
171+
});
172+
});
161173
};
162174
_this.isLocked(ctx, path, function (e, locked) {
163175
if (e || locked)
@@ -239,7 +251,19 @@ var FileSystem = (function () {
239251
_this._delete(path, {
240252
context: ctx,
241253
depth: depth
242-
}, callback);
254+
}, function (e) {
255+
if (!e) {
256+
_this.type(ctx, path, function (e, type) {
257+
ctx.server.options.storageManager.evaluateCreate(ctx, _this, path, type, function (size) {
258+
ctx.server.options.storageManager.reserve(ctx, _this, -size, function () {
259+
callback();
260+
});
261+
});
262+
});
263+
}
264+
else
265+
callback(e);
266+
});
243267
});
244268
});
245269
});
@@ -279,14 +303,59 @@ var FileSystem = (function () {
279303
_this.isLocked(ctx, path, function (e, isLocked) {
280304
if (e || isLocked)
281305
return callback(e ? e : Errors_1.Errors.Locked);
282-
var go = function (callback) {
306+
var finalGo = function (callback) {
283307
_this._openWriteStream(path, {
284308
context: ctx,
285309
estimatedSize: estimatedSize,
286310
targetSource: targetSource,
287311
mode: mode
288312
}, function (e, wStream) { return callback(e, wStream, created); });
289313
};
314+
var go = function (callback) {
315+
_this.size(ctx, path, true, function (e, size) {
316+
ctx.server.options.storageManager.evaluateContent(ctx, _this, size, function (sizeStored) {
317+
if (estimatedSize === undefined || estimatedSize === null || estimatedSize.constructor === Number && estimatedSize <= 0) {
318+
ctx.server.options.storageManager.available(ctx, _this, function (available) {
319+
if (available === -1)
320+
return finalGo(callback);
321+
if (available === 0)
322+
return callback(Errors_1.Errors.InsufficientStorage);
323+
var nb = 0;
324+
finalGo(function (e, wStream, created) {
325+
if (e)
326+
return callback(e, wStream, created);
327+
var stream = new stream_1.Transform({
328+
transform: function (chunk, encoding, callback) {
329+
nb += chunk.length;
330+
if (nb > available)
331+
callback(Errors_1.Errors.InsufficientStorage);
332+
else
333+
callback(null, chunk, encoding);
334+
}
335+
});
336+
stream.pipe(wStream);
337+
stream.on('finish', function () {
338+
ctx.server.options.storageManager.reserve(ctx, _this, nb, function (reserved) {
339+
if (!reserved)
340+
stream.emit('error', Errors_1.Errors.InsufficientStorage);
341+
});
342+
});
343+
callback(e, stream, created);
344+
});
345+
});
346+
}
347+
else {
348+
ctx.server.options.storageManager.evaluateContent(ctx, _this, estimatedSize, function (estimatedSizeStored) {
349+
ctx.server.options.storageManager.reserve(ctx, _this, estimatedSizeStored - sizeStored, function (reserved) {
350+
if (!reserved)
351+
return callback(Errors_1.Errors.InsufficientStorage);
352+
finalGo(callback);
353+
});
354+
});
355+
}
356+
});
357+
});
358+
};
290359
var createAndGo = function (intermediates) {
291360
_this.create(ctx, path, CommonTypes_1.ResourceType.File, intermediates, function (e) {
292361
if (e)
@@ -671,8 +740,25 @@ var FileSystem = (function () {
671740
});
672741
},
673742
getProperties: function (callback, byCopy) {
743+
var _this = this;
674744
issuePrivilegeCheck(fs, ctx, pPath, 'canReadProperties', callback, function () {
675-
pm.getProperties(callback, byCopy);
745+
pm.getProperties(function (e, bag) {
746+
if (!bag)
747+
return callback(e, bag);
748+
ctx.server.options.storageManager.available(ctx, _this, function (availableSize) {
749+
if (availableSize === -1)
750+
return callback(e, bag);
751+
ctx.server.options.storageManager.reserved(ctx, _this, function (reservedSize) {
752+
bag['DAV:quota-available-bytes'] = {
753+
value: availableSize.toString()
754+
};
755+
bag['DAV:quota-used-bytes'] = {
756+
value: reservedSize.toString()
757+
};
758+
callback(e, bag);
759+
});
760+
});
761+
}, byCopy);
676762
});
677763
}
678764
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { RequestContext } from '../../../server/v2/RequestContext';
2+
import { Path } from '../Path';
3+
import { ResourceType, ResourcePropertyValue, PropertyAttributes } from './CommonTypes';
4+
import { FileSystem } from './FileSystem';
5+
export declare type IStorageManagerEvaluateCallback = (size: number) => void;
6+
export interface IStorageManager {
7+
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
8+
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
9+
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
10+
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
11+
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
12+
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
13+
}
14+
export declare class NoStorageManager implements IStorageManager {
15+
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
16+
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
17+
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
18+
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
19+
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
20+
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
21+
}
22+
export declare class PerUserStorageManager implements IStorageManager {
23+
limitPerUser: number;
24+
storage: {
25+
[UUID: string]: number;
26+
};
27+
constructor(limitPerUser: number);
28+
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
29+
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
30+
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
31+
evalPropValue(value: ResourcePropertyValue): number;
32+
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
33+
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
34+
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
35+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
var NoStorageManager = (function () {
4+
function NoStorageManager() {
5+
}
6+
NoStorageManager.prototype.reserve = function (ctx, fs, size, callback) {
7+
callback(true);
8+
};
9+
NoStorageManager.prototype.evaluateCreate = function (ctx, fs, path, type, callback) {
10+
callback(0);
11+
};
12+
NoStorageManager.prototype.evaluateContent = function (ctx, fs, expectedSize, callback) {
13+
callback(0);
14+
};
15+
NoStorageManager.prototype.evaluateProperty = function (ctx, fs, name, value, attributes, callback) {
16+
callback(0);
17+
};
18+
NoStorageManager.prototype.available = function (ctx, fs, callback) {
19+
callback(-1);
20+
};
21+
NoStorageManager.prototype.reserved = function (ctx, fs, callback) {
22+
callback(0);
23+
};
24+
return NoStorageManager;
25+
}());
26+
exports.NoStorageManager = NoStorageManager;
27+
var PerUserStorageManager = (function () {
28+
function PerUserStorageManager(limitPerUser) {
29+
this.limitPerUser = limitPerUser;
30+
this.storage = {};
31+
}
32+
PerUserStorageManager.prototype.reserve = function (ctx, fs, size, callback) {
33+
var nb = this.storage[ctx.user.uid];
34+
if (nb === undefined)
35+
nb = 0;
36+
nb += size;
37+
if (nb > this.limitPerUser)
38+
return callback(false);
39+
this.storage[ctx.user.uid] = Math.max(0, nb);
40+
callback(true);
41+
};
42+
PerUserStorageManager.prototype.evaluateCreate = function (ctx, fs, path, type, callback) {
43+
fs.getFullPath(ctx, path, function (e, fullPath) {
44+
callback(fullPath.toString().length);
45+
});
46+
};
47+
PerUserStorageManager.prototype.evaluateContent = function (ctx, fs, expectedSize, callback) {
48+
callback(expectedSize);
49+
};
50+
PerUserStorageManager.prototype.evalPropValue = function (value) {
51+
var _this = this;
52+
if (!value)
53+
return 0;
54+
if (value.constructor === String)
55+
return value.length;
56+
if (Array.isArray(value))
57+
return value.map(function (el) { return _this.evalPropValue(el); }).reduce(function (p, n) { return p + n; }, 0);
58+
var xml = value;
59+
var attributesLength = Object.keys(xml.attributes).map(function (at) { return at.length + xml.attributes[at].length; }).reduce(function (p, n) { return p + n; }, 0);
60+
return xml.name.length + attributesLength + (xml.elements && xml.elements.length > 0 ? this.evalPropValue(xml.elements) : 0);
61+
};
62+
PerUserStorageManager.prototype.evaluateProperty = function (ctx, fs, name, value, attributes, callback) {
63+
callback(name.length + Object.keys(attributes).map(function (ak) { return attributes[ak].length + ak.length; }).reduce(function (p, n) { return p + n; }, 0) + this.evalPropValue(value));
64+
};
65+
PerUserStorageManager.prototype.available = function (ctx, fs, callback) {
66+
var nb = this.storage[ctx.user.uid];
67+
callback(nb === undefined ? this.limitPerUser : this.limitPerUser - nb);
68+
};
69+
PerUserStorageManager.prototype.reserved = function (ctx, fs, callback) {
70+
var nb = this.storage[ctx.user.uid];
71+
callback(nb === undefined ? 0 : nb);
72+
};
73+
return PerUserStorageManager;
74+
}());
75+
exports.PerUserStorageManager = PerUserStorageManager;

lib/manager/v2/fileSystem/export.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './Resource';
77
export * from './Serialization';
88
export * from './StandardMethods';
99
export * from './ContextInfo';
10+
export * from './StorageManager';

lib/manager/v2/fileSystem/export.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ __export(require("./PropertyManager"));
1111
__export(require("./Resource"));
1212
__export(require("./Serialization"));
1313
__export(require("./StandardMethods"));
14+
__export(require("./StorageManager"));

lib/server/v2/WebDAVServerOptions.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/// <reference types="node" />
2+
import { IStorageManager } from '../../manager/v2/fileSystem/StorageManager';
3+
import { FileSystemSerializer } from '../../manager/v2/fileSystem/Serialization';
24
import { HTTPAuthentication } from '../../user/v2/authentication/HTTPAuthentication';
35
import { Writable, Readable } from 'stream';
46
import { PrivilegeManager } from '../../user/v2/privilege/PrivilegeManager';
57
import { FileSystem } from '../../manager/v2/fileSystem/FileSystem';
6-
import { FileSystemSerializer } from '../../manager/v2/fileSystem/Serialization';
78
import * as https from 'https';
89
export interface IAutoSave {
910
treeFilePath: string;
@@ -30,6 +31,7 @@ export declare class WebDAVServerOptions {
3031
version?: string;
3132
autoSave?: IAutoSave;
3233
autoLoad?: IAutoLoad;
34+
storageManager?: IStorageManager;
3335
}
3436
export default WebDAVServerOptions;
3537
export declare function setDefaultServerOptions(options: WebDAVServerOptions): WebDAVServerOptions;

lib/server/v2/WebDAVServerOptions.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3+
var StorageManager_1 = require("../../manager/v2/fileSystem/StorageManager");
34
var HTTPDigestAuthentication_1 = require("../../user/v2/authentication/HTTPDigestAuthentication");
4-
var PrivilegeManager_1 = require("../../user/v2/privilege/PrivilegeManager");
5-
var SimpleUserManager_1 = require("../../user/v2/simple/SimpleUserManager");
65
var VirtualFileSystem_1 = require("../../manager/v2/instances/VirtualFileSystem");
6+
var SimpleUserManager_1 = require("../../user/v2/simple/SimpleUserManager");
7+
var PrivilegeManager_1 = require("../../user/v2/privilege/PrivilegeManager");
78
var WebDAVServerOptions = (function () {
89
function WebDAVServerOptions() {
910
this.requireAuthentification = false;
@@ -19,6 +20,7 @@ var WebDAVServerOptions = (function () {
1920
this.version = '1.8.0';
2021
this.autoSave = null;
2122
this.autoLoad = null;
23+
this.storageManager = new StorageManager_1.NoStorageManager();
2224
}
2325
return WebDAVServerOptions;
2426
}());

lib/server/v2/commands/Propfind.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ var default_1 = (function () {
313313
for (var name_1 in properties) {
314314
if (reqBody.mustDisplay(name_1)) {
315315
var tag = prop.ele(name_1);
316-
console.log(name_1, tag);
317316
if (reqBody.mustDisplayValue(name_1)) {
318317
var property = properties[name_1];
319318
if (tag.attributes)

0 commit comments

Comments
 (0)