init commit

This commit is contained in:
rainbownapkin 2021-12-06 19:56:40 -05:00
parent ae639426d0
commit 7a491681cc
257 changed files with 95524 additions and 80 deletions

View 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();
}

View 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();

View 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);
}
}