init commit
This commit is contained in:
parent
ae639426d0
commit
7a491681cc
257 changed files with 95524 additions and 80 deletions
36
src/channel-storage/channelstore.js
Normal file
36
src/channel-storage/channelstore.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { DatabaseStore } from './dbstore';
|
||||
import Config from '../config';
|
||||
import Promise from 'bluebird';
|
||||
|
||||
var CHANNEL_STORE = null;
|
||||
|
||||
export function init() {
|
||||
CHANNEL_STORE = loadChannelStore();
|
||||
}
|
||||
|
||||
export function load(id, channelName) {
|
||||
if (CHANNEL_STORE === null) {
|
||||
return Promise.reject(new Error('ChannelStore not initialized yet'));
|
||||
}
|
||||
|
||||
return CHANNEL_STORE.load(id, channelName);
|
||||
}
|
||||
|
||||
export function save(id, channelName, data) {
|
||||
if (CHANNEL_STORE === null) {
|
||||
return Promise.reject(new Error('ChannelStore not initialized yet'));
|
||||
}
|
||||
|
||||
return CHANNEL_STORE.save(id, channelName, data);
|
||||
}
|
||||
|
||||
function loadChannelStore() {
|
||||
if (Config.get('channel-storage.type') === 'file') {
|
||||
throw new Error(
|
||||
'channel-storage type "file" is no longer supported. Please see ' +
|
||||
'NEWS.md for instructions on upgrading.'
|
||||
);
|
||||
}
|
||||
|
||||
return new DatabaseStore();
|
||||
}
|
||||
24
src/channel-storage/db-chandump.js
Normal file
24
src/channel-storage/db-chandump.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import Promise from 'bluebird';
|
||||
|
||||
import Config from '../config';
|
||||
import db from '../database';
|
||||
import { DatabaseStore } from './dbstore';
|
||||
|
||||
/* eslint no-console: off */
|
||||
function main() {
|
||||
Config.load('config.yaml');
|
||||
db.init();
|
||||
const dbStore = new DatabaseStore();
|
||||
|
||||
Promise.delay(1000).then(() => {
|
||||
return dbStore.load(process.argv[2]);
|
||||
}).then((data) => {
|
||||
console.log(JSON.stringify(data, null, 4));
|
||||
process.exit(0);
|
||||
}).catch((err) => {
|
||||
console.error(`Error retrieving channel data: ${err.stack}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
122
src/channel-storage/dbstore.js
Normal file
122
src/channel-storage/dbstore.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import Promise from 'bluebird';
|
||||
import { ChannelStateSizeError } from '../errors';
|
||||
import db from '../database';
|
||||
import { Counter } from 'prom-client';
|
||||
|
||||
const LOGGER = require('@calzoneman/jsli')('dbstore');
|
||||
const SIZE_LIMIT = 1048576;
|
||||
const QUERY_CHANNEL_DATA = 'SELECT `key`, `value` FROM channel_data WHERE channel_id = ?';
|
||||
const loadRowcount = new Counter({
|
||||
name: 'cytube_channel_db_load_rows_total',
|
||||
help: 'Total rows loaded from the channel_data table'
|
||||
});
|
||||
const loadCharcount = new Counter({
|
||||
name: 'cytube_channel_db_load_chars_total',
|
||||
help: 'Total characters (JSON length) loaded from the channel_data table'
|
||||
});
|
||||
const saveRowcount = new Counter({
|
||||
name: 'cytube_channel_db_save_rows_total',
|
||||
help: 'Total rows saved in the channel_data table'
|
||||
});
|
||||
const saveCharcount = new Counter({
|
||||
name: 'cytube_channel_db_save_chars_total',
|
||||
help: 'Total characters (JSON length) saved in the channel_data table'
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function buildUpdateQuery(numEntries) {
|
||||
const values = [];
|
||||
for (let i = 0; i < numEntries; i++) {
|
||||
values.push('(?, ?, ?)');
|
||||
}
|
||||
|
||||
return `INSERT INTO channel_data VALUES ${values.join(', ')} ` +
|
||||
'ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)';
|
||||
}
|
||||
|
||||
export class DatabaseStore {
|
||||
load(id, channelName) {
|
||||
if (!id || id === 0) {
|
||||
return Promise.reject(new Error(`Cannot load state for [${channelName}]: ` +
|
||||
`id was passed as [${id}]`));
|
||||
}
|
||||
|
||||
return queryAsync(QUERY_CHANNEL_DATA, [id]).then(rows => {
|
||||
loadRowcount.inc(rows.length);
|
||||
|
||||
const data = {};
|
||||
rows.forEach(row => {
|
||||
try {
|
||||
data[row.key] = JSON.parse(row.value);
|
||||
loadCharcount.inc(row.value.length);
|
||||
} catch (e) {
|
||||
LOGGER.error(`Channel data for channel "${channelName}", ` +
|
||||
`key "${row.key}" is invalid: ${e}`);
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
async save(id, channelName, data) {
|
||||
if (!id || id === 0) {
|
||||
throw new Error(
|
||||
`Cannot save state for [${channelName}]: ` +
|
||||
`id was passed as [${id}]`
|
||||
);
|
||||
}
|
||||
|
||||
let totalSize = 0;
|
||||
let rowCount = 0;
|
||||
const substitutions = [];
|
||||
|
||||
for (const key in data) {
|
||||
if (typeof data[key] === 'undefined') {
|
||||
continue;
|
||||
}
|
||||
|
||||
rowCount++;
|
||||
|
||||
const value = JSON.stringify(data[key]);
|
||||
totalSize += value.length;
|
||||
|
||||
substitutions.push(id);
|
||||
substitutions.push(key);
|
||||
substitutions.push(value);
|
||||
}
|
||||
|
||||
if (rowCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalSize > SIZE_LIMIT) {
|
||||
throw new ChannelStateSizeError(
|
||||
'Channel state size is too large',
|
||||
{
|
||||
limit: SIZE_LIMIT,
|
||||
actual: totalSize
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
saveRowcount.inc(rowCount);
|
||||
saveCharcount.inc(totalSize);
|
||||
|
||||
return await queryAsync(buildUpdateQuery(rowCount), substitutions);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue