Skip to content

Commit 7d22fb7

Browse files
author
Slingexe
authored
Bot now starts pulling messages if it has everything it needs
1 parent 52e9098 commit 7d22fb7

7 files changed

Lines changed: 107 additions & 292 deletions

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ Run the BOT using `node index.js`
2626

2727
In hackmud run the command `chat_pass` and copy the result
2828
In discord send `/settings auth password:"pass"`
29-
Once it says its successfully set the Token run `/settings setup` then `/client start`
29+
Once it says its successfully set the Token run `/settings setup`, this should create text channels with the users you have on your hackmud account
30+
Run `/settings manage-users user:username pull:True` to enable pulling messages from your users (This doesn't affect the ability of sending messages as said users only recieving them)
31+
Once you have done all that you are now able to run `/client start` (Once you have done all the steps above the bot should pull messages on startup)
3032
The guild the bot is in should now have all of your users set as channels and it should start pulling messages.
3133

3234
## Usage

backend/fetchNewMessages.js

Lines changed: 52 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const { readFile } = require('fs/promises');
2+
const path = require('node:path');
3+
14
// Full Hackmud-to-Discord color mapping //  = U+001B
25
const hackmudToDiscordColors = {
36
'reset': '\', // Reset text formatting
@@ -121,72 +124,71 @@ function fiveMinutesAgoToRubyTS() {
121124
}
122125

123126
async function loadChannelMappings() {
124-
const mapRaw = await readFile(path.resolve(__dirname, '../../channelMappings.json'), 'utf8');
127+
const mapRaw = await readFile(path.resolve(__dirname, '../channelMappings.json'), 'utf8');
125128
return JSON.parse(mapRaw);
126129
}
127130

128131
async function loadPullUsers() {
129-
const configRaw = await readFile(path.resolve(__dirname, '../../config.json'), 'utf8');
132+
const configRaw = await readFile(path.resolve(__dirname, '../config.json'), 'utf8');
130133
const config = JSON.parse(configRaw);
131134
return config.pullusers || [];
132135
}
133136

134137
async function loadMudToken() {
135-
const configRaw = await readFile(path.resolve(__dirname, '../../config.json'), 'utf8');
138+
const configRaw = await readFile(path.resolve(__dirname, '../config.json'), 'utf8');
136139
const config = JSON.parse(configRaw);
137140
return config.mudtoken || [];
138141
}
139142

140143
let lastTimestamp = fiveMinutesAgoToRubyTS();
141144

142-
module.exports = {
143-
async execute() {
144-
145-
const channelMappings = await loadChannelMappings();
146-
const pullusers = await loadPullUsers();
147-
const mudtoken = await loadMudToken();
148-
const apiUrl = 'https://www.hackmud.com/mobile/chats.json';
149-
const payload = {
150-
chat_token: mudtoken,
151-
usernames: pullusers,
152-
after: lastTimestamp,
153-
}
154-
try {
155-
const response = await fetch(apiUrl, {
156-
method: 'POST',
157-
headers: { 'Content-Type': 'application/json' },
158-
body: JSON.stringify(payload),
159-
});
160-
const result = await response.json();
161-
if (result.ok) {
162-
Object.entries(result.chats).forEach(([user, messages]) => {
163-
if (messages.length === 0) {
164-
//console.log(`No new messages for user: ${user}`);
165-
} else {
166-
messages.forEach(async (message) => {
167-
const discordChannelId = channelMappings[user]
168-
if (discordChannelId) {
169-
const formattedMessage = Formatter(message)
170-
// Fetch the Discord channel and send the message
171-
const channel = interaction.client.channels.cache.get(discordChannelId);
172-
if (channel) {
173-
const result = await channel.send(formattedMessage);
174-
if (result.code === 50013) {
175-
console.log(`No permission to send message in ${channel.name}, message not sent`);
176-
return
177-
}
145+
async function fetchNewMessages(client) {
146+
const channelMappings = await loadChannelMappings();
147+
const pullusers = await loadPullUsers();
148+
const mudtoken = await loadMudToken();
149+
const apiUrl = 'https://www.hackmud.com/mobile/chats.json';
150+
const payload = {
151+
chat_token: mudtoken,
152+
usernames: pullusers,
153+
after: lastTimestamp,
154+
}
155+
try {
156+
const response = await fetch(apiUrl, {
157+
method: 'POST',
158+
headers: { 'Content-Type': 'application/json' },
159+
body: JSON.stringify(payload),
160+
});
161+
const result = await response.json();
162+
if (result.ok) {
163+
Object.entries(result.chats).forEach(([user, messages]) => {
164+
if (messages.length === 0) {
165+
//console.log(`No new messages for user: ${user}`);
166+
} else {
167+
messages.forEach(async (message) => {
168+
const discordChannelId = channelMappings[user]
169+
if (discordChannelId) {
170+
const formattedMessage = Formatter(message)
171+
172+
const channel = client.channels.cache.get(discordChannelId);
173+
if (channel) {
174+
const result = await channel.send(formattedMessage);
175+
if (result.code === 50013) {
176+
console.log(`No permission to send message in ${channel.name}, message not sent`);
177+
return
178178
}
179179
}
180-
});
181-
}
182-
})
183-
// Update the last timestamp
184-
lastTimestamp = NowToRubyTS()+1;
185-
} else {
186-
console.error('Hackmud API error:', result.msg || 'Unknown error');
187-
}
188-
} catch (error) {
189-
console.error('Error fetching messages:', error);
180+
}
181+
});
182+
}
183+
})
184+
// Update the last timestamp
185+
lastTimestamp = NowToRubyTS()+1;
186+
} else {
187+
console.error('Hackmud API error:', result.msg || 'Unknown error');
190188
}
189+
} catch (error) {
190+
console.error('Error fetching messages:', error);
191191
}
192-
}
192+
};
193+
194+
module.exports.fetchNewMessages = fetchNewMessages;

commands/mud/client.js

Lines changed: 3 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,6 @@
11
const { SlashCommandBuilder, MessageFlags, ActivityType } = require('discord.js');
2-
const fetch = require('node-fetch');
3-
const fs = require('node:fs');
2+
const { fetchNewMessages } = require('./../../backend/fetchNewMessages.js')
43
const { setChatPullInterval, clearChatPullInterval, getChatPullInterval } = require('./../../backend/pullInterval');
5-
const path = require('path');
6-
const { readFile } = require('fs/promises');
7-
8-
// Full Hackmud-to-Discord color mapping //  = U+001B
9-
const hackmudToDiscordColors = {
10-
'reset': '\', // Reset text formatting
11-
'0': '', // Hackmud: #9B9B9B | Discord: Gray
12-
'1': '', // Hackmud: #FFFFFF | Discord: White
13-
'2': '', // Hackmud: #1EFF00 | Discord: Green
14-
'3': '', // Hackmud: #0070DD | Discord: Blue
15-
'4': '', // Hackmud: #B035EE | Discord: Pink
16-
'5': '', // Hackmud: #FF8000 | Discord: Yellow
17-
'6': '', // Hackmud: #FF8000 | Discord: Yellow
18-
'7': '', // Hackmud: #FF8000 | Discord: Yellow
19-
'8': '', // Hackmud: #FF8000 | Discord: Yellow
20-
'9': '', // Hackmud: #FF8000 | Discord: Yellow
21-
'a': '', // Hackmud: #000000 | Discord: Gray
22-
'b': '', // Hackmud: #3F3F3F | Discord: Gray
23-
'c': '', // Hackmud: #676767 | Discord: Gray
24-
'd': '', // Hackmud: #7D0000 | Discord: Red
25-
'e': '', // Hackmud: #8E3434 | Discord: Red
26-
'f': '', // Hackmud: #A34F00 | Discord: Yellow
27-
'g': '', // Hackmud: #725437 | Discord: Yellow
28-
'h': '', // Hackmud: #A88600 | Discord: Yellow
29-
'i': '', // Hackmud: #B2934A | Discord: Yellow
30-
'j': '', // Hackmud: #939500 | Discord: Green
31-
'k': '', // Hackmud: #495225 | Discord: Green
32-
'l': '', // Hackmud: #299400 | Discord: Green
33-
'm': '', // Hackmud: #23381B | Discord: Gray
34-
'n': '', // Hackmud: #00535B | Discord: Cyan
35-
'o': '', // Hackmud: #324A4C | Discord: Cyan
36-
'p': '', // Hackmud: #0073A6 | Discord: Blue
37-
'q': '', // Hackmud: #385A6C | Discord: Blue
38-
'r': '', // Hackmud: #010067 | Discord: Blue
39-
's': '', // Hackmud: #507AA1 | Discord: Blue
40-
't': '', // Hackmud: #601C81 | Discord: Pink
41-
'u': '', // Hackmud: #43314C | Discord: Gray
42-
'v': '', // Hackmud: #8C0069 | Discord: Pink
43-
'w': '', // Hackmud: #973984 | Discord: Pink
44-
'x': '', // Hackmud: #880024 | Discord: Red
45-
'y': '', // Hackmud: #762E4A | Discord: Red
46-
'z': '', // Hackmud: #101215 | Discord: Gray
47-
'A': '', // Hackmud: #FFFFFF | Discord: White
48-
'B': '', // Hackmud: #CACACA | Discord: White
49-
'C': '', // Hackmud: #9B9B9B | Discord: Gray
50-
'D': '', // Hackmud: #FF0000 | Discord: Red
51-
'E': '', // Hackmud: #FF8383 | Discord: Red
52-
'F': '', // Hackmud: #FF8000 | Discord: Yellow
53-
'G': '', // Hackmud: #F3AA6F | Discord: Yellow
54-
'H': '', // Hackmud: #FBC803 | Discord: Yellow
55-
'I': '', // Hackmud: #FFD863 | Discord: Yellow
56-
'J': '', // Hackmud: #FFF404 | Discord: Yellow
57-
'K': '', // Hackmud: #F3F998 | Discord: Green
58-
'L': '', // Hackmud: #1EFF00 | Discord: Green
59-
'M': '', // Hackmud: #B3FF9B | Discord: Green
60-
'N': '', // Hackmud: #00FFFF | Discord: Cyan
61-
'O': '', // Hackmud: #8FE6FF | Discord: Cyan
62-
'P': '', // Hackmud: #0070DD | Discord: Blue
63-
'Q': '', // Hackmud: #A4E3FF | Discord: Blue
64-
'R': '', // Hackmud: #0000FF | Discord: Blue
65-
'S': '', // Hackmud: #7AB2F4 | Discord: Blue
66-
'T': '', // Hackmud: #B035EE | Discord: Pink
67-
'U': '', // Hackmud: #E6C4FF | Discord: Pink
68-
'V': '', // Hackmud: #FF00EC | Discord: Pink
69-
'W': '', // Hackmud: #FF96E0 | Discord: Pink
70-
'X': '', // Hackmud: #FF0070 | Discord: Red
71-
'Y': '', // Hackmud: #FF6A98 | Discord: Red
72-
'Z': '', // Hackmud: #0C112B | Discord: Gray
73-
};
74-
75-
function Formatter(message) {
76-
function convertHackmudColors(text) {
77-
// Regex to detect backtick-wrapped strings with a leading color code
78-
const regex = /`([a-zA-Z0-9])([^`]*)`/g;
79-
return text.replace(regex, (match, code, content) => {
80-
// Map the color code to the corresponding Discord color if it exists
81-
const discordColor = hackmudToDiscordColors[code];
82-
if (discordColor) {
83-
return `${discordColor}${content}${hackmudToDiscordColors.reset}`;
84-
}
85-
// If no color is found, return the original match
86-
return match;
87-
});
88-
}
89-
90-
// Extract timestamp and format it
91-
const timestamp = new Date(message.t * 1000);
92-
const hours = timestamp.getHours().toString().padStart(2, '0');
93-
const minutes = timestamp.getMinutes().toString().padStart(2, '0');
94-
const formattedTime = `${hours}${minutes}`;
95-
96-
// Format user, channel, and other elements
97-
const formattedUser = `${message.from_user}`;
98-
const formattedChnlBlue = `${message.channel}`;
99-
const formattedChnlPink = `${message.channel}`;
100-
const formattedTell = `tell`;
101-
const messageBord = `:::`;
102-
103-
let formattedMessage = "";
104-
105-
// Apply color conversion to the message text
106-
const convertedMessage = convertHackmudColors(message.msg);
107-
108-
if (message.is_join) {
109-
formattedMessage = `\`\`\`ansi\n${formattedTime} ${formattedChnlBlue} ${formattedUser} ${messageBord} ${convertedMessage} ${messageBord}\n\`\`\``;
110-
} else {
111-
if (!message.channel) {
112-
formattedMessage = `\`\`\`ansi\n${formattedTime} ${formattedTell} ${formattedUser} ${messageBord} ${convertedMessage} ${messageBord}\n\`\`\``;
113-
} else {
114-
formattedMessage = `\`\`\`ansi\n${formattedTime} ${formattedChnlPink} ${formattedUser} ${messageBord} ${convertedMessage} ${messageBord}\n\`\`\``;
115-
}
116-
}
117-
118-
return formattedMessage;
119-
}
120-
121-
function NowToRubyTS() {
122-
return Math.floor(Date.now() / 1000);
123-
}
124-
125-
function fiveMinutesAgoToRubyTS() {
126-
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
127-
return Math.floor(fiveMinutesAgo / 1000);
128-
}
129-
130-
async function loadChannelMappings() {
131-
const mapRaw = await readFile(path.resolve(__dirname, '../../channelMappings.json'), 'utf8');
132-
return JSON.parse(mapRaw);
133-
}
134-
135-
async function loadPullUsers() {
136-
const configRaw = await readFile(path.resolve(__dirname, '../../config.json'), 'utf8');
137-
const config = JSON.parse(configRaw);
138-
return config.pullusers || [];
139-
}
140-
141-
async function loadMudToken() {
142-
const configRaw = await readFile(path.resolve(__dirname, '../../config.json'), 'utf8');
143-
const config = JSON.parse(configRaw);
144-
return config.mudtoken || [];
145-
}
1464

1475
module.exports = {
1486
category: 'mud',
@@ -168,70 +26,11 @@ module.exports = {
16826
}
16927

17028
await interaction.client.user.setStatus('online');
171-
await interaction.client.user.setActivity(' for new messages...', { type: ActivityType.Custom, name: "custom", state: "Listening for new messages..." });
29+
await interaction.client.user.setActivity({ type: ActivityType.Custom, name: "custom", state: "Listening for new messages..." });
17230

17331
await interaction.reply({content: 'Bot initialized. Listening for new messages...', flags: MessageFlags.Ephemeral });
17432

175-
let lastTimestamp = fiveMinutesAgoToRubyTS();
176-
177-
async function fetchNewMessages() {
178-
const channelMappings = await loadChannelMappings();
179-
const pullusers = await loadPullUsers();
180-
const mudtoken = await loadMudToken();
181-
182-
const apiUrl = 'https://www.hackmud.com/mobile/chats.json';
183-
const payload = {
184-
chat_token: mudtoken,
185-
usernames: pullusers,
186-
after: lastTimestamp,
187-
};
188-
189-
try {
190-
const response = await fetch(apiUrl, {
191-
method: 'POST',
192-
headers: { 'Content-Type': 'application/json' },
193-
body: JSON.stringify(payload),
194-
});
195-
196-
const result = await response.json();
197-
198-
if (result.ok) {
199-
Object.entries(result.chats).forEach(([user, messages]) => {
200-
if (messages.length === 0) {
201-
//console.log(`No new messages for user: ${user}`);
202-
} else {
203-
messages.forEach(async (message) => {
204-
const discordChannelId = channelMappings[user];
205-
206-
if (discordChannelId) {
207-
const formattedMessage = Formatter(message);
208-
209-
// Fetch the Discord channel and send the message
210-
const channel = interaction.client.channels.cache.get(discordChannelId);
211-
212-
if (channel) {
213-
const result = await channel.send(formattedMessage);
214-
if (result.code === 50013) {
215-
console.log(`No permission to send message in ${channel.name}, message not sent`);
216-
return
217-
}
218-
}
219-
}
220-
});
221-
}
222-
});
223-
224-
// Update the last timestamp
225-
lastTimestamp = NowToRubyTS();
226-
} else {
227-
console.error('Hackmud API error:', result.msg || 'Unknown error');
228-
}
229-
} catch (error) {
230-
console.error('Error fetching messages:', error);
231-
}
232-
}
233-
234-
const interval = setInterval(fetchNewMessages, 5000);
33+
const interval = setInterval(() => fetchNewMessages(interaction.client), 5000);
23534
setChatPullInterval(interval);
23635
}
23736
if (option === 'stop') {

commands/mud/settings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ module.exports = {
140140
let chatCategory = guild.channels.cache.find(
141141
(channel) => channel.type === 4 && channel.name.toLowerCase() === 'chat'
142142
);
143-
143+
144144
if (!chatCategory) {
145145
chatCategory = await guild.channels.create({
146146
name: 'chat',

0 commit comments

Comments
 (0)