Add DatabaseStore
This commit is contained in:
parent
1ad41d7e58
commit
4bdd7a1e3b
|
@ -1,4 +1,5 @@
|
|||
import { FileStore } from './filestore';
|
||||
import { DatabaseStore } from './dbstore';
|
||||
|
||||
const CHANNEL_STORE = new FileStore();
|
||||
|
||||
|
|
83
src/channel-storage/dbstore.js
Normal file
83
src/channel-storage/dbstore.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
import Promise from 'bluebird';
|
||||
import { ChannelStateSizeError,
|
||||
ChannelDataNotFoundError } from '../errors';
|
||||
import db from '../database';
|
||||
import Logger from '../logger';
|
||||
|
||||
const SIZE_LIMIT = 1048576;
|
||||
const QUERY_CHANNEL_ID_FOR_NAME = 'SELECT id FROM channels WHERE name = ?';
|
||||
const QUERY_CHANNEL_DATA = 'SELECT `key`, `value` FROM channel_data WHERE channel_id = ?';
|
||||
const QUERY_UPDATE_CHANNEL_DATA =
|
||||
'INSERT INTO channel_data VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `value` = ?';
|
||||
|
||||
function queryAsync(query, substitutions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.query(query, substitutions, (err, res) => {
|
||||
if (err) {
|
||||
if (!(err instanceof Error)) {
|
||||
err = new Error(err);
|
||||
}
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export class DatabaseStore {
|
||||
load(channelName) {
|
||||
return queryAsync(QUERY_CHANNEL_ID_FOR_NAME, [channelName]).then((rows) => {
|
||||
if (rows.length === 0) {
|
||||
throw new ChannelNotFoundError(`Channel does not exist: "${channelName}"`);
|
||||
}
|
||||
|
||||
return queryAsync(QUERY_CHANNEL_DATA, [rows[0].id]);
|
||||
}).then(rows => {
|
||||
const data = {};
|
||||
for (const row of rows) {
|
||||
try {
|
||||
data[row.key] = JSON.parse(row.value);
|
||||
} catch (e) {
|
||||
Logger.errlog.log(`Channel data for channel "${channelName}", ` +
|
||||
`key "${row.key}" is invalid: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
save(channelName, data) {
|
||||
return queryAsync(QUERY_CHANNEL_ID_FOR_NAME, [channelName]).then((rows) => {
|
||||
if (rows.length === 0) {
|
||||
throw new ChannelNotFoundError(`Channel does not exist: "${channelName}"`);
|
||||
}
|
||||
|
||||
let totalSize = 0;
|
||||
const id = rows[0].id;
|
||||
const substitutions = [];
|
||||
for (const key of Object.keys(data)) {
|
||||
const value = JSON.stringify(data[key]);
|
||||
totalSize += value.length;
|
||||
substitutions.push([
|
||||
id,
|
||||
key,
|
||||
value,
|
||||
value // Extra substitution var necessary for ON DUPLICATE KEY UPDATE
|
||||
]);
|
||||
}
|
||||
|
||||
if (totalSize > SIZE_LIMIT) {
|
||||
throw new ChannelStateSizeError('Channel state size is too large', {
|
||||
limit: SIZE_LIMIT,
|
||||
actual: totalSize
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.map(substitutions, entry => {
|
||||
return queryAsync(QUERY_UPDATE_CHANNEL_DATA, entry);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -104,6 +104,15 @@ const TBL_BANS = "" +
|
|||
"INDEX (`ip`, `channel`), INDEX (`name`, `channel`)" +
|
||||
") CHARACTER SET utf8";
|
||||
|
||||
const TBL_CHANNEL_DATA = "" +
|
||||
"CREATE TABLE IF NOT EXISTS `channel_data` (" +
|
||||
"`channel_id` INT NOT NULL," +
|
||||
"`key` VARCHAR(20) NOT NULL," +
|
||||
"`value` TEXT CHARACTER SET utf8mb4 NOT NULL," +
|
||||
"PRIMARY KEY (`channel_id`, `key`)," +
|
||||
"FOREIGN KEY (`channel_id`) REFERENCES `channels`(`id`) ON DELETE CASCADE" +
|
||||
") CHARACTER SET utf8";
|
||||
|
||||
module.exports.init = function (queryfn, cb) {
|
||||
var tables = {
|
||||
users: TBL_USERS,
|
||||
|
@ -116,7 +125,8 @@ module.exports.init = function (queryfn, cb) {
|
|||
user_playlists: TBL_USER_PLAYLISTS,
|
||||
aliases: TBL_ALIASES,
|
||||
stats: TBL_STATS,
|
||||
meta: TBL_META
|
||||
meta: TBL_META,
|
||||
channel_data: TBL_CHANNEL_DATA
|
||||
};
|
||||
|
||||
var AsyncQueue = require("../asyncqueue");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import createError from 'create-error';
|
||||
|
||||
export const ChannelStateSizeError = createError('ChannelStateSizeError');
|
||||
export const ChannelNotFoundError = createError('ChannelNotFoundError');
|
||||
|
|
Loading…
Reference in a new issue