From c7a4ec9e4bf046974851633e0a2938e122e368ba Mon Sep 17 00:00:00 2001 From: Benjamin Kyd Date: Mon, 13 Jul 2020 23:53:42 +0100 Subject: [PATCH] Rewrite underway, new database system and database migrated from leveldb to sqlite --- .gitignore | 4 ++ README.md | 12 +++- index.js | 37 +----------- package.json | 7 ++- src/database.js | 132 +++++++++++++++++++++++++++++++++++++++++ src/discord.js | 40 +++++++++++++ src/discordcommands.js | 0 src/discordevents.js | 0 src/index.js | 25 ++++++++ src/logger.js | 112 ++++++++++++++++++++++++++++++++++ 10 files changed, 331 insertions(+), 38 deletions(-) create mode 100644 src/database.js create mode 100644 src/discord.js create mode 100644 src/discordcommands.js create mode 100644 src/discordevents.js create mode 100644 src/index.js create mode 100644 src/logger.js diff --git a/.gitignore b/.gitignore index fb29aef..fb9dd02 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ /uptime.json /.vscode/ package-lock.json +info.txt +logs.log +.env +storage/ diff --git a/README.md b/README.md index 0095bbb..6f790dd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,15 @@ Clone the repo, run `npm install`, run the `index.js` once, then fill the config.json, then rerun the bot. -However you can invite my hosted version of the bot [here](https://discordapp.com/api/oauth2/authorize?client_id=463829271933354006&permissions=128&scope=bot) and I recommend doing so. +Setting up the enviroment variables is easy +Firstly create a .env file with the following fields +``` + BOT_TOKEN + BOT_GAME + DB_LOCATION +``` + +However you can propriatery verion [here](https://discordapp.com/api/oauth2/authorize?client_id=463829271933354006&permissions=128&scope=bot) and I recommend doing so. ## How it works @@ -17,4 +25,4 @@ MIT, see LICENSE # Contributors - ahoZiorce - Founder, maintainer -- Ben (plane000)#8618 - Maintainer, contributor +- Ben Kyd (https://benkyd.co.uk) - Maintainer, contributor diff --git a/index.js b/index.js index f1bb987..6d432ca 100644 --- a/index.js +++ b/index.js @@ -1,35 +1,2 @@ -const levelup = require('levelup'); -const leveldown = require('leveldown'); -const zlib = require('zlib'); - -let db = levelup(leveldown('./logoriDB')); // Make that path customizable - -function get(key) { - return new Promise((resolve, reject) => { - db.get(key, (err, value) => { - if (err) { - reject(err); - return; - } - resolve(value); - }); - }); - } - - -function deflateObj(obj) { - let text = JSON.stringify(obj); - let compressed = zlib.deflateSync(text).toString('base64'); - return compressed; -} - -function inflateObj(str) { - let bufferCompressed = new Buffer(str, 'base64'); - let text = zlib.inflateSync(bufferCompressed).toString(); - return text; -} - -db.createReadStream() - .on('data', async (data) => { - console.log(Buffer(data.key, 'base64').toString(), " = ", await get(Buffer(data.key, 'base64').toString())); -}); +// pre settup +require('./src/index.js').main(); diff --git a/package.json b/package.json index f1acbb2..d33a4e5 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,15 @@ "author": "Alejandro W. Sior, Ben Kyd (https://benkyd.co.uk)", "license": "MIT", "dependencies": { + "colors": "^1.4.0", + "dotenv": "^8.2.0", "eris": "^0.13.3", "level": "^6.0.1", "leveldown": "^5.6.0", "levelup": "^4.4.0", - "zlib-sync": "^0.1.7" + "moment": "^2.27.0", + "sequelize": "^6.3.3", + "sqlite3": "^5.0.0", + "zlib-sync": "0.1.4" } } diff --git a/src/database.js b/src/database.js new file mode 100644 index 0000000..4aab938 --- /dev/null +++ b/src/database.js @@ -0,0 +1,132 @@ +const Logger = require('./logger.js'); + +const Sequelize = require('sequelize'); + +let Guild; + +module.exports.setup = async function() +{ + Logger.info('Setting up database'); + + if (process.env.NODE_ENV == "production") + { + Logger.database('Setting up production databse'); + } else { + Logger.database('Setting up development databse'); + } + + const database = new Sequelize({ + dialect: 'sqlite', + storage: process.env.NODE_ENV == "production" ? process.env.DB_LOCATION : process.env.DB_DEV_LOCATION, + logging: Logger.database + }); + + Guild = database.define('guild', { + id: { + type: Sequelize.STRING, + primaryKey: true, + unique: true + }, + name: Sequelize.STRING, + prefix: Sequelize.STRING, + logchannel: Sequelize.STRING, + logsettings: Sequelize.JSON, // JSON / Array + modcases: Sequelize.INTEGER + }, { + tableName: 'guild' + }); + + try + { + await database.authenticate(); + await database.sync(); + Logger.info('Database connection has been established successfully.'); + } catch (error) { + Logger.panic('Unable to connect to the database:', error); + } + +} + +module.exports.NewGuild = async function(id, name, prefix, logchannel, logsettings, modcases) +{ + try { + let user = await Guild.create({ + id: id, + name: name, + prefix: prefix, + logchannel: logchannel, + logsettings: logsettings, + modcases: modcases + }); + return user; + } catch (e) { + Logger.error(`An error occured while inserting guild ${id} : ${e}`); + return -1; + } +} + +module.exports.FetchGuild = async function(id) +{ + try { + let guild = await Guild.findOne({where: {id: id}}); + return guild == null ? -1 : guild; + } catch (e) { + Logger.error(`An error occured while fetching guild ${id} : ${e}`); + return -1; + } +} + +module.exports.UpdateGuildPrefix = async function(id, prefix) +{ + try { + await Guild.update({prefix: prefix}, {where: {id: id}}); + return 1; + } catch (e) { + Logger.error(`An error occured while updating guild id ${id} : ${e}`); + return -1; + } +} + +module.exports.UpdateGuildLogChannel = async function(id, channel) +{ + try { + await Guild.update({logchannel: channel}, {where: {id: id}}); + return 1; + } catch (e) { + Logger.error(`An error occured while updating guild id ${id} : ${e}`); + return -1; + } +} + +module.exports.UpdateGuildLogSettings = async function(id, settings) +{ + try { + await Guild.update({logsettings: settings}, {where: {id: id}}); + return 1; + } catch (e) { + Logger.error(`An error occured while updating guild id ${id} : ${e}`); + return -1; + } +} + +module.exports.IncrementGuildModCases = async function(id) +{ + try { + await Guild.update({modcases: Sequelize.literal('modcases + 1')}, {where: {id: id}}); + return 1; + } catch (e) { + Logger.error(`An error occured while updating guild id ${id} : ${e}`); + return -1; + } +} + +module.exports.DeleteGuild = async function(id) +{ + try { + await Guild.destroy({where: {id: id}}); + return 1; + } catch (e) { + Logger.error(`An error occured while deleting guild id ${id} : ${e}`); + return -1; + } +} diff --git a/src/discord.js b/src/discord.js new file mode 100644 index 0000000..77e5fc0 --- /dev/null +++ b/src/discord.js @@ -0,0 +1,40 @@ +const Logger = require('./logger.js'); +const Database = require('./database.js'); + +const fs = require('fs'); + +const Eris = require('eris'); + +let bot; + +module.exports.setup = async function() +{ + Logger.info('Setting up discord bot'); + + if (!process.env.BOT_TOKEN) Logger.panic('No BOT_TOKEN in .env file!') + + bot = new Eris(process.env.BOT_TOKEN, {allowedMentions: false, restMode: true}); + + bot.on('ready', async () => { + Logger.info(`Discord logged in as ${bot.user.username}#${bot.user.discriminator}`); + + let typestr = process.env.BOT_GAME_TYPE || 'playing'; + let game = process.env.BOT_GAME || '*'; + + let type; + switch (typestr) { + case 'playing': type = 0; break; + case 'listening': type = 2; break; + case 'watching': type = 3; break; + default: type = 3; break; + } + + bot.editStatus('online', {name: game, type: type}); + + }); + + // settup events + + bot.connect(); +} + diff --git a/src/discordcommands.js b/src/discordcommands.js new file mode 100644 index 0000000..e69de29 diff --git a/src/discordevents.js b/src/discordevents.js new file mode 100644 index 0000000..e69de29 diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..7de9584 --- /dev/null +++ b/src/index.js @@ -0,0 +1,25 @@ +const Logger = require('./logger.js'); +const Database = require('./database.js'); +const Discord = require('./discord.js'); + +require('dotenv').config() + +module.exports.main = async function() +{ + Logger.SetLevel(Logger.VERBOSE_LOGS); + Logger.welcome(); + + if (process.env.NODE_ENV == "production") + { + Logger.info('Starting in production mode'); + } else { + Logger.info('Starting in development mode'); + } + + await Database.setup(); + + await Discord.setup(); + + Logger.ready(); + +} diff --git a/src/logger.js b/src/logger.js new file mode 100644 index 0000000..9f92a99 --- /dev/null +++ b/src/logger.js @@ -0,0 +1,112 @@ +const colours = require('colors/safe'); +const moment = require('moment'); +const fs = require('fs'); + +let LogLevel = 1; +let Dialect = 'SQLITE'; +let logPath = 'logs.log'; +let dateFormat = 'DD-MM-YY HH:mm:ss' + +module.exports.init = function(path) { + if (path) logPath = path; + + if (!fs.existsSync(logPath)) { + fs.writeFileSync(logPath, ''); + } + fs.appendFileSync(logPath, '[SYSTEM STARTING UP] \n'); + + console.log(colours.rainbow('Starting up...')); +} + +module.exports.SetLevel = function(level) { + LogLevel = level; +} + +module.exports.SetDialect = function(dialect) { + Dialect = dialect; +} + +module.exports.SetDateFormat = function(format) { + dateFormat = format; +} + +module.exports.VERBOSE_LOGS = 0; +module.exports.DEBUG_LOGS = 1; +module.exports.INFO_LOGS = 2; +module.exports.WARN_LOGS = 3; + +module.exports.welcome = function() { + console.log(colours.rainbow(" \ + __ _ \n \ + / / ___ __ _ ___ _ __(_) \n \ + / / / _ \\ / _` |/ _ \\| '__| | \n \ + / /__| (_) | (_| | (_) | | | | \n \ + \\____/\\___/ \\__, |\\___/|_| |_| \n \ + |___/ ` \n \ + " + )) +} + +module.exports.database = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [${Dialect}] ${message} \n`); + if (LogLevel > 0) return; + console.log('[' + d.toLocaleString() + '] [' + + colours.magenta(Dialect) + '] ' + message); +} + +module.exports.middleware = function(origin, message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [MIDDLEWARE: ${origin}] ${message} \n`); + if (LogLevel > 0) return; + console.log('[' + d.toLocaleString() + '] [' + + colours.yellow(`MIDDLEWARE: ${origin}`) + '] ' + message); +} + +module.exports.debug = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [DEBUG] ${message} \n`); + if (LogLevel > 1) return; + console.log('[' + d.toLocaleString() + '] [' + + colours.cyan('DEBUG') + '] ' + message); +} + +module.exports.ready = function() { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [READY] \n`); + console.log('[' + d.toLocaleString() + '] [' + + colours.rainbow('READY') + ']'); +} + +module.exports.info = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [INFO] ${message} \n`); + if (LogLevel > 2) return; + console.log('[' + d.toLocaleString() + '] [' + + colours.green('INFO') + '] ' + message); +} + +module.exports.warn = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [WARN] ${message} \n`); + if (LogLevel > 3) return; + console.log('[' + d.toLocaleString() + '] [' + + colours.yellow('WARN') + '] ' + message); +} + +module.exports.error = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [ERROR] ${message} \n`); + console.log('[' + d.toLocaleString() + '] [' + + colours.red('ERROR') + '] ' + message); +} + +module.exports.panic = function(message) { + let d = moment().format(dateFormat); + fs.appendFileSync(logPath, `[${d.toLocaleString()}] [PANIC] ${message} \n`); + console.log('[' + d.toLocaleString() + '] [' + + colours.red('PANIC') + '] ' + message); + console.log('[' + d.toLocaleString() + '] [' + + colours.red('PANIC') + '] ABORTING...'); + process.exit(); +}