33 * D++, A Lightweight C++ library for Discord
44 *
55 * SPDX-License-Identifier: Apache-2.0
6- * Copyright 2021 Craig Edwards and D++ contributors
6+ #include <dpp/zlibcontext.h> * Copyright 2021 Craig Edwards and D++ contributors
77 * (https://github.com/brainboxdotcc/DPP/graphs/contributors)
88 *
99 * Licensed under the Apache License, Version 2.0 (the "License");
2828#include < thread>
2929#include < dpp/json.h>
3030#include < dpp/etf.h>
31- #include < zlib.h>
3231
3332#define PATH_UNCOMPRESSED_JSON " /?v=" DISCORD_API_VERSION " &encoding=json"
3433#define PATH_COMPRESSED_JSON " /?v=" DISCORD_API_VERSION " &encoding=json&compress=zlib-stream"
@@ -48,45 +47,12 @@ namespace dpp {
4847 */
4948constexpr int LARGE_THRESHOLD = 250 ;
5049
51- /* *
52- * @brief This is an opaque class containing zlib library specific structures.
53- * We define it this way so that the public facing D++ library doesn't require
54- * the zlib headers be available to build against it.
55- */
56- class zlibcontext {
57- public:
58- /* *
59- * @brief Zlib stream struct
60- */
61- z_stream d_stream{};
62-
63- /* *
64- * @brief Initialise zlib struct via inflateInit()
65- */
66- zlibcontext () {
67- int error = inflateInit (&d_stream);
68- if (error != Z_OK) {
69- throw dpp::connection_exception ((exception_error_code)error, " Can't initialise stream compression!" );
70- }
71- }
72-
73- /* *
74- * @brief Destroy zlib struct via inflateEnd()
75- */
76- ~zlibcontext () {
77- inflateEnd (&d_stream);
78- }
79- };
80-
81-
8250/* *
8351 * @brief Resume constructor for websocket client
8452 */
8553discord_client::discord_client (discord_client &old, uint64_t sequence, const std::string& session_id)
8654 : websocket_client(old.owner, old.resume_gateway_url, " 443" , old.compressed ? (old.protocol == ws_json ? PATH_COMPRESSED_JSON : PATH_COMPRESSED_ETF) : (old.protocol == ws_json ? PATH_UNCOMPRESSED_JSON : PATH_UNCOMPRESSED_ETF)),
8755 compressed (old.compressed),
88- zlib(nullptr ),
89- decompressed_total(old.decompressed_total),
9056 connect_time(0 ),
9157 ping_start(0.0 ),
9258 etf(nullptr ),
@@ -113,8 +79,6 @@ discord_client::discord_client(discord_client &old, uint64_t sequence, const std
11379discord_client::discord_client (dpp::cluster* _cluster, uint32_t _shard_id, uint32_t _max_shards, const std::string &_token, uint32_t _intents, bool comp, websocket_protocol_t ws_proto)
11480 : websocket_client(_cluster, _cluster->default_gateway, " 443" , comp ? (ws_proto == ws_json ? PATH_COMPRESSED_JSON : PATH_COMPRESSED_ETF) : (ws_proto == ws_json ? PATH_UNCOMPRESSED_JSON : PATH_UNCOMPRESSED_ETF)),
11581 compressed(comp),
116- zlib(nullptr ),
117- decompressed_total(0 ),
11882 connect_time(0 ),
11983 ping_start(0.0 ),
12084 etf(nullptr ),
@@ -138,10 +102,9 @@ discord_client::discord_client(dpp::cluster* _cluster, uint32_t _shard_id, uint3
138102}
139103
140104void discord_client::start_connecting () {
141- etf = std::make_unique<etf_parser>(etf_parser () );
105+ etf = std::make_unique<etf_parser>();
142106 if (compressed) {
143107 zlib = std::make_unique<zlibcontext>();
144- decomp_buffer.resize (DECOMP_BUFFER_SIZE);
145108 }
146109 websocket_client::connect ();
147110}
@@ -150,10 +113,6 @@ void discord_client::cleanup()
150113{
151114}
152115
153- discord_client::~discord_client ()
154- {
155- }
156-
157116void discord_client::on_disconnect ()
158117{
159118 log (ll_trace, " discord_client::on_disconnect()" );
@@ -167,7 +126,7 @@ void discord_client::on_disconnect()
167126
168127uint64_t discord_client::get_decompressed_bytes_in ()
169128{
170- return decompressed_total;
129+ return zlib ? zlib-> decompressed_total : 0 ;
171130}
172131
173132void discord_client::set_resume_hostname ()
@@ -191,40 +150,12 @@ bool discord_client::handle_frame(const std::string &buffer, ws_opcode opcode)
191150 /* Check that we have a complete compressed frame */
192151 if ((uint8_t )buffer[buffer.size () - 4 ] == 0x00 && (uint8_t )buffer[buffer.size () - 3 ] == 0x00 && (uint8_t )buffer[buffer.size () - 2 ] == 0xFF
193152 && (uint8_t )buffer[buffer.size () - 1 ] == 0xFF ) {
194- /* Decompress buffer */
195- decompressed.clear ();
196- /* This is safe; zlib requires us to cast away the const. The underlying buffer is unchanged. */
197- zlib->d_stream .next_in = reinterpret_cast <Bytef*>(const_cast <char *>(buffer.data ()));
198- zlib->d_stream .avail_in = static_cast <uInt>(buffer.size ());
199- do {
200- zlib->d_stream .next_out = static_cast <Bytef*>(decomp_buffer.data ());
201- zlib->d_stream .avail_out = DECOMP_BUFFER_SIZE;
202- int ret = inflate (&(zlib->d_stream ), Z_NO_FLUSH);
203- size_t have = DECOMP_BUFFER_SIZE - zlib->d_stream .avail_out ;
204- switch (ret)
205- {
206- case Z_NEED_DICT:
207- case Z_STREAM_ERROR:
208- this ->error (err_compression_stream);
209- this ->close ();
210- return false ;
211- case Z_DATA_ERROR:
212- this ->error (err_compression_data);
213- this ->close ();
214- return false ;
215- case Z_MEM_ERROR:
216- this ->error (err_compression_memory);
217- this ->close ();
218- return false ;
219- case Z_OK:
220- this ->decompressed .append (decomp_buffer.begin (), decomp_buffer.begin () + have);
221- this ->decompressed_total += have;
222- break ;
223- default :
224- /* Stub */
225- break ;
226- }
227- } while (zlib->d_stream .avail_out == 0 );
153+ auto result = zlib->decompress (buffer, decompressed);
154+ if (result != err_no_code_specified) {
155+ this ->error (result);
156+ this ->close ();
157+ return false ;
158+ }
228159 data = decompressed;
229160 } else {
230161 /* No complete compressed frame yet */
0 commit comments