-
Notifications
You must be signed in to change notification settings - Fork 0
/
hyperate.js
159 lines (134 loc) · 5.07 KB
/
hyperate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import { SlashCommandBuilder } from 'discord.js';
import WebSocket from 'ws';
const apiToken = "pdcXMcD5noL8rqs1FNQP4ZHZ68T6c1P6E85vVAD7cgbYDqrIgumPHLilYR4LCGHH"; // Load your API token from an environment variable
class HypeRateWebsocket {
constructor({ apiKey, initialChannel }) {
this.apiKey = apiKey;
this.ws = null;
this.currentChannel = initialChannel || null;
this.generalListeners = [];
}
connect() {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(`wss://app.hyperate.io/socket/websocket?token=${this.apiKey}`, {
rejectUnauthorized: true, // Set to true in production
perMessageDeflate: false,
});
this.ws.onopen = () => {
console.log('WebSocket connection opened.');
this.joinChannel(this.currentChannel); // Join the specified channel
resolve();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = () => {
console.log('WebSocket connection closed.');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received message:', data);
this.handleMessage(data);
};
});
}
joinChannel(channelId) {
if (!channelId) return; // Exit if no channel ID is provided
const message = {
topic: `hr:${channelId}`,
event: 'phx_join',
payload: {},
ref: 0
};
this.sendMessage(message);
}
handleMessage(data) {
if (data.event === 'hr_update') {
const heartbeat = data.payload.hr;
const channel = data.topic;
// Notify all registered listeners
this.generalListeners.forEach((listener) => {
listener(channel, heartbeat);
});
}
}
startHeartbeatTimer() {
setInterval(() => {
const message = {
topic: 'phoenix',
event: 'heartbeat',
payload: {},
ref: 0
};
this.sendMessage(message);
}, 10000); // Send heartbeat every 10 seconds
}
sendMessage(message) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
}
}
addGeneralListener(callback) {
this.generalListeners.push(callback);
}
removeGeneralListener(callback) {
this.generalListeners = this.generalListeners.filter(listener => listener !== callback);
}
leaveChannel(channelId) {
const message = {
topic: `hr:${channelId}`,
event: 'phx_leave',
payload: {},
ref: 0
};
this.sendMessage(message);
}
}
// Initialize a single HypeRateWebsocket instance
const hyperateSocket = new HypeRateWebsocket({ apiKey: apiToken, initialChannel: 'internal-testing' });
// Connect the WebSocket once at bot startup
hyperateSocket.connect().then(() => {
console.log('HypeRate WebSocket connected.');
hyperateSocket.startHeartbeatTimer(); // Start sending keep-alive packets
}).catch(console.error);
// Discord command to fetch heart rate
const command = {
name: "hyperate",
description: "Fetches the current heart rate from a HypeRate user.",
data: new SlashCommandBuilder()
.setName('hyperate')
.setDescription('Fetch the current heart rate of a HypeRate user.')
.addStringOption(option =>
option.setName('user')
.setDescription('The HypeRate user ID')
.setRequired(true)),
async execute(interaction) {
const userId = interaction.options.getString('user'); // Get the user ID from command options
let hasReplied = false;
// Acknowledge the interaction
await interaction.reply({ content: `Fetching heart rate for HypeRate user: ${userId}...`, ephemeral: true });
hasReplied = true;
// Add a listener for heart rate updates
const listener = (channel, heartbeat) => {
if (hasReplied) {
interaction.followUp({
content: `HypeRate user **${userId}** currently has a heart rate of **${heartbeat} BPM**.`,
ephemeral: true
});
hyperateSocket.removeGeneralListener(listener); // Remove listener after responding
}
};
hyperateSocket.addGeneralListener(listener); // Register the listener
// Set a timeout to handle no response cases
setTimeout(async () => {
if (hasReplied) {
await interaction.followUp({
content: `No heart rate updates received for user **${userId}**. Please try again later.`,
ephemeral: true
});
}
}, 30000); // 30-second timeout
}
};
export default command;