<commit_before>#if _MSC_VER && !__INTEL_COMPILER
#pragma warning( disable: 4307 )
#endif

#include <chrono>
#include <functional>
#include "client.h"
#include "json.h"
#ifdef SLEEPY_USE_HARD_CODED_GATEWAY
	#include <cstring>
#endif

namespace SleepyDiscord {
	void BaseDiscordClient::start(const std::string _token, const char maxNumOfThreads) {
		ready = false;
		bot = true;
		token = std::unique_ptr<std::string>(new std::string(_token)); //add client to list
		
		messagesRemaining = 4;
		getTheGateway();
 		connect(theGateway);
#ifndef SLEEPY_ONE_THREAD
		if (2 < maxNumOfThreads) runAsync();
		if (1 < maxNumOfThreads) clock_thread = std::thread(&BaseDiscordClient::runClock_thread, this);
#endif
	}

	BaseDiscordClient::~BaseDiscordClient() {
		ready = false;
#ifndef SLEEPY_ONE_THREAD
		if (clock_thread.joinable()) clock_thread.join();
#endif
	}

	Response BaseDiscordClient::request(const RequestMethod method, const std::string _url, const std::string jsonParameters/*,
		cpr::Parameters httpParameters*/, const std::initializer_list<Part>& multipartParameters) {
		//check if rate limited
		static bool isRateLimited = false;
		static int64_t nextRetry = 0;
		Response response;
		if (isRateLimited) {
			if (nextRetry <= getEpochTimeMillisecond())
				isRateLimited = false;
			else {
				//Response response;
				response.statusCode = TOO_MANY_REQUESTS;
				setError(response.statusCode);
				return response;
			}
		} else if (_url == "gateway") {  //getting the gateway should happen in getTheGateway
			return { NO_CONTENT, "", {} };
		}
		{	//the { is used so that onResponse is called after session is removed to make debugging performance issues easier
			//request starts here
			Session session;
			session.setUrl("https://discordapp.com/api/v6/" + _url);
			std::vector<HeaderPair> header = {
				{ "Authorization", bot ? "Bot " + getToken() : getToken() },
				{ "User-Agent", "SleepyDiscord (https://github.com/yourWaifu/SleepyDiscord, vtheBestVersion)" },
			};
			if (jsonParameters != "") {
				session.setBody(&jsonParameters);
				header.push_back({"Content-Type", "application/json"});
			//} else if (httpParameters.content != "") {	//this is broken for now
			//	session.SetParameters(httpParameters);
			} else if (0 < multipartParameters.size()) {
				session.setMultipart(multipartParameters);
				header.push_back({ "Content-Type", "multipart/form-data" });
			}
			header.push_back({ "Content-Length", std::to_string(jsonParameters.length()) });
			session.setHeader(header);
			//Response response;
			switch (method) {
			case Post:   response = session.Post  ();       break;
			case Patch:  response = session.Patch ();       break;
			case Delete: response = session.Delete();       break;
			case Get:    response = session.Get   ();       break;
			case Put:    response = session.Put   ();       break;
			default:     response.statusCode = BAD_REQUEST; break; //unexpected method
			}
			//status checking
			switch (response.statusCode) {
			case OK: case CREATED: case NO_CONTENT: case NOT_MODIFIED: break;
			case TOO_MANY_REQUESTS:   //this should fall down to default
				nextRetry = getEpochTimeMillisecond() + std::stoi(response.header["Retry-After"]);
				isRateLimited = true;
			default:
			{		//error
				setError(response.statusCode);		//https error
				std::vector<std::string> values = json::getValues(response.text.c_str(),
				{ "code", "message" });	//parse json to get code and message
				if (!values.empty())
					onError(static_cast<ErrorCode>(std::stoi(values[0])), values[1]);	//send message to the 
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
				throw static_cast<ErrorCode>(response.statusCode);
#endif
			} break;
			}
			//rate limit check
			std::string remaining = response.header["X-RateLimit-Remaining"];
			if (remaining != "" && std::stoi(remaining) == 0) {
				nextRetry = std::stoi(response.header["X-RateLimit-Reset"]);
				isRateLimited = true;
				setError(TOO_MANY_REQUESTS);
			}
		}
		onResponse(response);
		return response;
	}

	Response BaseDiscordClient::request(const RequestMethod method, const std::string url, const std::initializer_list<Part>& multipartParameters) {
		return request(method, url, "", /*cpr::Parameters{},*/ multipartParameters);<commit_msg>fixed crash from some errors<commit_after>#if _MSC_VER && !__INTEL_COMPILER
#pragma warning( disable: 4307 )
#endif

#include <chrono>
#include <functional>
#include "client.h"
#include "json.h"
#ifdef SLEEPY_USE_HARD_CODED_GATEWAY
	#include <cstring>
#endif

namespace SleepyDiscord {
	void BaseDiscordClient::start(const std::string _token, const char maxNumOfThreads) {
		ready = false;
		bot = true;
		token = std::unique_ptr<std::string>(new std::string(_token)); //add client to list
		
		messagesRemaining = 4;
		getTheGateway();
 		connect(theGateway);
#ifndef SLEEPY_ONE_THREAD
		if (2 < maxNumOfThreads) runAsync();
		if (1 < maxNumOfThreads) clock_thread = std::thread(&BaseDiscordClient::runClock_thread, this);
#endif
	}

	BaseDiscordClient::~BaseDiscordClient() {
		ready = false;
#ifndef SLEEPY_ONE_THREAD
		if (clock_thread.joinable()) clock_thread.join();
#endif
	}

	Response BaseDiscordClient::request(const RequestMethod method, const std::string _url, const std::string jsonParameters/*,
		cpr::Parameters httpParameters*/, const std::initializer_list<Part>& multipartParameters) {
		//check if rate limited
		static bool isRateLimited = false;
		static int64_t nextRetry = 0;
		Response response;
		if (isRateLimited) {
			if (nextRetry <= getEpochTimeMillisecond())
				isRateLimited = false;
			else {
				//Response response;
				response.statusCode = TOO_MANY_REQUESTS;
				setError(response.statusCode);
				return response;
			}
		} else if (_url == "gateway") {  //getting the gateway should happen in getTheGateway
			return { NO_CONTENT, "", {} };
		}
		{	//the { is used so that onResponse is called after session is removed to make debugging performance issues easier
			//request starts here
			Session session;
			session.setUrl("https://discordapp.com/api/v6/" + _url);
			std::vector<HeaderPair> header = {
				{ "Authorization", bot ? "Bot " + getToken() : getToken() },
				{ "User-Agent", "SleepyDiscord (https://github.com/yourWaifu/SleepyDiscord, vtheBestVersion)" },
			};
			if (jsonParameters != "") {
				session.setBody(&jsonParameters);
				header.push_back({"Content-Type", "application/json"});
			//} else if (httpParameters.content != "") {	//this is broken for now
			//	session.SetParameters(httpParameters);
			} else if (0 < multipartParameters.size()) {
				session.setMultipart(multipartParameters);
				header.push_back({ "Content-Type", "multipart/form-data" });
			}
			header.push_back({ "Content-Length", std::to_string(jsonParameters.length()) });
			session.setHeader(header);
			//Response response;
			switch (method) {
			case Post:   response = session.Post  ();       break;
			case Patch:  response = session.Patch ();       break;
			case Delete: response = session.Delete();       break;
			case Get:    response = session.Get   ();       break;
			case Put:    response = session.Put   ();       break;
			default:     response.statusCode = BAD_REQUEST; break; //unexpected method
			}
			//status checking
			switch (response.statusCode) {
			case OK: case CREATED: case NO_CONTENT: case NOT_MODIFIED: break;
			case TOO_MANY_REQUESTS:   //this should fall down to default
				nextRetry = getEpochTimeMillisecond() + std::stoi(response.header["Retry-After"]);
				isRateLimited = true;
			default:
			{		//error
				const ErrorCode code = static_cast<ErrorCode>(response.statusCode);
				setError(code);		//https error
				std::vector<std::string> values = json::getValues(response.text.c_str(),
				{ "code", "message" });	//parse json to get code and message
				if (!values.empty() && values[0] != "")
					onError(static_cast<ErrorCode>(std::stoi(values[0])), values[1]);	//send message to the error event
				else
					onError(code, response.text);
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
				throw code;
#endif
			} break;
			}
			//rate limit check
			std::string remaining = response.header["X-RateLimit-Remaining"];
			if (remaining != "" && std::stoi(remaining) == 0) {
				nextRetry = std::stoi(response.header["X-RateLimit-Reset"]);
				isRateLimited = true;
				setError(TOO_MANY_REQUESTS);
			}
		}
		onResponse(response);
		return response;
	}

	Response BaseDiscordClient::request(const RequestMethod method, const std::string url, const std::initializer_list<Part>& multipartParameters) {
		return request(method, url, "", /*cpr::Parameters{},*/ multipartParameters);
{'fraction_non_alphanumeric': 0.13586390464066658, 'fraction_numerical': 0.0035875477375303783, 'mean_word_length': 4.177950868783703, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 23, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2852057', 'n_tokens_mistral': 3081, 'n_tokens_neox': 2712, 'n_words': 637}