changes to localstorage: +gzip compression
parent
5544354727
commit
947140a4c8
|
@ -17,14 +17,14 @@ export default class Client extends eris.Client {
|
|||
|
||||
public serverManagement: ServerManagement;
|
||||
|
||||
public db: { Member: mongoose.Model<MemberInterface>, Moderation: mongoose.Model<ModerationInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface>, local: LocalStorage };
|
||||
public db: { Member: mongoose.Model<MemberInterface>, Moderation: mongoose.Model<ModerationInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface>, local: { muted: LocalStorage } };
|
||||
|
||||
constructor(token: string, options?: eris.ClientOptions) {
|
||||
super(token, options);
|
||||
this.commands = new Collection<Command>();
|
||||
this.events = new Collection<Event>();
|
||||
this.intervals = new Collection<NodeJS.Timeout>();
|
||||
this.db = { Member, Moderation, PagerNumber, Rank, Redirect, local: new LocalStorage(this) };
|
||||
this.db = { Member, Moderation, PagerNumber, Rank, Redirect, local: { muted: new LocalStorage('muted') } };
|
||||
}
|
||||
|
||||
public async loadDatabase() {
|
||||
|
|
|
@ -1,37 +1,65 @@
|
|||
/* eslint-disable no-constant-condition */
|
||||
import { promises as fs, constants } from 'fs';
|
||||
import { Client } from '.';
|
||||
import { promises as fs, accessSync, constants, writeFileSync } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { gzip, gzipSync, unzip } from 'zlib';
|
||||
|
||||
type JSONData = [{key: string, value: any}?];
|
||||
|
||||
|
||||
/**
|
||||
* Persistant local JSON-based storage.
|
||||
* Auto-locking system to prevent corrupted data.
|
||||
* - auto-locking system to prevent corrupted data
|
||||
* - uses gzip compression to keep DB storage space utilization low
|
||||
* @author Matthew <matthew@staff.libraryofcode.org>
|
||||
*/
|
||||
export default class LocalStorage {
|
||||
private client: Client;
|
||||
|
||||
protected storagePath: string;
|
||||
|
||||
private locked: boolean = false;
|
||||
|
||||
constructor(client: Client, storagePath = `${__dirname}/../../localstorage`) {
|
||||
this.client = client;
|
||||
this.storagePath = storagePath;
|
||||
constructor(dbName: string) {
|
||||
this.storagePath = `${__dirname}/../../localstorage/${dbName}.json.gz`;
|
||||
this.init();
|
||||
}
|
||||
|
||||
private async init() {
|
||||
private init() {
|
||||
try {
|
||||
await fs.access(`${this.storagePath}/1.json`, constants.F_OK);
|
||||
accessSync(this.storagePath, constants.F_OK);
|
||||
} catch {
|
||||
const setup = [];
|
||||
await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(setup), { encoding: 'utf8' });
|
||||
const data = gzipSync(JSON.stringify(setup));
|
||||
writeFileSync(this.storagePath, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses data using gzip.
|
||||
* @param data The data to be compressed.
|
||||
* ```ts
|
||||
* await LocalStorage.compress('hello!');
|
||||
* ```
|
||||
*/
|
||||
static async compress(data: string): Promise<Buffer> {
|
||||
const func = promisify(gzip);
|
||||
const comp = <Buffer> await func(data);
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompresses data using gzip.
|
||||
* @param data The data to be decompressed.
|
||||
* ```ts
|
||||
* const compressed = await LocalStorage.compress('data');
|
||||
* const decompressed = await LocalStorage.decompress(compressed);
|
||||
* console.log(decompressed); // logs 'data';
|
||||
* ```
|
||||
*/
|
||||
static async decompress(data: Buffer): Promise<string> {
|
||||
const func = promisify(unzip);
|
||||
const uncomp = <Buffer> await func(data);
|
||||
return uncomp.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves one data from the store.
|
||||
* If the store has multiple entries for the same key, this function will only return the first entry.
|
||||
|
@ -46,9 +74,10 @@ export default class LocalStorage {
|
|||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
this.locked = false;
|
||||
const json: JSONData = JSON.parse(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const result = json.filter((data) => data.key === key);
|
||||
if (!result[0]) return null;
|
||||
return result[0].value;
|
||||
|
@ -67,9 +96,10 @@ export default class LocalStorage {
|
|||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
this.locked = false;
|
||||
const json: JSONData = JSON.parse(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const result = json.filter((data) => data.key === key);
|
||||
if (result.length < 1) return null;
|
||||
return result;
|
||||
|
@ -90,10 +120,12 @@ export default class LocalStorage {
|
|||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
||||
const json: JSONData = JSON.parse(file);
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
json.push({ key, value });
|
||||
await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(json), { encoding: 'utf8' });
|
||||
const comp = await LocalStorage.compress(JSON.stringify(json));
|
||||
await fs.writeFile(this.storagePath, comp);
|
||||
this.locked = false;
|
||||
}
|
||||
|
||||
|
@ -111,10 +143,12 @@ export default class LocalStorage {
|
|||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
||||
const json: JSONData = JSON.parse(file);
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const filtered = json.filter((data) => data.key !== key);
|
||||
await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(filtered), { encoding: 'utf8' });
|
||||
const comp = await LocalStorage.compress(JSON.stringify(filtered));
|
||||
await fs.writeFile(this.storagePath, comp);
|
||||
this.locked = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ export default class Moderation {
|
|||
} else date = null;
|
||||
const expiration = { date, processed };
|
||||
mod.expiration = expiration;
|
||||
await this.client.db.local.set(`muted-${member.id}`, true);
|
||||
await this.client.db.local.muted.set(`muted-${member.id}`, true);
|
||||
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle(`Case ${logID} | Mute`);
|
||||
|
@ -171,7 +171,7 @@ export default class Moderation {
|
|||
date: new Date(),
|
||||
});
|
||||
|
||||
await this.client.db.local.del(`muted-${member.id}`);
|
||||
await this.client.db.local.muted.del(`muted-${member.id}`);
|
||||
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle(`Case ${logID} | Unmute`);
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class Mute extends Command {
|
|||
if (!member) return this.error(message.channel, 'Cannot find user.');
|
||||
|
||||
try {
|
||||
const res1 = await this.client.db.local.get<boolean>(`muted-${member.id}`);
|
||||
const res1 = await this.client.db.local.muted.get<boolean>(`muted-${member.id}`);
|
||||
if (res1 || this.mainGuild.members.get(member.id).roles.includes('478373942638149643')) return this.error(message.channel, 'This user is already muted.');
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.');
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class Unmute extends Command {
|
|||
if (!member) return this.error(message.channel, 'Cannot find user.');
|
||||
|
||||
try {
|
||||
const res1 = await this.client.db.local.get<boolean>(`muted-${member.id}`);
|
||||
const res1 = await this.client.db.local.muted.get<boolean>(`muted-${member.id}`);
|
||||
if (!res1 || !this.mainGuild.members.get(member.id).roles.includes('478373942638149643')) return this.error(message.channel, 'This user is already unmuted.');
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.');
|
||||
|
|
|
@ -11,7 +11,7 @@ export default class GuildMemberAdd extends Event {
|
|||
|
||||
public async run(_, member: Member) {
|
||||
try {
|
||||
const search = await this.client.db.local.get<boolean>(`muted-${member.user.id}`);
|
||||
const search = await this.client.db.local.muted.get<boolean>(`muted-${member.user.id}`);
|
||||
if (search === true) {
|
||||
member.addRole('478373942638149643');
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export default function checkLock(client: Client): NodeJS.Timeout {
|
|||
await client.util.moderation.unban(moderation.userID, system);
|
||||
break;
|
||||
case 2:
|
||||
if (await client.db.local.get<boolean>(`muted-${moderation.userID}`) === true) {
|
||||
if (await client.db.local.muted.get<boolean>(`muted-${moderation.userID}`) === true) {
|
||||
await client.util.moderation.unmute(moderation.userID, system);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue