41 namespace discord_core_internal {
43 constexpr uint16_t webSocketMaxPayloadLengthLarge{ 65535u };
44 constexpr uint8_t webSocketPayloadLengthMagicLarge{ 126u };
45 constexpr uint8_t webSocketPayloadLengthMagicHuge{ 127u };
46 constexpr uint8_t maxHeaderSize{
sizeof(uint64_t) + 2u };
47 constexpr uint8_t webSocketMaxPayloadLengthSmall{ 125u };
48 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 };
75 DCA_INLINE
static unordered_map<websocket_close_code, jsonifier::string> outputErrorValues{ {
77 "we're not sure what went wrong.",
92 "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 "
97 DCA_INLINE websocket_close& operator=(uint16_t valueNew) {
102 DCA_INLINE websocket_close(uint16_t valueNew) {
106 DCA_INLINE
operator jsonifier::string_view() {
111 class DiscordCoreAPI_Dll event_converter {
113 event_converter(
const jsonifier::string& eventNew);
118 jsonifier::string_view eventValue{};
136 class websocket_core;
138 class DiscordCoreAPI_Dll websocket_tcpconnection :
public tcp_connection<websocket_tcpconnection> {
140 friend class websocket_core;
142 DCA_INLINE websocket_tcpconnection() =
default;
144 DCA_INLINE websocket_tcpconnection& operator=(websocket_tcpconnection&& other) =
default;
145 DCA_INLINE websocket_tcpconnection(websocket_tcpconnection&& other) =
default;
147 websocket_tcpconnection(
const jsonifier::string& baseUrlNew, uint16_t portNew, websocket_core* ptrNew);
149 void handleBuffer()
override;
152 websocket_core* ptr{};
155 enum class websocket_type { normal = 0, voice = 1 };
157 enum class websocket_state { connecting = 0, upgrading = 1, Collecting_Hello = 2, Sending_Identify = 3, authenticated = 4, disconnected = 5 };
159 class DiscordCoreAPI_Dll websocket_core {
161 friend class discord_core_api::voice_connection;
162 friend class websocket_tcpconnection;
164 DCA_INLINE websocket_core() =
default;
166 websocket_core& operator=(websocket_core&& data)
noexcept;
167 websocket_core(websocket_core&& data)
noexcept;
169 websocket_core(config_manager* configManagerNew, websocket_type typeOfWebSocketNew);
171 template<
typename value_type>
void createHeader(jsonifier::string_base<value_type>& outBuffer, websocket_op_code opCode) {
172 int64_t originalSize{
static_cast<int64_t
>(outBuffer.size()) };
173 outBuffer.insert(outBuffer.begin(),
static_cast<value_type
>(
static_cast<uint8_t
>(opCode) | webSocketMaskBit));
175 int64_t indexCount{};
176 if (originalSize <= webSocketMaxPayloadLengthSmall) {
177 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(originalSize));
179 }
else if (originalSize <= webSocketMaxPayloadLengthLarge) {
180 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(webSocketPayloadLengthMagicLarge));
183 outBuffer.insert(outBuffer.begin() + 1,
static_cast<value_type
>(webSocketPayloadLengthMagicHuge));
186 for (int64_t x = indexCount - 1; x >= 0; x--) {
187 outBuffer.insert(outBuffer.begin() + 1 + indexCount - x,
static_cast<value_type
>(originalSize >> (x * 8)));
190 outBuffer.at(1) |= webSocketMaskBit;
191 outBuffer.insert(outBuffer.begin() + 2 + indexCount, 0);
192 outBuffer.insert(outBuffer.begin() + 3 + indexCount, 0);
193 outBuffer.insert(outBuffer.begin() + 4 + indexCount, 0);
194 outBuffer.insert(outBuffer.begin() + 5 + indexCount, 0);
197 bool connect(
const jsonifier::string& baseUrlNew, jsonifier::string_view relativePath,
const uint16_t portNew);
199 virtual bool onMessageReceived(jsonifier::string_view_base<uint8_t> message) = 0;
201 bool sendMessage(jsonifier::string_base<uint8_t>& dataToSend,
bool priority);
203 bool checkForAndSendHeartBeat(
bool =
false);
205 void parseConnectionHeaders();
207 virtual void onClosed() = 0;
209 bool areWeConnected();
215 virtual ~websocket_core() =
default;
218 stop_watch<milliseconds> heartBeatStopWatch{ 20000ms };
219 jsonifier::string_base<uint8_t> currentMessage{};
220 std::atomic<websocket_state> currentState{};
221 bool haveWeReceivedHeartbeatAck{
true };
222 std::atomic_bool areWeCollectingData{};
223 websocket_tcpconnection tcpConnection{};
224 uint32_t maxReconnectTries{ 10 };
225 uint32_t currentReconnectTries{};
226 std::array<uint64_t, 2> shard{};
227 config_manager* configManager{};
228 uint32_t lastNumberReceived{};
229 websocket_op_code dataOpCode{};
230 std::mutex accessMutex{};
231 bool areWeHeartBeating{};
232 websocket_type wsType{};
233 bool areWeResuming{};
239 friend struct discord_core_api::on_voice_server_update_data;
240 friend struct discord_core_api::on_voice_state_update_data;
241 friend class tcp_connection<websocket_tcpconnection>;
242 friend class discord_core_api::discord_core_client;
243 friend class discord_core_api::voice_connection;
244 friend class discord_core_api::bot_user;
245 friend class base_socket_agent;
246 friend class sound_cloud_api;
247 friend class websocket_core;
248 friend class you_tube_api;
250 DCA_INLINE websocket_client() =
default;
252 DCA_INLINE websocket_client& operator=(websocket_client&&) =
default;
253 DCA_INLINE websocket_client(websocket_client&&) =
default;
255 websocket_client(uint64_t currentShardNew, std::atomic_bool* doWeQuitNew);
257 void getVoiceConnectionData(
const voice_connect_init_data& doWeCollect);
259 bool onMessageReceived(jsonifier::string_view_base<uint8_t> message)
override;
263 void onClosed()
override;
265 virtual ~websocket_client();
268 unordered_map<uint64_t, unbounded_message_block<voice_connection_data>*> voiceConnectionDataBufferMap{};
269 voice_connection_data voiceConnectionData{};
270 jsonifier::string resumeUrl{};
271 jsonifier::string sessionId{};
272 std::atomic_bool* doWeQuit{};
273 bool serverUpdateCollected{};
274 bool stateUpdateCollected{};
278 class base_socket_agent {
280 friend class discord_core_api::discord_core_client;
281 friend class discord_core_api::bot_user;
283 base_socket_agent(std::atomic_bool* doWeQuitNew);
285 void connect(websocket_client& value);
287 ~base_socket_agent();
290 unordered_map<uint64_t, websocket_client> shardMap{};
291 std::deque<connection_package> connections{};
292 std::atomic_bool* doWeQuit{};
293 std::jthread taskThread{};
295 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.
@ heartbeat
Fired periodically by the client to keep the connection alive.
@ hello
the session has been invalidated. you should reconnect and identify/resume accordingly.
@ resume
Resume a previous session that was disconnected.
@ Request_Guild_Members
Request information about offline guild members in a large guild.
@ Heartbeat_ACK
sent in response to receiving a heartbeat to acknowledge that it has been received.
@ dispatch
An event was dispatched.
@ reconnect
You should attempt to reconnect and resume immediately.
@ identify
Starts a new session during the initial handshake.
@ Voice_State_Update
Used to join/leave or move between voice channels.
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.
@ connect
Allows for joining of a voice channel.
The main namespace for the forward-facing interfaces.