Merge branch 'dev'
commit
9625e11238
|
@ -17,14 +17,14 @@ export default class Client extends eris.Client {
|
||||||
|
|
||||||
public serverManagement: ServerManagement;
|
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) {
|
constructor(token: string, options?: eris.ClientOptions) {
|
||||||
super(token, options);
|
super(token, options);
|
||||||
this.commands = new Collection<Command>();
|
this.commands = new Collection<Command>();
|
||||||
this.events = new Collection<Event>();
|
this.events = new Collection<Event>();
|
||||||
this.intervals = new Collection<NodeJS.Timeout>();
|
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() {
|
public async loadDatabase() {
|
||||||
|
|
|
@ -1,37 +1,65 @@
|
||||||
/* eslint-disable no-constant-condition */
|
/* eslint-disable no-constant-condition */
|
||||||
import { promises as fs, constants } from 'fs';
|
import { promises as fs, accessSync, constants, writeFileSync } from 'fs';
|
||||||
import { Client } from '.';
|
import { promisify } from 'util';
|
||||||
|
import { gzip, gzipSync, unzip } from 'zlib';
|
||||||
|
|
||||||
type JSONData = [{key: string, value: any}?];
|
type JSONData = [{key: string, value: any}?];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persistant local JSON-based storage.
|
* 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>
|
* @author Matthew <matthew@staff.libraryofcode.org>
|
||||||
*/
|
*/
|
||||||
export default class LocalStorage {
|
export default class LocalStorage {
|
||||||
private client: Client;
|
|
||||||
|
|
||||||
protected storagePath: string;
|
protected storagePath: string;
|
||||||
|
|
||||||
private locked: boolean = false;
|
private locked: boolean = false;
|
||||||
|
|
||||||
constructor(client: Client, storagePath = `${__dirname}/../../localstorage`) {
|
constructor(dbName: string) {
|
||||||
this.client = client;
|
this.storagePath = `${__dirname}/../../localstorage/${dbName}.json.gz`;
|
||||||
this.storagePath = storagePath;
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async init() {
|
private init() {
|
||||||
try {
|
try {
|
||||||
await fs.access(`${this.storagePath}/1.json`, constants.F_OK);
|
accessSync(this.storagePath, constants.F_OK);
|
||||||
} catch {
|
} catch {
|
||||||
const setup = [];
|
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.
|
* Retrieves one data from the store.
|
||||||
* If the store has multiple entries for the same key, this function will only return the first entry.
|
* 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;
|
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;
|
this.locked = false;
|
||||||
const json: JSONData = JSON.parse(file);
|
const json: JSONData = JSON.parse(uncomp);
|
||||||
const result = json.filter((data) => data.key === key);
|
const result = json.filter((data) => data.key === key);
|
||||||
if (!result[0]) return null;
|
if (!result[0]) return null;
|
||||||
return result[0].value;
|
return result[0].value;
|
||||||
|
@ -67,9 +96,10 @@ export default class LocalStorage {
|
||||||
}
|
}
|
||||||
this.locked = true;
|
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;
|
this.locked = false;
|
||||||
const json: JSONData = JSON.parse(file);
|
const json: JSONData = JSON.parse(uncomp);
|
||||||
const result = json.filter((data) => data.key === key);
|
const result = json.filter((data) => data.key === key);
|
||||||
if (result.length < 1) return null;
|
if (result.length < 1) return null;
|
||||||
return result;
|
return result;
|
||||||
|
@ -90,10 +120,12 @@ export default class LocalStorage {
|
||||||
}
|
}
|
||||||
this.locked = true;
|
this.locked = true;
|
||||||
|
|
||||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
const file = await fs.readFile(this.storagePath);
|
||||||
const json: JSONData = JSON.parse(file);
|
const uncomp = await LocalStorage.decompress(file);
|
||||||
|
const json: JSONData = JSON.parse(uncomp);
|
||||||
json.push({ key, value });
|
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;
|
this.locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,10 +143,12 @@ export default class LocalStorage {
|
||||||
}
|
}
|
||||||
this.locked = true;
|
this.locked = true;
|
||||||
|
|
||||||
const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' });
|
const file = await fs.readFile(this.storagePath);
|
||||||
const json: JSONData = JSON.parse(file);
|
const uncomp = await LocalStorage.decompress(file);
|
||||||
|
const json: JSONData = JSON.parse(uncomp);
|
||||||
const filtered = json.filter((data) => data.key !== key);
|
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;
|
this.locked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ export default class Moderation {
|
||||||
} else date = null;
|
} else date = null;
|
||||||
const expiration = { date, processed };
|
const expiration = { date, processed };
|
||||||
mod.expiration = expiration;
|
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();
|
const embed = new RichEmbed();
|
||||||
embed.setTitle(`Case ${logID} | Mute`);
|
embed.setTitle(`Case ${logID} | Mute`);
|
||||||
|
@ -171,7 +171,7 @@ export default class Moderation {
|
||||||
date: new Date(),
|
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();
|
const embed = new RichEmbed();
|
||||||
embed.setTitle(`Case ${logID} | Unmute`);
|
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.');
|
if (!member) return this.error(message.channel, 'Cannot find user.');
|
||||||
|
|
||||||
try {
|
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.');
|
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
|
} catch {} // eslint-disable-line no-empty
|
||||||
if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.');
|
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.');
|
if (!member) return this.error(message.channel, 'Cannot find user.');
|
||||||
|
|
||||||
try {
|
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.');
|
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
|
} catch {} // eslint-disable-line no-empty
|
||||||
if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.');
|
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) {
|
public async run(_, member: Member) {
|
||||||
try {
|
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) {
|
if (search === true) {
|
||||||
member.addRole('478373942638149643');
|
member.addRole('478373942638149643');
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export default function checkLock(client: Client): NodeJS.Timeout {
|
||||||
await client.util.moderation.unban(moderation.userID, system);
|
await client.util.moderation.unban(moderation.userID, system);
|
||||||
break;
|
break;
|
||||||
case 2:
|
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);
|
await client.util.moderation.unmute(moderation.userID, system);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue