@universis/user-storage
Version:
Universis Api Server Extension for managing user remote storage
214 lines (147 loc) • 7.64 kB
JavaScript
;
var _common = require("@themost/common");
var redis = _interopRequireWildcard(require("redis"));
var _service = require("./service");
var _es6Promisify = require("es6-promisify");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const REDIS_JSON_COMMANDS = ["json.del", "json.get", "json.mget", "json.set", "json.type", "json.numincrby", "json.nummultby", "json.strappend", "json.strlen", "json.arrappend", "json.arrindex", "json.arrinsert", "json.arrlen", "json.arrpop", "json.arrtrim", "json.objkeys", "json.objlen", "json.debug", "json.forget", "json.resp"];
function createJsonClient(options) {
// add json commands
REDIS_JSON_COMMANDS.forEach(command => {
// noinspection JSUnresolvedFunction
redis.addCommand(command);
}); // and finally return client
return redis.createClient(options);
}
class RedisUserStorageService extends _service.UserStorageService {
/**
* Formats a path like key string to a redis command compatible key e.g. user1/application1/lastAction to .user1.application1.lastAction
* @param key
* @returns {string|*}
*/
static escapeKey(key) {
let res = key.replace(/\//ig, '.');
if (/^\./.test(res)) {
return res;
}
return '.' + res;
}
/**
* @param {IApplication} app
*/
constructor(app) {
super(app);
}
/**
* @name RedisClient#json_set
* @param {*} ...args
*/
/**
* @name RedisClient#json_get
* @param {*} ...args
*/
/**
*
* @param {DataContext} context
* @param {string} key
* @param {*} value
* @param {number=} expiration
*/
async setItem(context, key, value, expiration) {
// validate user
const hasAccess = await context.getConfiguration().getStrategy(_service.UserStorageAccessConfiguration).verify(context, `me/${key}`, 'write');
if (hasAccess == null) {
throw new _common.AccessDeniedError('Write access to the specified user storage key is denied');
} // create redis client
const client = createJsonClient(this.options);
const json_set = (0, _es6Promisify.promisify)(client.json_set).bind(client); // noinspection JSUnresolvedVariable
const json_type = (0, _es6Promisify.promisify)(client.json_type).bind(client);
const quit = (0, _es6Promisify.promisify)(client.quit).bind(client); // validate root object
//split key e.g. .key1.key2.key3 to an array of [ '', 'key1', 'key2', 'key3' ]
const keys = _service.UserStorageService.escapeKey(key).split('.'); // enumerate existence of keys from [1] to [length - 1] in order to avoid redis errors
for (let i = 0; i < keys.length - 1; i++) {
let key1 = keys.slice(0, i + 1).join('.'); // ensure root key
if (i === 0) {
key1 = '.';
} // validate key e.g. .key1 and .key1.key2
const value1 = await json_type(`${context.user.name}`, key1); // if key does not exist
if (value1 == null) {
// set value
await json_set(`${context.user.name}`, key1, JSON.stringify({}));
}
}
if (typeof expiration === "number" && expiration > 0) {
// call json_set() with expiration
await json_set(`${context.user.name}`, _service.UserStorageService.escapeKey(key), 'EX', Math.ceil(expiration), JSON.stringify(value)); // close client
await quit(); // and return
return value;
} // call json_set() with expiration
await json_set(`${context.user.name}`, _service.UserStorageService.escapeKey(key), JSON.stringify(value)); // close client
await quit(); // and return
return value;
}
/**
* @param {DataContext} context
* @param {string} key
*/
async getItem(context, key) {
// validate user
const hasAccess = await context.getConfiguration().getStrategy(_service.UserStorageAccessConfiguration).verify(context, `me/${key}`, 'read');
if (hasAccess == null) {
throw new _common.AccessDeniedError('Read access to the specified user storage key is denied');
} // create redis client
const client = createJsonClient(this.options); // noinspection JSUnresolvedVariable
const json_type = (0, _es6Promisify.promisify)(client.json_type).bind(client);
const json_get = (0, _es6Promisify.promisify)(client.json_get).bind(client); // noinspection JSUnresolvedVariable
const quit = (0, _es6Promisify.promisify)(client.quit).bind(client); // call json_get()
const type = await json_type(`${context.user.name}`, _service.UserStorageService.escapeKey(key));
if (type == null) {
return null;
} // get value
const res = await json_get(`${context.user.name}`, 'NOESCAPE', _service.UserStorageService.escapeKey(key)); // quit
await quit(); // if value is not null
if (res != null) {
// parse string value and return
return JSON.parse(res);
}
return res;
}
/**
* @param {DataContext} context
* @param {string} key
* @returns Promise<*>
*/
async removeItem(context, key) {
// validate user access
const hasAccess = await context.getConfiguration().getStrategy(_service.UserStorageAccessConfiguration).verify(context, `me/${key}`, 'write');
if (hasAccess == null) {
throw new _common.AccessDeniedError('Write access to the specified user storage key is denied');
} // create redis client
const client = createJsonClient(this.options); // noinspection JSUnresolvedVariable
const json_del = (0, _es6Promisify.promisify)(client.json_del).bind(client);
const quit = (0, _es6Promisify.promisify)(client.quit).bind(client); // call json_del()
const res = await json_del(`${context.user.name}`, _service.UserStorageService.escapeKey(key)); // close client
await quit(); // and return
return res === 1;
}
/**
* @param {DataContext} context
* @returns Promise<*>
*/
async clear(context) {
// validate user access
const hasAccess = context.getConfiguration().getStrategy(_service.UserStorageAccessConfiguration).verify(context, `me`, 'write');
if (hasAccess == null) {
throw new _common.AccessDeniedError('Write access to the specified user storage key is denied');
} // create redis client
const client = createJsonClient(this.options);
const del = (0, _es6Promisify.promisify)(client.del).bind(client);
const quit = (0, _es6Promisify.promisify)(client.quit).bind(client); // call json_del()
const res = await del(`${context.user.name}`);
await quit();
return res === 1;
}
}
module.exports.RedisUserStorageService = RedisUserStorageService;
//# sourceMappingURL=redis.js.map