diff --git a/.gitignore b/.gitignore index 8d0f276..9c22db2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,4 @@ -cmake-build-debug/CMakeFiles/ -cmake-build-release/CMakeFiles/ -cmake-build-debug/BeamNG/ -cmake-build-release/BeamNG/ -cmake-build-debug/Resources/ -cmake-build-release/Resources/ -cmake-build-debug/*.* -cmake-build-release/*.* -cmake-build-debug/Makefile -cmake-build-release/Makefile +cmake-build-debug +cmake-build-release /.idea/ *.log -cmake-build-release/key diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fede8a..73f9fdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,18 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "src/*/*.hpp" "include/*.h" "include/*/*.h" "include/*/*/*.h") +#file(GLOB evpp_src evpp/evpp/*.cc evpp/evpp/*/*.cc evpp/evpp/*.h evpp/evpp/*/*.h) + add_executable(${PROJECT_NAME} ${source_files}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Launcher") - +add_definitions("-DEVPP_HTTP_CLIENT_SUPPORTS_SSL") +add_subdirectory("evpp") if (WIN32) + find_package(glog CONFIG REQUIRED) + find_package(Libevent CONFIG REQUIRED) find_package(ZLIB REQUIRED) find_package(CURL REQUIRED) + find_package(OpenSSL REQUIRED) message(STATUS "MSVC -> forcing use of statically-linked runtime.") STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) @@ -17,11 +23,13 @@ if (WIN32) set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}) include_directories(${VcpkgRoot}/include) link_directories(${VcpkgRoot}/lib) - target_link_libraries(${PROJECT_NAME} PRIVATE discord-rpc CURL::libcurl ZLIB::ZLIB) + target_link_libraries(${PROJECT_NAME} PRIVATE discord-rpc evpp_static + libevent::core libevent::extra glog::glog ZLIB::ZLIB + OpenSSL::SSL OpenSSL::Crypto libevent::openssl) else(WIN32) #MINGW add_definitions("-D_WIN32_WINNT=0x0600") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s -static-libgcc -static-libstdc++ --static") - target_link_libraries(${PROJECT_NAME} discord-rpc.a ssp z ws2_32) + target_link_libraries(${PROJECT_NAME} discord-rpc evpp_static glog event pthread ssl crypto event_openssl ws2_32 ssp dbghelp iphlpapi z) endif(WIN32) -target_include_directories(${PROJECT_NAME} PUBLIC $) \ No newline at end of file +target_include_directories(${PROJECT_NAME} PUBLIC include evpp) \ No newline at end of file diff --git a/include/http.h b/include/http.h index 75640c8..0ede2be 100755 --- a/include/http.h +++ b/include/http.h @@ -6,7 +6,21 @@ /// Created by Anonymous275 on 7/18/2020 /// #pragma once +#include +#include #include -int Download(const std::string& URL,const std::string& Path,bool close); -std::string PostHTTP(const std::string& IP, const std::string& Fields); -std::string HTTP_REQUEST(const std::string& IP,int port); \ No newline at end of file +#include "Logger.h" +class HTTP{ +public: + static void Response(const std::shared_ptr& response, evpp::httpc::Request* request); + static bool Download(const std::string &IP, const std::string &Path); + static std::string Post(const std::string& IP, const std::string& Fields); + static std::string Get(const std::string &IP); + static void Init(char* argv[]){ + google::InitGoogleLogging(argv[0]); + google::SetStderrLogging(google::GLOG_ERROR); + evpp::httpc::SET_SSL_VERIFY_MODE(SSL_VERIFY_NONE); + } +private: + static std::string Res_; +}; \ No newline at end of file diff --git a/include/winmain-inl.h b/include/winmain-inl.h new file mode 100644 index 0000000..5cabc5d --- /dev/null +++ b/include/winmain-inl.h @@ -0,0 +1,24 @@ +#pragma once + +namespace { +struct OnApp { + OnApp() { +#ifdef WIN32 + // Initialize Winsock 2.2 + WSADATA wsaData; + int err = WSAStartup(MAKEWORD(2, 2), &wsaData); + + if (err) { + std::cout << "WSAStartup() failed with error: %d" << err; + } +#endif + } + ~OnApp() { +#ifdef WIN32 + WSACleanup(); +#endif + } +} __s_onexit_pause; +} + + diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index ba55b90..4ed22ea 100755 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -8,7 +8,7 @@ #include "Network/network.h" #include "Security/Init.h" -#include "Curl/http.h" +#include "http.h" #include #include #include "Startup.h" @@ -58,7 +58,7 @@ void Parse(std::string Data,SOCKET CSocket){ NetReset(); Terminate = true; TCPTerminate = true; - Data = Code + HTTP_REQUEST("https://beammp.com/servers-info",443); + Data = Code + HTTP::Get("https://beammp.com/servers-info"); break; case 'C': ListOfMods.clear(); diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index b23108c..20b7365 100755 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -6,139 +6,113 @@ /// Created by Anonymous275 on 7/18/2020 /// -#include +#include +#include #include #include +#include +#include "http.h" #include #include -class CurlManager{ -public: - CurlManager(){ - curl = curl_easy_init(); - } - ~CurlManager(){ - curl_easy_cleanup(curl); - } - inline CURL* Get(){ - return curl; - } -private: - CURL *curl; -}; +#include "winmain-inl.h" -static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){ - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; +static bool responded; +std::string HTTP::Res_{}; +void HTTP::Response(const std::shared_ptr& response, evpp::httpc::Request* request){ + if(response->http_code() == 200){ + Res_ = std::move(response->body().ToString()); + } else { + std::cout << "\n"; + error("Failed request! http code " + std::to_string(response->http_code())); + } + responded = true; + assert(request == response->request()); + delete request; } -std::string HTTP_REQUEST(const std::string& IP,int port){ - static thread_local CurlManager M; +std::string HTTP::Get(const std::string &IP) { static std::mutex Lock; std::scoped_lock Guard(Lock); - CURL *curl = M.Get(); - CURLcode res; - std::string readBuffer; - if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(curl, CURLOPT_PORT, port); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); - res = curl_easy_perform(curl); - if(res != CURLE_OK)return "-1"; + responded = false; + Res_.clear(); + evpp::EventLoopThread t; + t.Start(true); + + auto* r = new evpp::httpc::GetRequest(t.loop(), IP, evpp::Duration(10.0)); + r->Execute(Response); + + while (!responded) { + usleep(1); } - return readBuffer; + + t.Stop(true); + return Res_; } -int nb_bar; -double last_progress, progress_bar_adv; -bool Downloaded; -int progress_bar (void *bar, double t, double d){ - if(t > 0 && last_progress != round(d/t*100)){ - nb_bar = 25; - progress_bar_adv = round(d/t*nb_bar); - std::cout<<"\r"; - std::cout<< "Progress : [ "; - std::cout<stream) { - fopen_s(&out->stream,out->filename,"wb"); - if(!out->stream)return -1; - } - return fwrite(buffer, size, nmemb, out->stream); -} -int Download(const std::string& URL,const std::string& Path,bool close){ - static thread_local CurlManager M; - CURL *curl = M.Get(); - CURLcode res; - struct File file = {Path.c_str(),nullptr}; - Downloaded = false; - if(curl){ - curl_easy_setopt(curl, CURLOPT_URL,URL.c_str()); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_bar); - curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); - res = curl_easy_perform(curl); - if(res != CURLE_OK){ - return res; - } - } - if(file.stream)fclose(file.stream); - if(!Downloaded){ - remove(Path.c_str()); - fatal("Failed to download please try again later!"); - } - std::cout << std::endl; - return -1; -} -std::string PostHTTP(const std::string& IP, const std::string& Fields) { - static auto *header = new curl_slist{(char*)"Content-Type: application/json"}; - static thread_local CurlManager M; +std::string HTTP::Post(const std::string& IP, const std::string& Fields) { static std::mutex Lock; std::scoped_lock Guard(Lock); - CURL* curl = M.Get(); - CURLcode res; - std::string readBuffer; + responded = false; + Res_.clear(); + evpp::EventLoopThread t; + t.Start(true); + auto* r = new evpp::httpc::PostRequest(t.loop(), IP, Fields, evpp::Duration(10.0)); + r->AddHeader("Content-Type","application/json"); + r->Execute(Response); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - //curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); - - res = curl_easy_perform(curl); - - if (res != CURLE_OK) - return "-1"; + while (!responded) { + usleep(1); } - return readBuffer; -} \ No newline at end of file + + t.Stop(true); + if(Res_.empty())return "-1"; + else return Res_; +} + +void ProgressBar(size_t d, size_t t){ + static double last_progress, progress_bar_adv; + progress_bar_adv = round(d/double(t)*25); + std::cout << "\r"; + std::cout << "Progress : [ "; + std::cout << round(d/double(t)*100); + std::cout << "% ] ["; + int i; + for(i = 0; i <= progress_bar_adv; i++)std::cout<<"#"; + for(i = 0; i < 25 - progress_bar_adv; i++)std::cout<<"."; + std::cout << "]"; + last_progress = round(d/double(t)*100); +} + +bool HTTP::Download(const std::string &IP, const std::string &Path) { + static std::mutex Lock; + std::scoped_lock Guard(Lock); + responded = false; + Res_.clear(); + evpp::EventLoopThread t; + t.Start(true); + auto* r = new evpp::httpc::GetRequest(t.loop(), IP, evpp::Duration(10.0)); + r->set_progress_callback(ProgressBar); + r->Execute(Response); + + while (!responded) { + usleep(1); + } + + t.Stop(true); + + if(Res_.empty())return false; + + std::ofstream File(Path, std::ios::binary); + if(File.is_open()) { + File << Res_; + File.close(); + std::cout << "\n"; + }else{ + error("Failed to open file directory: " + Path); + return false; + } + + return true; +} diff --git a/src/Security/Login.cpp b/src/Security/Login.cpp index b3ae762..3efc6e9 100755 --- a/src/Security/Login.cpp +++ b/src/Security/Login.cpp @@ -6,7 +6,7 @@ /// Created by Anonymous275 on 11/26/2020 /// -#include "Curl/http.h" +#include "http.h" #include #include "Logger.h" #include @@ -47,7 +47,7 @@ std::string Login(const std::string& fields){ return ""; } info("Attempting to authenticate..."); - std::string Buffer = PostHTTP("https://auth.beammp.com/userlogin", fields); + std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields); json::Document d; d.Parse(Buffer.c_str()); if(Buffer == "-1"){ @@ -88,7 +88,7 @@ void CheckLocalKey(){ Key.read(&Buffer[0], Size); Key.close(); - Buffer = PostHTTP("https://auth.beammp.com/userlogin", R"({"pk":")"+Buffer+"\"}"); + Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}"); json::Document d; d.Parse(Buffer.c_str()); diff --git a/src/Startup.cpp b/src/Startup.cpp index d23f2b7..79030e2 100755 --- a/src/Startup.cpp +++ b/src/Startup.cpp @@ -6,16 +6,15 @@ /// Created by Anonymous275 on 7/16/2020 /// - #include "Discord/discord_info.h" #include "Network/network.h" #include "Security/Init.h" -#include "Curl/http.h" -#include #include #include "Startup.h" +#include #include "Logger.h" #include +#include "http.h" extern int TraceBack; bool Dev = false; @@ -71,20 +70,19 @@ void CheckName(int argc,char* args[]){ } void CheckForUpdates(int argc,char*args[],const std::string& CV){ - std::string link = "https://beammp.com/builds/launcher?version=true"; - std::string HTTP = HTTP_REQUEST(link,443); + std::string link; + std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true"); bool fallback = false; if(HTTP.find_first_of("0123456789") == std::string::npos){ - link = "https://backup1.beammp.com/builds/launcher?version=true"; - HTTP = HTTP_REQUEST(link,443); + HTTP = HTTP::Get("https://backup1.beammp.com/builds/launcher?version=true"); fallback = true; if(HTTP.find_first_of("0123456789") == std::string::npos) { fatal("Primary Servers Offline! sorry for the inconvenience!"); } } if(fallback){ - link = "https://backup1.beammp.com/builds/launcher?download=true"; - }else link = "https://beammp.com/builds/launcher?download=true"; + link = "www.backup1.beammp.com/builds/launcher?download=true"; + }else link = "www.beammp.com/builds/launcher?download=true"; std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); @@ -95,13 +93,13 @@ void CheckForUpdates(int argc,char*args[],const std::string& CV){ info("Update found!"); info("Updating..."); if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!"); - int i = Download(link, EP,true); - if(i != -1){ - error("Launcher Update failed! trying again... code : " + std::to_string(i)); + + if(!HTTP::Download(link, EP)){ + error("Launcher Update failed! trying again..."); std::this_thread::sleep_for(std::chrono::seconds(2)); - int i2 = Download(link, EP,true); - if(i2 != -1){ - error("Launcher Update failed! code : " + std::to_string(i2)); + + if(!HTTP::Download(link, EP)){ + error("Launcher Update failed!"); std::this_thread::sleep_for(std::chrono::seconds(5)); ReLaunch(argc,args); } @@ -125,7 +123,6 @@ void CustomPort(int argc, char* argv[]){ } void InitLauncher(int argc, char* argv[]) { system("cls"); - curl_global_init(CURL_GLOBAL_DEFAULT); SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str()); InitLog(); CheckName(argc, argv); @@ -134,7 +131,6 @@ void InitLauncher(int argc, char* argv[]) { CustomPort(argc, argv); Discord_Main(); CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch()); - } size_t DirCount(const std::filesystem::path& path){ return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{}); @@ -180,11 +176,11 @@ void PreGame(const std::string& GamePath){ fatal(e.what()); } - /* Download("https://backend.beammp.com/builds/client?download=true" + /* Download("www.backend.beammp.com/builds/client?download=true" "&pk=" + PublicKey + "&branch=" + Branch, GetGamePath() + R"(mods\multiplayer\BeamMP.zip)", true);*/ - Download("https://beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)", true); + HTTP::Download("https://beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); info("Download Complete!"); } diff --git a/src/main.cpp b/src/main.cpp index 5de2f30..ccf126c 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,7 @@ #include #include "Logger.h" #include - +#include "http.h" [[noreturn]] void flush(){ while(true){ @@ -20,24 +20,25 @@ } } + int main(int argc, char* argv[]) { #ifdef DEBUG std::thread th(flush); th.detach(); #endif - GetEP(argv[0]); + HTTP::Init(argv); InitLauncher(argc,argv); + try { LegitimacyCheck(); }catch (std::exception& e){ fatal("Main 1 : " + std::string(e.what())); } + PreGame(GetGameDir()); InitGame(GetGameDir()); CoreNetwork(); - ///TODO: make sure to use argv[0] for everything that should be in the same dir (mod down ect...) - ///move to master create branch then make the new config in json }