Skip to content

Commit

Permalink
Added the storage manager to allow to limit the storage
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienCastex committed Aug 20, 2017
1 parent 6eb0cd0 commit 74094e3
Show file tree
Hide file tree
Showing 13 changed files with 439 additions and 25 deletions.
100 changes: 93 additions & 7 deletions lib/manager/v2/fileSystem/FileSystem.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var stream_1 = require("stream");
var LockScope_1 = require("../../../resource/lock/LockScope");
var LockType_1 = require("../../../resource/lock/LockType");
var LockKind_1 = require("../../../resource/lock/LockKind");
Expand Down Expand Up @@ -154,10 +155,21 @@ var FileSystem = (function () {
this.emit('before-create', ctx, path, { type: type, createIntermediates: createIntermediates });
issuePrivilegeCheck(this, ctx, path, 'canWrite', callback, function () {
var go = function () {
_this._create(path, {
context: ctx,
type: type
}, callback);
ctx.server.options.storageManager.evaluateCreate(ctx, _this, path, type, function (size) {
ctx.server.options.storageManager.reserve(ctx, _this, size, function (reserved) {
if (!reserved)
return callback(Errors_1.Errors.InsufficientStorage);
_this._create(path, {
context: ctx,
type: type
}, function (e) {
if (e)
ctx.server.options.storageManager.reserve(ctx, _this, -size, function () { return callback(e); });
else
callback();
});
});
});
};
_this.isLocked(ctx, path, function (e, locked) {
if (e || locked)
Expand Down Expand Up @@ -239,7 +251,19 @@ var FileSystem = (function () {
_this._delete(path, {
context: ctx,
depth: depth
}, callback);
}, function (e) {
if (!e) {
_this.type(ctx, path, function (e, type) {
ctx.server.options.storageManager.evaluateCreate(ctx, _this, path, type, function (size) {
ctx.server.options.storageManager.reserve(ctx, _this, -size, function () {
callback();
});
});
});
}
else
callback(e);
});
});
});
});
Expand Down Expand Up @@ -279,14 +303,59 @@ var FileSystem = (function () {
_this.isLocked(ctx, path, function (e, isLocked) {
if (e || isLocked)
return callback(e ? e : Errors_1.Errors.Locked);
var go = function (callback) {
var finalGo = function (callback) {
_this._openWriteStream(path, {
context: ctx,
estimatedSize: estimatedSize,
targetSource: targetSource,
mode: mode
}, function (e, wStream) { return callback(e, wStream, created); });
};
var go = function (callback) {
_this.size(ctx, path, true, function (e, size) {
ctx.server.options.storageManager.evaluateContent(ctx, _this, size, function (sizeStored) {
if (estimatedSize === undefined || estimatedSize === null || estimatedSize.constructor === Number && estimatedSize <= 0) {
ctx.server.options.storageManager.available(ctx, _this, function (available) {
if (available === -1)
return finalGo(callback);
if (available === 0)
return callback(Errors_1.Errors.InsufficientStorage);
var nb = 0;
finalGo(function (e, wStream, created) {
if (e)
return callback(e, wStream, created);
var stream = new stream_1.Transform({
transform: function (chunk, encoding, callback) {
nb += chunk.length;
if (nb > available)
callback(Errors_1.Errors.InsufficientStorage);
else
callback(null, chunk, encoding);
}
});
stream.pipe(wStream);
stream.on('finish', function () {
ctx.server.options.storageManager.reserve(ctx, _this, nb, function (reserved) {
if (!reserved)
stream.emit('error', Errors_1.Errors.InsufficientStorage);
});
});
callback(e, stream, created);
});
});
}
else {
ctx.server.options.storageManager.evaluateContent(ctx, _this, estimatedSize, function (estimatedSizeStored) {
ctx.server.options.storageManager.reserve(ctx, _this, estimatedSizeStored - sizeStored, function (reserved) {
if (!reserved)
return callback(Errors_1.Errors.InsufficientStorage);
finalGo(callback);
});
});
}
});
});
};
var createAndGo = function (intermediates) {
_this.create(ctx, path, CommonTypes_1.ResourceType.File, intermediates, function (e) {
if (e)
Expand Down Expand Up @@ -671,8 +740,25 @@ var FileSystem = (function () {
});
},
getProperties: function (callback, byCopy) {
var _this = this;
issuePrivilegeCheck(fs, ctx, pPath, 'canReadProperties', callback, function () {
pm.getProperties(callback, byCopy);
pm.getProperties(function (e, bag) {
if (!bag)
return callback(e, bag);
ctx.server.options.storageManager.available(ctx, _this, function (availableSize) {
if (availableSize === -1)
return callback(e, bag);
ctx.server.options.storageManager.reserved(ctx, _this, function (reservedSize) {
bag['DAV:quota-available-bytes'] = {
value: availableSize.toString()
};
bag['DAV:quota-used-bytes'] = {
value: reservedSize.toString()
};
callback(e, bag);
});
});
}, byCopy);
});
}
});
Expand Down
35 changes: 35 additions & 0 deletions lib/manager/v2/fileSystem/StorageManager.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { RequestContext } from '../../../server/v2/RequestContext';
import { Path } from '../Path';
import { ResourceType, ResourcePropertyValue, PropertyAttributes } from './CommonTypes';
import { FileSystem } from './FileSystem';
export declare type IStorageManagerEvaluateCallback = (size: number) => void;
export interface IStorageManager {
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
}
export declare class NoStorageManager implements IStorageManager {
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
}
export declare class PerUserStorageManager implements IStorageManager {
limitPerUser: number;
storage: {
[UUID: string]: number;
};
constructor(limitPerUser: number);
reserve(ctx: RequestContext, fs: FileSystem, size: number, callback: (reserved: boolean) => void): void;
evaluateCreate(ctx: RequestContext, fs: FileSystem, path: Path, type: ResourceType, callback: IStorageManagerEvaluateCallback): void;
evaluateContent(ctx: RequestContext, fs: FileSystem, expectedSize: number, callback: IStorageManagerEvaluateCallback): void;
evalPropValue(value: ResourcePropertyValue): number;
evaluateProperty(ctx: RequestContext, fs: FileSystem, name: string, value: ResourcePropertyValue, attributes: PropertyAttributes, callback: IStorageManagerEvaluateCallback): void;
available(ctx: RequestContext, fs: FileSystem, callback: (available: number) => void): void;
reserved(ctx: RequestContext, fs: FileSystem, callback: (reserved: number) => void): void;
}
75 changes: 75 additions & 0 deletions lib/manager/v2/fileSystem/StorageManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var NoStorageManager = (function () {
function NoStorageManager() {
}
NoStorageManager.prototype.reserve = function (ctx, fs, size, callback) {
callback(true);
};
NoStorageManager.prototype.evaluateCreate = function (ctx, fs, path, type, callback) {
callback(0);
};
NoStorageManager.prototype.evaluateContent = function (ctx, fs, expectedSize, callback) {
callback(0);
};
NoStorageManager.prototype.evaluateProperty = function (ctx, fs, name, value, attributes, callback) {
callback(0);
};
NoStorageManager.prototype.available = function (ctx, fs, callback) {
callback(-1);
};
NoStorageManager.prototype.reserved = function (ctx, fs, callback) {
callback(0);
};
return NoStorageManager;
}());
exports.NoStorageManager = NoStorageManager;
var PerUserStorageManager = (function () {
function PerUserStorageManager(limitPerUser) {
this.limitPerUser = limitPerUser;
this.storage = {};
}
PerUserStorageManager.prototype.reserve = function (ctx, fs, size, callback) {
var nb = this.storage[ctx.user.uid];
if (nb === undefined)
nb = 0;
nb += size;
if (nb > this.limitPerUser)
return callback(false);
this.storage[ctx.user.uid] = Math.max(0, nb);
callback(true);
};
PerUserStorageManager.prototype.evaluateCreate = function (ctx, fs, path, type, callback) {
fs.getFullPath(ctx, path, function (e, fullPath) {
callback(fullPath.toString().length);
});
};
PerUserStorageManager.prototype.evaluateContent = function (ctx, fs, expectedSize, callback) {
callback(expectedSize);
};
PerUserStorageManager.prototype.evalPropValue = function (value) {
var _this = this;
if (!value)
return 0;
if (value.constructor === String)
return value.length;
if (Array.isArray(value))
return value.map(function (el) { return _this.evalPropValue(el); }).reduce(function (p, n) { return p + n; }, 0);
var xml = value;
var attributesLength = Object.keys(xml.attributes).map(function (at) { return at.length + xml.attributes[at].length; }).reduce(function (p, n) { return p + n; }, 0);
return xml.name.length + attributesLength + (xml.elements && xml.elements.length > 0 ? this.evalPropValue(xml.elements) : 0);
};
PerUserStorageManager.prototype.evaluateProperty = function (ctx, fs, name, value, attributes, callback) {
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));
};
PerUserStorageManager.prototype.available = function (ctx, fs, callback) {
var nb = this.storage[ctx.user.uid];
callback(nb === undefined ? this.limitPerUser : this.limitPerUser - nb);
};
PerUserStorageManager.prototype.reserved = function (ctx, fs, callback) {
var nb = this.storage[ctx.user.uid];
callback(nb === undefined ? 0 : nb);
};
return PerUserStorageManager;
}());
exports.PerUserStorageManager = PerUserStorageManager;
1 change: 1 addition & 0 deletions lib/manager/v2/fileSystem/export.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './Resource';
export * from './Serialization';
export * from './StandardMethods';
export * from './ContextInfo';
export * from './StorageManager';
1 change: 1 addition & 0 deletions lib/manager/v2/fileSystem/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ __export(require("./PropertyManager"));
__export(require("./Resource"));
__export(require("./Serialization"));
__export(require("./StandardMethods"));
__export(require("./StorageManager"));
4 changes: 3 additions & 1 deletion lib/server/v2/WebDAVServerOptions.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/// <reference types="node" />
import { IStorageManager } from '../../manager/v2/fileSystem/StorageManager';
import { FileSystemSerializer } from '../../manager/v2/fileSystem/Serialization';
import { HTTPAuthentication } from '../../user/v2/authentication/HTTPAuthentication';
import { Writable, Readable } from 'stream';
import { PrivilegeManager } from '../../user/v2/privilege/PrivilegeManager';
import { FileSystem } from '../../manager/v2/fileSystem/FileSystem';
import { FileSystemSerializer } from '../../manager/v2/fileSystem/Serialization';
import * as https from 'https';
export interface IAutoSave {
treeFilePath: string;
Expand All @@ -30,6 +31,7 @@ export declare class WebDAVServerOptions {
version?: string;
autoSave?: IAutoSave;
autoLoad?: IAutoLoad;
storageManager?: IStorageManager;
}
export default WebDAVServerOptions;
export declare function setDefaultServerOptions(options: WebDAVServerOptions): WebDAVServerOptions;
6 changes: 4 additions & 2 deletions lib/server/v2/WebDAVServerOptions.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var StorageManager_1 = require("../../manager/v2/fileSystem/StorageManager");
var HTTPDigestAuthentication_1 = require("../../user/v2/authentication/HTTPDigestAuthentication");
var PrivilegeManager_1 = require("../../user/v2/privilege/PrivilegeManager");
var SimpleUserManager_1 = require("../../user/v2/simple/SimpleUserManager");
var VirtualFileSystem_1 = require("../../manager/v2/instances/VirtualFileSystem");
var SimpleUserManager_1 = require("../../user/v2/simple/SimpleUserManager");
var PrivilegeManager_1 = require("../../user/v2/privilege/PrivilegeManager");
var WebDAVServerOptions = (function () {
function WebDAVServerOptions() {
this.requireAuthentification = false;
Expand All @@ -19,6 +20,7 @@ var WebDAVServerOptions = (function () {
this.version = '1.8.0';
this.autoSave = null;
this.autoLoad = null;
this.storageManager = new StorageManager_1.NoStorageManager();
}
return WebDAVServerOptions;
}());
Expand Down
1 change: 0 additions & 1 deletion lib/server/v2/commands/Propfind.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ var default_1 = (function () {
for (var name_1 in properties) {
if (reqBody.mustDisplay(name_1)) {
var tag = prop.ele(name_1);
console.log(name_1, tag);
if (reqBody.mustDisplayValue(name_1)) {
var property = properties[name_1];
if (tag.attributes)
Expand Down

0 comments on commit 74094e3

Please sign in to comment.