2018-02-06 22:31:18 +00:00
|
|
|
const config = require('../config');
|
|
|
|
const Metadata = require('../metadata');
|
|
|
|
const mozlog = require('../log');
|
|
|
|
const createRedisClient = require('./redis');
|
|
|
|
|
2018-09-24 22:08:39 +00:00
|
|
|
function getPrefix(seconds) {
|
|
|
|
return Math.max(Math.floor(seconds / 86400), 1);
|
|
|
|
}
|
|
|
|
|
2018-02-06 22:31:18 +00:00
|
|
|
class DB {
|
|
|
|
constructor(config) {
|
2018-10-05 18:01:58 +00:00
|
|
|
let Storage = null;
|
|
|
|
if (config.s3_bucket) {
|
|
|
|
Storage = require('./s3');
|
|
|
|
} else if (config.gcs_bucket) {
|
|
|
|
Storage = require('./gcs');
|
|
|
|
} else {
|
|
|
|
Storage = require('./fs');
|
|
|
|
}
|
2018-02-06 22:31:18 +00:00
|
|
|
this.log = mozlog('send.storage');
|
2018-08-08 18:07:09 +00:00
|
|
|
|
2018-08-09 21:49:52 +00:00
|
|
|
this.storage = new Storage(config, this.log);
|
2018-08-08 18:07:09 +00:00
|
|
|
|
2018-02-06 22:31:18 +00:00
|
|
|
this.redis = createRedisClient(config);
|
|
|
|
this.redis.on('error', err => {
|
|
|
|
this.log.error('Redis:', err);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async ttl(id) {
|
|
|
|
const result = await this.redis.ttlAsync(id);
|
|
|
|
return Math.ceil(result) * 1000;
|
|
|
|
}
|
|
|
|
|
2020-07-25 18:22:57 +00:00
|
|
|
async getPrefixedInfo(id) {
|
2020-07-13 17:21:28 +00:00
|
|
|
const [prefix, dead, flagged] = await this.redis.hmgetAsync(
|
|
|
|
id,
|
|
|
|
'prefix',
|
|
|
|
'dead',
|
|
|
|
'flagged'
|
|
|
|
);
|
2020-07-25 18:22:57 +00:00
|
|
|
return {
|
|
|
|
filePath: `${prefix}-${id}`,
|
|
|
|
flagged,
|
|
|
|
dead
|
|
|
|
};
|
2018-02-06 22:31:18 +00:00
|
|
|
}
|
|
|
|
|
2018-08-08 18:07:09 +00:00
|
|
|
async length(id) {
|
2020-07-25 18:22:57 +00:00
|
|
|
const { filePath } = await this.getPrefixedInfo(id);
|
2018-08-09 21:49:52 +00:00
|
|
|
return this.storage.length(filePath);
|
2018-02-06 22:31:18 +00:00
|
|
|
}
|
|
|
|
|
2018-08-08 18:07:09 +00:00
|
|
|
async get(id) {
|
2020-07-25 18:22:57 +00:00
|
|
|
const info = await this.getPrefixedInfo(id);
|
|
|
|
if (info.dead || info.flagged) {
|
|
|
|
throw new Error(info.flagged ? 'flagged' : 'dead');
|
|
|
|
}
|
|
|
|
return this.storage.getStream(info.filePath);
|
2018-08-08 18:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async set(id, file, meta, expireSeconds = config.default_expire_seconds) {
|
2018-09-24 22:08:39 +00:00
|
|
|
const prefix = getPrefix(expireSeconds);
|
2018-08-09 21:49:52 +00:00
|
|
|
const filePath = `${prefix}-${id}`;
|
|
|
|
await this.storage.set(filePath, file);
|
2018-12-18 21:55:46 +00:00
|
|
|
if (meta) {
|
2020-07-13 17:21:28 +00:00
|
|
|
this.redis.hmset(id, { prefix, ...meta });
|
|
|
|
} else {
|
|
|
|
this.redis.hset(id, 'prefix', prefix);
|
2018-12-18 21:55:46 +00:00
|
|
|
}
|
2018-08-08 18:07:09 +00:00
|
|
|
this.redis.expire(id, expireSeconds);
|
2018-02-06 22:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
setField(id, key, value) {
|
|
|
|
this.redis.hset(id, key, value);
|
|
|
|
}
|
|
|
|
|
2019-04-19 11:10:49 +00:00
|
|
|
incrementField(id, key, increment = 1) {
|
|
|
|
this.redis.hincrby(id, key, increment);
|
|
|
|
}
|
|
|
|
|
2020-07-25 18:22:57 +00:00
|
|
|
async kill(id) {
|
2020-07-25 22:36:09 +00:00
|
|
|
const { filePath, dead } = await this.getPrefixedInfo(id);
|
|
|
|
if (!dead) {
|
|
|
|
this.storage.del(filePath);
|
|
|
|
this.redis.hset(id, 'dead', 1);
|
|
|
|
}
|
2020-07-13 17:21:28 +00:00
|
|
|
}
|
|
|
|
|
2020-07-25 22:36:09 +00:00
|
|
|
async flag(id) {
|
2020-07-25 18:22:57 +00:00
|
|
|
await this.kill(id);
|
2020-07-25 22:36:09 +00:00
|
|
|
this.redis.hset(id, 'flagged', 1);
|
2020-07-13 17:21:28 +00:00
|
|
|
}
|
|
|
|
|
2018-08-08 18:07:09 +00:00
|
|
|
async del(id) {
|
2020-07-25 18:22:57 +00:00
|
|
|
const { filePath } = await this.getPrefixedInfo(id);
|
2018-08-09 21:49:52 +00:00
|
|
|
this.storage.del(filePath);
|
2018-02-06 22:31:18 +00:00
|
|
|
this.redis.del(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
async ping() {
|
|
|
|
await this.redis.pingAsync();
|
2018-08-09 21:49:52 +00:00
|
|
|
await this.storage.ping();
|
2018-02-06 22:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async metadata(id) {
|
|
|
|
const result = await this.redis.hgetallAsync(id);
|
|
|
|
return result && new Metadata(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = new DB(config);
|