diff --git a/README.md b/README.md index 43cfff4..9014935 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ The arguments are optional because the token and youtube-api-key that the bot ne ], "music": { "timeout": 300000 + }, + "webservice": { // optional + "enabled": true, // enable the server + "port": 8080, // set the port + "graphiql": false // switch the graphiql interface on/off } } ``` diff --git a/bot.js b/bot.js index f13a31c..6585572 100644 --- a/bot.js +++ b/bot.js @@ -4,6 +4,7 @@ const Discord = require("discord.js"), cmd = require("./lib/cmd"), guilding = require('./lib/guilding'), utils = require('./lib/utils'), + webapi = require('./lib/webapi'), config = require('./config.json'), args = require('args-parser')(process.argv), sqlite3 = require('sqlite3'), @@ -43,6 +44,7 @@ class Bot { } } guilding.setLogger(logger); + webapi.setLogger(logger); cmd.init(prefix); logger.verbose('Registering commands'); this.registerCommands(); @@ -68,6 +70,15 @@ class Bot { }); }); this.registerCallbacks(); + + if (config.webservice && config.webservice.enabled) { + logger.verbose('Creating WebServer'); + this.webServer = new webapi.WebServer(config.webservice.port || 8080); + logger.debug('Setting Reference Objects to webserver'); + this.webServer.setReferenceObjects({ + client: this.client + }); + } } start() { @@ -78,6 +89,10 @@ class Bot { }).catch((err) => { reject(err); }); + if (this.webServer){ + this.webServer.start(); + logger.info(`WebServer runing on port ${this.webServer.port}`); + } }) } diff --git a/graphql/schema.graphql b/graphql/schema.graphql new file mode 100644 index 0000000..404e47d --- /dev/null +++ b/graphql/schema.graphql @@ -0,0 +1,39 @@ +type User { + id: String + name: String + avatar: String + bot: Boolean + tag: String +} +type Role { + id: String + name: String + color: String + members: [GuildMember] +} +type GuildMember { + id: String + user: User + nickname: String + roles: [Role] + highestRole: Role +} +type Guild { + id: String + name: String + owner: GuildMember + members: [GuildMember] + roles: [Role] + memberCount: Int + icon: String +} +type Client { + guilds(count: Int): [Guild] + user: User + ping: Float + status: Int + uptime: Int +} +type Query { + client: Client +} \ No newline at end of file diff --git a/lib/webapi.js b/lib/webapi.js new file mode 100644 index 0000000..32f578a --- /dev/null +++ b/lib/webapi.js @@ -0,0 +1,98 @@ +const express = require('express'), + graphqlHTTP = require('express-graphql'), + {buildSchema} = require('graphql'), + config = require('../config.json'), + fs = require('fs'); + +let logger = require('winston'); + +exports.setLogger = function (newLogger) { + logger = newLogger; +}; + +exports.WebServer = class { + constructor(port, schema, root) { + this.app = express(); + this.port = port; + this.schema = buildSchema(fs.readFileSync('./graphql/schema.graphql', 'utf-8')); + this.root = {}; + } + + start() { + this.app.use('/graphql', graphqlHTTP({ + schema: this.schema, + rootValue: this.root, + graphiql: config.webservice.graphiql || false + })); + this.app.listen(this.port); + } + + setReferenceObjects(objects) { + this.root = { + client: { + guilds: ({count}) => { + let dcGuilds = objects.client.guilds.values(); + return Array.from(dcGuilds).map((x) => new Guild(x)).slice(0, count); + }, + user: () => { + return new User(objects.client.user); + }, + ping: () => { + return objects.client.ping; + }, + status: () => { + return objects.client.status; + }, + uptime: () => { + return objects.client.uptime; + } + } + } + } +}; + +class Guild { + constructor(discordGuild) { + this.id = discordGuild.id; + this.name = discordGuild.name; + this.owner = new GuildMember(discordGuild.owner); + this.memberCount = discordGuild.memberCount; + this.icon = discordGuild.iconURL; + this.members = Array.from(discordGuild.members.values()) + .map((x) => new GuildMember(x)); + this.roles = Array.from(discordGuild.roles.values()) + .map((x) => new Role(x)); + } +} + +class Role { + constructor(discordRole) { + this.id = discordRole.id; + this.name = discordRole.name; + this.color = discordRole.hexColor; + this.members = Array.from(discordRole.members.values) + .map((x) => new GuildMember(x)); + } +} + +class GuildMember { + constructor(discordGuildMember) { + this.id = discordGuildMember.id; + this.user = new User(discordGuildMember.user); + this.nickname = discordGuildMember.nickname; + this.roles = Array.from(discordGuildMember.roles.values()) + .map((x) => new Role(x)); + this.highestRole = new Role(discordGuildMember.highestRole); + } +} + +class User { + constructor(discordUser) { + this.id = discordUser.id; + this.name = discordUser.username; + this.avatar = discordUser.avatarURL; + this.bot = discordUser.bot; + this.tag = discordUser.tag; + this.tag = discordUser.tag; + } +} \ No newline at end of file diff --git a/package.json b/package.json index a416cfb..0ae3f96 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,12 @@ "dependencies": { "args-parser": "1.1.0", "discord.js": "11.4.2", + "eslint-plugin-graphql": "^3.0.1", + "express": "^4.16.4", + "express-graphql": "^0.7.1", "ffmpeg-binaries": "4.0.0", "get-youtube-title": "1.0.0", + "graphql": "^14.1.1", "opusscript": "0.0.6", "sqlite3": "4.0.6", "winston": "3.2.1", @@ -25,5 +29,10 @@ "nyc": "^13.1.0", "rewire": "^4.0.1", "sinon": "^7.2.3" + }, + "eslintConfig": { + "parserOptions": { + "sourceType": "script" + } } }