The code establishes and manages a WebSocket connection to Discord, handling events such as connection opening, message receiving, and connection closing, with functions like authorizeGateway() and closeGateway(). It also includes functions like requestAuthQ() for making requests to the Discord API, although this function appears to be incomplete and intended to handle a queue of requests.
npm run import -- "discord request"const {request} = require('gaxios')
const WebSocket = require('ws')
const {delay, wait, timeout} = importer.import("discord utilities")
const {
gatewayIdentified, gatewayClose, gatewayMessage,
} = importer.import("discord gateway")
const {
TOKEN, DEFAULT_API, DEFAULT_RATE
} = importer.import("discord configuration")
var ws = false
var wsConnecting = false
var previousRequest = 0
async function gatewayUrl() {
// TODO: return the same result if queried less than 1 second ago
// doesn't use requestAuthQ because that would create an infinite loop
var result = await request({
headers: {
'Authorization': `Bot ${TOKEN}`
},
method: 'GET',
url: `${DEFAULT_API}gateway/bot`
})
return result.data
}
function gatewayOpen() {
console.log('Connecting to Discord')
}
async function authorizeGateway() {
if(wsConnecting) {
var result = await wait(() => ws && ws.identified, 3000)
if(!result)
return await authorizeGateway()
else
return ws
} else if (ws && ws.readyState == 1 && ws.identified) {
return ws
}
wsConnecting = true
try {
ws = new WebSocket((await gatewayUrl()).url)
ws.identified = false
} catch (e) {
console.log('Authorize error', e.message)
ws = false
wsConnecting = false
return
}
ws.on('open', gatewayOpen)
ws.on('message', gatewayMessage.bind(null, ws, authorizeGateway, interactionResponse))
ws.on('close', gatewayClose.bind(null, ws, authorizeGateway))
await wait(() => ws.identified, 3000)
wsConnecting = false
return ws
}
function closeGateway() {
gatewayClose(ws)
}
var previousRequest = 0
async function requestAuthQ(outgoing) {
await authorizeGateway()
if(typeof outgoing.headers == 'undefined')
outgoing.headers = {}
outgoing.headers['Authorization'] = `Bot ${TOKEN}`
outgoing.url = DEFAULT_API + outgoing.url
previousRequest = await delay(previousRequest, DEFAULT_RATE)
var resolveRequest
resolveRequest = async () => {
var result
try {
//console.log('Discord request', outgoing)
result = (await request(outgoing)).data
} catch (e) {
// check result for rate limit and re-run this request in a queue
if(e.code == 429) {
console.log('Delayed request', e.response.data.retry_after)
await timeout(e.response.data.retry_after * 1000)
return await resolveRequest()
} else {
console.log(e)
if(e.response) {
console.log(e.response.data.errors)
}
throw e
}
}
return result
}
return await resolveRequest()
}
async function interactionResponse(interactionId, interactionToken) {
var json = {
'type': 5
}
return await requestAuthQ({
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
url: `interactions/${interactionId}/${interactionToken}/callback`,
data: JSON.stringify(json)
})
}
module.exports = {
authorizeGateway,
gatewayUrl,
closeGateway,
requestAuthQ,
interactionResponse,
}
const { request } = require('gaxios');
const WebSocket = require('ws');
const { delay, wait, timeout } = require('discord utilities');
const {
gatewayIdentified, gatewayClose, gatewayMessage,
} = require('discord gateway');
const {
TOKEN, DEFAULT_API, DEFAULT_RATE
} = require('discord configuration');
class DiscordGateway {
constructor() {
this.ws = false;
this.wsConnecting = false;
this.previousRequest = 0;
}
async gatewayUrl() {
try {
const result = await request({
headers: {
Authorization: `Bot ${TOKEN}`,
},
method: 'GET',
url: `${DEFAULT_API}gateway/bot`,
});
return result.data;
} catch (error) {
console.error('Error getting gateway URL:', error);
throw error;
}
}
async authorizeGateway() {
const now = Date.now();
if (this.wsConnecting && now - this.previousRequest < 1000) {
// Return cached result from previous request if queried less than 1 second ago
return this.ws;
}
this.wsConnecting = true;
try {
const result = await this.gatewayUrl();
this.ws = new WebSocket(result.url);
this.ws.identified = false;
} catch (error) {
console.error('Authorize error:', error.message);
this.ws = false;
this.wsConnecting = false;
return;
}
this.ws.on('open', () => console.log('Connecting to Discord'));
this.ws.on('message', (event) => gatewayMessage(event, this.authorizeGateway));
this.ws.on('close', () => gatewayClose(this.ws, this.authorizeGateway));
await this.waitForGatewayIdentification(3000);
this.wsConnecting = false;
return this.ws;
}
async waitForGatewayIdentification(timeoutMs) {
if (this.ws && this.ws.readyState === 1 && this.ws.identified) {
return this.ws;
}
try {
await wait(() => this.ws.identified, timeoutMs);
} catch (error) {
console.error('Error waiting for gateway identification:', error);
throw error;
}
}
async closeGateway() {
gatewayClose(this.ws, this.authorizeGateway);
}
async requestAuthQ(outgoing) {
await this.authorizeGateway();
if (!outgoing.headers) {
outgoing.headers = {};
}
outgoing.headers.Authorization = `Bot ${TOKEN}`;
outgoing.url = DEFAULT_API + outgoing.url;
const waitTime = await delay(this.previousRequest, DEFAULT_RATE);
this.previousRequest = waitTime;
const resolveRequest = async () => {
try {
const result = await request(outgoing);
return result.data;
} catch (error) {
if (error.code === 429) {
console.log('Delayed request:', error.response.data.retry_after);
await timeout(error.response.data.retry_after * 1000);
return await resolveRequest();
} else {
console.error(error);
if (error.response) {
console.error(error.response.data.errors);
}
throw error;
}
}
};
return await resolveRequest();
}
async interactionResponse(interactionId, interactionToken) {
const json = { type: 5 };
return await this.requestAuthQ({
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
url: `interactions/${interactionId}/${interactionToken}/callback`,
data: JSON.stringify(json),
});
}
}
module.exports = new DiscordGateway();The code imports various modules and variables:
gaxios: a Google API client library for making HTTP requests.ws: a WebSocket library for establishing a real-time connection to Discord.discord utilities, discord gateway, and discord configuration: custom modules for handling Discord-related functionality.Variables are declared for the WebSocket connection (ws and wsConnecting) and for tracking the timing of requests (previousRequest).
gatewayUrl()This function retrieves the Discord gateway URL by making a GET request to the Discord API with the bot token as an authorization header. The result is returned as a promise.
gatewayOpen()This function logs a message to the console indicating that the connection to Discord is being established.
authorizeGateway()This function is responsible for establishing a WebSocket connection to Discord and authorizing the bot. It:
wsConnecting) or if a connection already exists (ws).gatewayUrl().open: logs a message to the console when the connection is established.message: receives messages from Discord and passes them to gatewayMessage() for handling.close: closes the connection and attempts to re-authorize when the connection is closed.closeGateway()This function closes the WebSocket connection to Discord.
requestAuthQ()This function makes a request to the Discord API with authentication. It:
authorizeGateway() to establish a new connection if necessary.Note that this function seems to be incomplete, as indicated by the TODO comment and the presence of a resolveRequest function. The code appears to be intended to handle a queue of requests, but this part is not fully implemented.