41 namespace discord_core_internal {
43 inline constexpr uint16_t webSocketMaxPayloadLengthLarge{ 65535u };
44 inline constexpr uint8_t webSocketPayloadLengthMagicLarge{ 126u };
45 inline constexpr uint8_t webSocketPayloadLengthMagicHuge{ 127u };
46 inline constexpr uint8_t maxHeaderSize{
sizeof(uint64_t) + 2u };
47 inline constexpr uint8_t webSocketMaxPayloadLengthSmall{ 125u };
48 inline constexpr uint8_t webSocketMaskBit{ (1u << 7u) };
50 enum class websocket_op_code : uint8_t { Op_Continuation = 0x00, Op_Text = 0x01, Op_Binary = 0x02, Op_Close = 0x08, Op_Ping = 0x09, Op_Pong = 0x0a };
86 inline static unordered_map<websocket_close_code, jsonifier::string_view> outputErrorValues{ {
88 "we're not sure what went wrong.",
103 "you sent a disallowed intent for a gateway intent. you may have tried to specify an intent that you have not enabled or are not "
108 inline websocket_close& operator=(uint16_t valueNew) {
113 inline websocket_close(uint16_t valueNew) {
117 inline operator jsonifier::string_view() {
118 return websocket_close::outputErrorValues[mappingValues[
static_cast<uint16_t
>(value)]];
121 inline operator bool() {
122 return static_cast<std::underlying_type_t<decltype(value)
>>(value) &
static_cast<std::underlying_type_t<decltype(value)
>>(websocket_close_code::We_Do_Reconnect);
126 class DiscordCoreAPI_Dll event_converter {
128 event_converter(jsonifier::string eventNew);
133 jsonifier::string eventValue{};
151 class websocket_core;
153 class DiscordCoreAPI_Dll websocket_tcpconnection :
public tcp_connection<websocket_tcpconnection> {
155 friend class websocket_core;
157 inline websocket_tcpconnection() =
default;
159 inline websocket_tcpconnection& operator=(websocket_tcpconnection&& other) =
default;
160 inline websocket_tcpconnection(websocket_tcpconnection&& other) =
default;
162 websocket_tcpconnection(
const jsonifier::string& baseUrlNew, uint16_t portNew, websocket_core* ptrNew);
164 void handleBuffer()
override;
167 websocket_core* ptr{};
170 enum class websocket_type { normal = 0, voice = 1 };
174 class DiscordCoreAPI_Dll websocket_core :
public etf_parser {
177 friend class websocket_tcpconnection;
179 inline websocket_core() =
default;
181 websocket_core& operator=(websocket_core&& data)
noexcept;
182 websocket_core(websocket_core&& data)
noexcept;
184 websocket_core(config_manager* configManagerNew, websocket_type typeOfWebSocketNew);
186 template<
typename value_type>
void createHeader(jsonifier::string_base<value_type>& outBuffer, websocket_op_code opCode) {
187 int64_t originalSize{
static_cast<int64_t
>(outBuffer.size()) };
188 outBuffer.insert(outBuffer.begin(),
static_cast<value_type
>(
static_cast<uint8_t
>(opCode) | webSocketMaskBit));
190 int64_t indexCount{};
191 if (originalSize <= webSocketMaxPayloadLengthSmall) {
192 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(originalSize));
194 }
else if (originalSize <= webSocketMaxPayloadLengthLarge) {
195 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(webSocketPayloadLengthMagicLarge));
198 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(webSocketPayloadLengthMagicHuge));
201 for (int64_t x = indexCount - 1; x >= 0; x--) {
202 outBuffer.insert(outBuffer.begin() + 1 + indexCount - x,
static_cast<value_type
>(originalSize >> (x * 8)));
205 outBuffer.at(1) |= webSocketMaskBit;
206 outBuffer.insert(outBuffer.begin() + 2 + indexCount, 0);
207 outBuffer.insert(outBuffer.begin() + 3 + indexCount, 0);
208 outBuffer.insert(outBuffer.begin() + 4 + indexCount, 0);
209 outBuffer.insert(outBuffer.begin() + 5 + indexCount, 0);
212 bool connect(
const jsonifier::string& baseUrlNew, jsonifier::string_view relativePath,
const uint16_t portNew);
214 virtual bool onMessageReceived(jsonifier::string_view_base<uint8_t> message) = 0;
216 bool sendMessage(jsonifier::string_base<uint8_t>& dataToSend,
bool priority);
218 bool checkForAndSendHeartBeat(
bool =
false);
220 void parseConnectionHeaders();
222 virtual void onClosed() = 0;
224 bool areWeConnected();
230 virtual ~websocket_core() =
default;
233 stop_watch<milliseconds> heartBeatStopWatch{ 20000ms };
234 jsonifier::string_base<uint8_t> currentMessage{};
235 std::atomic<websocket_state> currentState{};
236 bool haveWeReceivedHeartbeatAck{
true };
237 std::atomic_bool areWeCollectingData{};
238 websocket_tcpconnection tcpConnection{};
239 uint32_t maxReconnectTries{ 10 };
240 uint32_t currentReconnectTries{};
241 std::array<uint64_t, 2> shard{};
242 config_manager* configManager{};
243 uint32_t lastNumberReceived{};
244 websocket_op_code dataOpCode{};
245 std::mutex accessMutex{};
246 bool areWeHeartBeating{};
247 websocket_type wsType{};
248 bool areWeResuming{};
256 friend class tcp_connection<websocket_tcpconnection>;
260 friend class base_socket_agent;
261 friend class sound_cloud_api;
262 friend class websocket_core;
263 friend class you_tube_api;
274 bool onMessageReceived(jsonifier::string_view_base<uint8_t> message)
override;
278 void onClosed()
override;
283 unordered_map<uint64_t, unbounded_message_block<voice_connection_data>*> voiceConnectionDataBufferMap{};
284 voice_connection_data voiceConnectionData{};
285 jsonifier::string resumeUrl{};
286 jsonifier::string sessionId{};
287 std::atomic_bool* doWeQuit{};
288 bool serverUpdateCollected{};
289 bool stateUpdateCollected{};
293 class base_socket_agent {
298 base_socket_agent(std::atomic_bool* doWeQuitNew);
302 ~base_socket_agent();
305 unordered_map<uint64_t, websocket_client> shardMap{};
306 std::deque<connection_package> connections{};
307 std::atomic_bool* doWeQuit{};
308 std::jthread taskThread{};
310 void run(std::stop_token);
websocket_op_codes
For the opcodes that could be sent/received via discord's websockets.
@ Presence_Update
Update the client's presence.
@ Request_Guild_Members
Request information about offline guild members in a large guild.
@ dispatch
An event was dispatched.
@ reconnect
You should attempt to reconnect and resume immediately.
@ Voice_State_Update
Used to join/leave or move between voice channels.
A type of user_data, to represent the bot and some of its associated endpoints.
discord_core_client - the main class for this library.
A websocket client, for communication via a tcp-connection.
websocket_close_code
Websocket close codes.
@ Sharding_Required
The session would have handled too many guilds - you are required to shard your connection in order t...
@ Invalid_API_Version
You sent an invalid version for the gateway.
@ Invalid_Intent
You sent an invalid intent for a gateway intent. you may have incorrectly calculated the bitwise valu...
@ Decode_Error
You sent an invalid payload to us. don't do that!
@ Already_Authenticated
You sent more than one identify payload. don't do that!
@ Invalid_Shard
You sent us an invalid shard when identifying.
@ Invalid_Seq
the sequence sent when resuming the session was invalid. reconnect and start a new session.
@ Authentication_Failed
The account token sent with your identify payload is incorrect.
@ Unknown_Opcode
You sent an invalid gateway opcode or an invalid payload for an opcode. don't do that!
@ Disallowed_Intent
You sent a disallowed intent for a gateway intent. you may have tried to specify an intent that you h...
@ Unknown_Error
We're not sure what went wrong. try reconnecting?
@ Rate_Limited
Woah nelly! you're sending payloads to us too quickly. slow it down! you will be disconnected on rece...
@ Session_Timed
Your session timed out. reconnect and start a new one.
@ Not_Authenticated
You sent us a payload prior to identifying.
@ Normal_Close
Normal close.
A class representing a snowflake identifier with various operations.
voice_connection class - represents the connection to a given voice channel_data.
@ connect
Allows for joining of a voice channel.
The main namespace for the forward-facing interfaces.
@ hello
Time to wait between sending heartbeats in milliseconds.
@ resume
Resume a connection.
@ Heartbeat_ACK
Sent to acknowledge a received client heartbeat.
@ identify
Begin a voice websocket connection.
@ Sending_Identify
Sending the identify payload.
@ Collecting_Hello
collecting the client hello.
Data that is received as part of a voice server update event.
Data that is received as part of a voice state update event.
For connecting to a voice-channel. "streamInfo" is used when a SOCKET is created to connect this bot ...