Skip to content

Commit

Permalink
add requests
Browse files Browse the repository at this point in the history
  • Loading branch information
curtisf committed Dec 3, 2019
1 parent 958e58d commit 483009b
Show file tree
Hide file tree
Showing 14 changed files with 751 additions and 18 deletions.
11 changes: 8 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@

// This file is just for tesing, and must be adapted for module use later.
(async () => {
require('dotenv').config()
const Client = require('./src/classes/Client')

const client = await Client.build(process.env.AMQP_URI, process.env.AMQP_QUEUE || 'wildbeast')
const client = await Client.build(process.env.DISCORD_TOKEN, process.env.AMQP_URI, process.env.AMQP_QUEUE || 'wildbeast')
client.on('ready', () => {
console.log('Client is ready')
})
client.on('guildCreate', (guild) => {
console.log('guild create from init', guild.iconURL)
})
client.on('messageCreate', m => {
console.log('message create', m)
if (m.channel.id === '265283332269408257' && !m.author.bot && m.content === 'hello') {
client.createMessage(m.channel.id, {
content: `Hello, ${m.author.username}#${m.author.discriminator}. You were created on ${new Date(m.author.createdAt).toISOString()} and joined this server ${new Date(m.member.joinedAt).toISOString()}`
})
console.log(m.member)
}
})
})()
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "midgard",
"name": "@thesharks/midgard",
"version": "0.0.1",
"description": "Worker library for Heimdall",
"main": "index.js",
Expand All @@ -18,7 +18,9 @@
"homepage": "https://github.com/thesharks/midgard#readme",
"dependencies": {
"amqplib": "^0.5.5",
"dotenv": "^8.2.0"
"dotenv": "^8.2.0",
"https": "^1.0.0",
"zlib": "^1.0.5"
},
"devDependencies": {
"eslint": "^6.6.0",
Expand Down
31 changes: 28 additions & 3 deletions src/classes/Client.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
const amqp = require('amqplib')
const { EventEmitter } = require('events')
const MessageProcessor = require('./MessageProcessor')
const RequestHandler = require('./rest/RequestHandler')
const Endpoints = require('./rest/EndpointConstants')
const Message = require('./types/Message')

module.exports = class Client extends EventEmitter {
constructor (connection, channel, queue) {
constructor (token, connection, channel, queue) {
super(MessageProcessor)
this._token = token
this._conn = connection
this._chann = channel
this._queue = queue
this._messageProcessor = new MessageProcessor(this)
this._requestHandler = new RequestHandler(this)
this._chann.consume(this._queue, m => {
let msg
try {
Expand All @@ -24,13 +29,13 @@ module.exports = class Client extends EventEmitter {
process.on('exit', () => this._conn.close())
}

static async build (uri, queue) {
static async build (token, uri, queue) {
const connection = await amqp.connect(undefined)
const channel = await connection.createChannel()
channel.assertQueue(queue, {
durable: true
})
return new this(connection, channel, queue)
return new this(token, connection, channel, queue)
}

get isAlive () {
Expand All @@ -41,4 +46,24 @@ module.exports = class Client extends EventEmitter {
return true
}
}

createMessage (channelID, content, file) {
if (content !== undefined) {
if (typeof content !== 'object' || content === null) {
content = {
content: '' + content
}
} else if (content.content !== undefined && typeof content.content !== 'string') {
content.content = '' + content.content
} else if (content.content === undefined && !content.embed && !file) {
return Promise.reject(new Error('No content, file, or embed'))
}
if (content.content) {
content.content = content.content.replace(/@everyone/g, '@\u200beveryone').replace(/@here/g, '@\u200bhere')
}
} else if (!file) {
return Promise.reject(new Error('No content, file, or embed'))
}
return this._requestHandler.request('POST', Endpoints.CHANNEL_MESSAGES(channelID), true, content, file).then((message) => new Message(message, this))
}
}
3 changes: 1 addition & 2 deletions src/classes/MessageProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ module.exports = class MessageProcessor extends EventEmitter {
}

handle (msg) {
// console.log(msg.t)
switch (msg.t) {
case 'GUILD_CREATE': {
this._client.emit('guildCreate', new Guild(msg.d))
break
}
case 'MESSAGE_CREATE': {
this._client.emit('messageCreate', new Message(msg.d))
this._client.emit('messageCreate', new Message(msg.d, this._client))
break
}
}
Expand Down
55 changes: 55 additions & 0 deletions src/classes/errors/DiscordHTTPError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module.exports = class DiscordHTTPError extends Error {
constructor (req, res, response, stack) {
super()

Object.defineProperty(this, 'req', {
enumerable: false,
value: req
})
Object.defineProperty(this, 'res', {
enumerable: false,
value: res
})
Object.defineProperty(this, 'response', {
enumerable: false,
value: response
})

Object.defineProperty(this, 'code', {
enumerable: false,
value: res.statusCode
})
let message = `${res.statusCode} ${res.statusMessage} on ${req.method} ${req.path}`
const errors = this.flattenErrors(response)
if (errors.length > 0) {
message += '\n ' + errors.join('\n ')
}
Object.defineProperty(this, 'message', {
enumerable: false,
value: message
})

if (stack) {
this.stack = this.name + ': ' + this.message + '\n' + stack
} else {
Error.captureStackTrace(this, DiscordHTTPError)
}
}

get name () {
return this.constructor.name
}

flattenErrors (errors, keyPrefix = '') {
let messages = []
for (const fieldName in errors) {
if (!errors.hasOwnProperty(fieldName) || fieldName === 'message' || fieldName === 'code') {
continue
}
if (Array.isArray(errors[fieldName])) {
messages = messages.concat(errors[fieldName].map((str) => `${keyPrefix + fieldName}: ${str}`))
}
}
return messages
}
}
63 changes: 63 additions & 0 deletions src/classes/errors/DiscordRESTError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module.exports = class DiscordRESTError extends Error {
constructor (req, res, response, stack) {
super()

Object.defineProperty(this, 'req', {
enumerable: false,
value: req
})
Object.defineProperty(this, 'res', {
enumerable: false,
value: res
})
Object.defineProperty(this, 'response', {
enumerable: false,
value: response
})

Object.defineProperty(this, 'code', {
enumerable: false,
value: +response.code || -1
})
let message = response.message || 'Unknown error'
if (response.errors) {
message += '\n ' + this.flattenErrors(response.errors).join('\n ')
} else {
const errors = this.flattenErrors(response)
if (errors.length > 0) {
message += '\n ' + errors.join('\n ')
}
}
Object.defineProperty(this, 'message', {
enumerable: false,
value: message
})

if (stack) {
this.stack = this.name + ': ' + this.message + '\n' + stack
} else {
Error.captureStackTrace(this, DiscordRESTError)
}
}

get name () {
return `${this.constructor.name} [${this.code}]`
}

flattenErrors (errors, keyPrefix = '') {
let messages = []
for (const fieldName in errors) {
if (!errors.hasOwnProperty(fieldName) || fieldName === 'message' || fieldName === 'code') {
continue
}
if (errors[fieldName]._errors) {
messages = messages.concat(errors[fieldName]._errors.map((obj) => `${keyPrefix + fieldName}: ${obj.message}`))
} else if (Array.isArray(errors[fieldName])) {
messages = messages.concat(errors[fieldName].map((str) => `${keyPrefix + fieldName}: ${str}`))
} else if (typeof errors[fieldName] === 'object') {
messages = messages.concat(this.flattenErrors(errors[fieldName], keyPrefix + fieldName + '.'))
}
}
return messages
}
}
71 changes: 70 additions & 1 deletion src/classes/rest/EndpointConstants.js
Original file line number Diff line number Diff line change
@@ -1 +1,70 @@
exports.CDN_URL = 'https://cdn.discordapp.com'
module.exports.CDN_URL = 'https://cdn.discordapp.com'
module.exports.BASE_URL = '/api/v7'
module.exports.CHANNEL = (chanID) => `/channels/${chanID}`
module.exports.CHANNEL_BULK_DELETE = (chanID) => `/channels/${chanID}/messages/bulk-delete`
module.exports.CHANNEL_CALL_RING = (chanID) => `/channels/${chanID}/call/ring`
module.exports.CHANNEL_INVITES = (chanID) => `/channels/${chanID}/invites`
module.exports.CHANNEL_MESSAGE_REACTION = (chanID, msgID, reaction) => `/channels/${chanID}/messages/${msgID}/reactions/${reaction}`
module.exports.CHANNEL_MESSAGE_REACTION_USER = (chanID, msgID, reaction, userID) => `/channels/${chanID}/messages/${msgID}/reactions/${reaction}/${userID}`
module.exports.CHANNEL_MESSAGE_REACTIONS = (chanID, msgID) => `/channels/${chanID}/messages/${msgID}/reactions`
module.exports.CHANNEL_MESSAGE = (chanID, msgID) => `/channels/${chanID}/messages/${msgID}`
module.exports.CHANNEL_MESSAGES = (chanID) => `/channels/${chanID}/messages`
module.exports.CHANNEL_MESSAGES_SEARCH = (chanID) => `/channels/${chanID}/messages/search`
module.exports.CHANNEL_PERMISSION = (chanID, overID) => `/channels/${chanID}/permissions/${overID}`
module.exports.CHANNEL_PERMISSIONS = (chanID) => `/channels/${chanID}/permissions`
module.exports.CHANNEL_PIN = (chanID, msgID) => `/channels/${chanID}/pins/${msgID}`
module.exports.CHANNEL_PINS = (chanID) => `/channels/${chanID}/pins`
module.exports.CHANNEL_RECIPIENT = (groupID, userID) => `/channels/${groupID}/recipients/${userID}`
module.exports.CHANNEL_TYPING = (chanID) => `/channels/${chanID}/typing`
module.exports.CHANNEL_WEBHOOKS = (chanID) => `/channels/${chanID}/webhooks`
module.exports.CHANNELS = '/channels'
module.exports.GATEWAY = '/gateway'
module.exports.GATEWAY_BOT = '/gateway/bot'
module.exports.GUILD = (guildID) => `/guilds/${guildID}`
module.exports.GUILD_AUDIT_LOGS = (guildID) => `/guilds/${guildID}/audit-logs`
module.exports.GUILD_BAN = (guildID, memberID) => `/guilds/${guildID}/bans/${memberID}`
module.exports.GUILD_BANS = (guildID) => `/guilds/${guildID}/bans`
module.exports.GUILD_CHANNELS = (guildID) => `/guilds/${guildID}/channels`
module.exports.GUILD_EMBED = (guildID) => `/guilds/${guildID}/embed`
module.exports.GUILD_EMOJI = (guildID, emojiID) => `/guilds/${guildID}/emojis/${emojiID}`
module.exports.GUILD_EMOJIS = (guildID) => `/guilds/${guildID}/emojis`
module.exports.GUILD_INTEGRATION = (guildID, inteID) => `/guilds/${guildID}/integrations/${inteID}`
module.exports.GUILD_INTEGRATION_SYNC = (guildID, inteID) => `/guilds/${guildID}/integrations/${inteID}/sync`
module.exports.GUILD_INTEGRATIONS = (guildID) => `/guilds/${guildID}/integrations`
module.exports.GUILD_INVITES = (guildID) => `/guilds/${guildID}/invites`
module.exports.GUILD_VANITY_URL = (guildID) => `/guilds/${guildID}/vanity-url`
module.exports.GUILD_MEMBER = (guildID, memberID) => `/guilds/${guildID}/members/${memberID}`
module.exports.GUILD_MEMBER_NICK = (guildID, memberID) => `/guilds/${guildID}/members/${memberID}/nick`
module.exports.GUILD_MEMBER_ROLE = (guildID, memberID, roleID) => `/guilds/${guildID}/members/${memberID}/roles/${roleID}`
module.exports.GUILD_MEMBERS = (guildID) => `/guilds/${guildID}/members`
module.exports.GUILD_MESSAGES_SEARCH = (guildID) => `/guilds/${guildID}/messages/search`
module.exports.GUILD_PRUNE = (guildID) => `/guilds/${guildID}/prune`
module.exports.GUILD_ROLE = (guildID, roleID) => `/guilds/${guildID}/roles/${roleID}`
module.exports.GUILD_ROLES = (guildID) => `/guilds/${guildID}/roles`
module.exports.GUILD_VOICE_REGIONS = (guildID) => `/guilds/${guildID}/regions`
module.exports.GUILD_WEBHOOKS = (guildID) => `/guilds/${guildID}/webhooks`
module.exports.GUILDS = '/guilds'
module.exports.INVITE = (inviteID) => `/invite/${inviteID}`
module.exports.OAUTH2_APPLICATION = (appID) => `/oauth2/applications/${appID}`
module.exports.USER = (userID) => `/users/${userID}`
module.exports.USER_BILLING = (userID) => `/users/${userID}/billing`
module.exports.USER_BILLING_PAYMENTS = (userID) => `/users/${userID}/billing/payments`
module.exports.USER_BILLING_PREMIUM_SUBSCRIPTION = (userID) => `/users/${userID}/billing/premium-subscription`
module.exports.USER_CHANNELS = (userID) => `/users/${userID}/channels`
module.exports.USER_CONNECTIONS = (userID) => `/users/${userID}/connections`
module.exports.USER_CONNECTION_PLATFORM = (userID, platform, id) => `/users/${userID}/connections/${platform}/${id}`
module.exports.USER_GUILD = (userID, guildID) => `/users/${userID}/guilds/${guildID}`
module.exports.USER_GUILDS = (userID) => `/users/${userID}/guilds`
module.exports.USER_MFA_CODES = (userID) => `/users/${userID}/mfa/codes`
module.exports.USER_MFA_TOTP_DISABLE = (userID) => `/users/${userID}/mfa/totp/disable`
module.exports.USER_MFA_TOTP_ENABLE = (userID) => `/users/${userID}/mfa/totp/enable`
module.exports.USER_NOTE = (userID, targetID) => `/users/${userID}/note/${targetID}`
module.exports.USER_PROFILE = (userID) => `/users/${userID}/profile`
module.exports.USER_RELATIONSHIP = (userID, relID) => `/users/${userID}/relationships/${relID}`
module.exports.USER_SETTINGS = (userID) => `/users/${userID}/settings`
module.exports.USERS = '/users'
module.exports.VOICE_REGIONS = '/voice/regions'
module.exports.WEBHOOK = (hookID) => `/webhooks/${hookID}`
module.exports.WEBHOOK_SLACK = (hookID) => `/webhooks/${hookID}/slack`
module.exports.WEBHOOK_TOKEN = (hookID, token) => `/webhooks/${hookID}/${token}`
module.exports.WEBHOOK_TOKEN_SLACK = (hookID, token) => `/webhooks/${hookID}/${token}/slack`
Loading

0 comments on commit 483009b

Please sign in to comment.