chabrador
Version:
A key-incrementer database stored in memory.
206 lines (187 loc) • 6.46 kB
JavaScript
/* *******************************************************
* chabrador
*
* @license
*
* Apache-2.0
*
* Copyright 2019-2025 Alex Stevovich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @meta
*
* package_name: chabrador
* file_name: src/index.js
* purpose: Core functionality and exports combined.
*
* @system
*
* generated_on: 2025-03-12T22:41:53.666Z
* certified_version: 1.0.0
* file_uuid: 31b39b2d-eba2-4494-9c17-fb02b9eba957
* file_size: 6287 bytes
* file_hash: ff156d88bb566bfd9f970fc025facbfde99af2c9ae0f193ec632214a514386b2
* mast_hash: a603c6ece7943d0e6a421c117903c8876bfc2b1667e8ccc9595c18b74c0c6a2c
* generated_by: preamble on npm!
*
* [Preamble Metadata]
********************************************************/
import fs from 'fs/promises';
import path from 'path';
import chalk from 'chalk';
const pluginHexColor = 'c999ff';
function doFanfare(logger) {
const art = String.raw`
;\
|' \
_ ; : ;
/ '-. /: : |
| ,-.'-. ,': : |
\ : '. '. ,'-. : |
\ ; ; '-.__,' '-.|
\ ; ; ::: ,::'':. '.
\ '-. : ' :. '. \
\ \ , ; ,: (\
\ :., :. ,'o)): ' '-.
,/,' ;' ,::"''.'---' '. '-._
,/ : ; '" ';' ,--'.
;/ :; ; ,:' ( ,:)
,.,:. ; ,:., ,-._ '. \""'/
'::' ':'' ,'( \'._____.-'"'
;, ; '. '. '._'-. \\
;:. ;: '-._'-.\ \'.
'':. : |' '. '\ ) \
${chalk.white.bold('-chabrador-')} ' ;: | '--\__,'
'' ,'
,-'
`;
art.split('\n').forEach((line) => {
logger.info(chalk.hex(pluginHexColor).bold(line));
});
}
class KeyValType {
static SUCCESS = 'SUCCESS';
static WARN = 'WARN';
static ERROR = 'ERROR';
static PENDING = 'PENDING';
}
function logKeyVal(key, value, type) {
const outputKey =
chalk.hex(pluginHexColor).bold(`CHABRADOR`) +
chalk.hex('#FFFFFF').bold(`.${key}:`);
let color = chalk.hex('FFFFFF');
if (type == KeyValType.SUCCESS) {
color = chalk.hex('00FF00').bold(value);
} else if (type == KeyValType.WARN) {
color = chalk.hex('ffd642').bold(value);
} else if (type == KeyValType.ERROR) {
color = chalk.hex('FF0000').bold(value);
} else if (type == KeyValType.PENDING) {
color = chalk.bgHex('#2c79e6').bold(` ${value} `);
}
const outputValue = color;
return `${outputKey} ${outputValue}`;
}
export class Chabrador {
constructor({
filePath = 'chabrador-memory.json',
backupInterval = 600000, // 10 minutes
maxEntries = 250000, // Auto-delete if exceeded
logger = console, // Allow external logger, default to console
fanfare = false,
} = {}) {
this._filePath = path.resolve(filePath);
this._memory = { overflows: [], entries: {} }; // Always fresh
this._backupInterval = backupInterval;
this._maxEntries = maxEntries;
this._loaded = false;
this.logger = logger;
if (fanfare) {
doFanfare(logger);
}
this.logger.info(logKeyVal('status', 'Online', KeyValType.SUCCESS));
this._startAutoSave();
}
async load() {
this.logger.info(logKeyVal('load-memory', 'Start', KeyValType.PENDING));
try {
const content = await fs.readFile(this._filePath, 'utf-8');
const data = JSON.parse(content);
this._memory = {
overflows: Array.isArray(data.overflows) ? data.overflows : [],
entries: typeof data.entries === 'object' ? data.entries : {},
};
this._loaded = true;
this.logger.info(
logKeyVal('load-memory', 'Success', KeyValType.SUCCESS),
);
} catch {
this.logger.warn(logKeyVal('load-memory', 'New', KeyValType.WARN));
this._memory = { overflows: [], entries: {} };
}
}
boop(id) {
const now = Date.now();
if (!this._memory.entries[id]) {
this._memory.entries[id] = { c: 1, t: now };
} else {
this._memory.entries[id].c += 1;
this._memory.entries[id].t = now;
}
this._handleOverflow();
}
_handleOverflow() {
const entryCount = Object.keys(this._memory.entries).length;
if (entryCount > this._maxEntries) {
this._memory.overflows.push({ t: Date.now(), c: entryCount });
this._memory.entries = {}; // Purge entries
this.logger.warn(
logKeyVal('overflow-memory', '⚠️ Success', KeyValType.SUCCESS),
);
}
}
async save() {
try {
await fs.writeFile(
this._filePath,
JSON.stringify(this._memory, null, 2),
);
this.logger.info(
logKeyVal('memory.task.save', 'complete', KeyValType.SUCCESS),
);
} catch (error) {
this.logger.error('❌ Error saving Chabrador database:', error);
this.logger.error(
logKeyVal('memory.task.save', 'error', KeyValType.ERROR),
);
}
}
reset() {
this._memory = { overflows: [], entries: {} };
this.logger.info(
logKeyVal('reset-memory', 'Memory Cleared', KeyValType.SUCCESS),
);
}
_startAutoSave() {
setInterval(() => {
this.save();
}, this._backupInterval);
}
}
export async function adopt(options) {
const chabrador = new Chabrador(options);
await chabrador.load();
return chabrador;
}
export default { adopt, Chabrador };