Update:
- Add Support for Downloading Data/Files, do Api Requests - Refactor Tasks System - Now uses std::thread - The Net Functions Will Break IDBN server for now
This commit is contained in:
parent
a0923acec7
commit
6d7781b209
@ -30,6 +30,8 @@
|
||||
- Fix Crash in FilsSystem
|
||||
- Implement basic Theme System
|
||||
- Remove 0.9.4 Security
|
||||
- Tasks now based on std functional/thread
|
||||
- Add Network Support (Download Files, APi Requests)
|
||||
## 0.9.4
|
||||
- Implement new Security System To prevent from crashes
|
||||
- Implement Functiontrace for better Timing Tests
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <renderd7/Hid.hpp>
|
||||
#include <renderd7/Image.hpp>
|
||||
#include <renderd7/Message.hpp>
|
||||
#include <renderd7/Net.hpp>
|
||||
#include <renderd7/Overlays.hpp>
|
||||
#include <renderd7/StealConsole.hpp>
|
||||
#include <renderd7/Timer.hpp>
|
||||
|
60
include/renderd7/Net.hpp
Normal file
60
include/renderd7/Net.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* This file is part of RenderD7
|
||||
* Copyright (C) 2021-2024 NPI-D7, tobid7
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <renderd7/external/json.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace RenderD7 {
|
||||
namespace Net {
|
||||
// Define List of Errors
|
||||
enum Error_ {
|
||||
Error_None, // Function Executed Successfully
|
||||
Error_Memory, // Memory Allocation Error
|
||||
Error_Write, // Unable to Write File
|
||||
Error_StatusCode, // Error with Status Code
|
||||
Error_Git, // Git Error
|
||||
Error_CtrStatus, // 3ds Result Code
|
||||
Error_Curl, // Curl Error
|
||||
Error_Busy, // Another Download Taskl is already running
|
||||
Error_Invalid, // Invalid Json struct
|
||||
Error_NoWifi, // Console not connected to wifi
|
||||
};
|
||||
// Set an typedefine for Error code
|
||||
using Error = unsigned long long;
|
||||
// Extract Error_ from Error code
|
||||
inline Error_ ErrorCode(Error err) {
|
||||
return static_cast<Error_>(static_cast<unsigned int>(err & 0xffffffff));
|
||||
}
|
||||
// Extract Http Status code, Curl Error Code or Ctr Result Code
|
||||
inline int StatusCode(Error err) {
|
||||
Error_ c = ErrorCode(err);
|
||||
if (c != Error_StatusCode && c != Error_CtrStatus && c != Error_Curl)
|
||||
return 0;
|
||||
return static_cast<unsigned int>(err >> 32);
|
||||
}
|
||||
Error Download(const std::string& url, std::string& data);
|
||||
Error Download2File(const std::string& url, const std::string& path);
|
||||
Error GitDownloadRelease(const std::string& url, const std::string& asset_name,
|
||||
const std::string& path, bool prerelease = false);
|
||||
Error JsonApiRequest(const std::string& api_url, nlohmann::json& res);
|
||||
unsigned long long GetProgressCurrent();
|
||||
unsigned long long GetProgressTotal();
|
||||
} // namespace Net
|
||||
} // namespace RenderD7
|
@ -17,14 +17,15 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <3ds.h>
|
||||
#include <functional>
|
||||
|
||||
namespace RenderD7 {
|
||||
namespace Tasks {
|
||||
/// @brief Push A Task
|
||||
/// @param entrypoint Function of Your Task
|
||||
void create(ThreadFunc entrypoint);
|
||||
/// @param fun Function of Your Task
|
||||
/// @return index
|
||||
int Create(std::function<void()> fun);
|
||||
/// @brief Destroy all Tasks
|
||||
void destroy(void);
|
||||
void DestroyAll();
|
||||
} // namespace Tasks
|
||||
} // namespace RenderD7
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <renderd7/Net.hpp>
|
||||
#include <renderd7/external/json.hpp>
|
||||
#include <renderd7/global_db.hpp>
|
||||
#include <renderd7/renderd7.hpp>
|
||||
@ -73,3 +74,7 @@ extern bool rd7i_fade_scene_wait;
|
||||
extern bool rd7i_idb_running;
|
||||
extern bool rd7i_graphics_on;
|
||||
extern bool rd7i_amdt;
|
||||
extern void* rd7i_soc_buf;
|
||||
|
||||
RenderD7::Net::Error rd7i_soc_init();
|
||||
void rd7i_soc_deinit();
|
294
source/Net.cpp
Normal file
294
source/Net.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
/**
|
||||
* This file is part of RenderD7
|
||||
* Copyright (C) 2021-2024 NPI-D7, tobid7
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TODO: Make Download2File faster on large files
|
||||
|
||||
#include <3ds.h>
|
||||
#include <curl/curl.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <renderd7/Net.hpp>
|
||||
#include <renderd7/internal_db.hpp>
|
||||
|
||||
static RenderD7::Net::Error rd7i_check_wifi() {
|
||||
// if (rd7i_is_citra) return 0;
|
||||
int s = osGetWifiStrength();
|
||||
return (s == 0);
|
||||
}
|
||||
|
||||
static size_t rd7i_handle_data(char* ptr, size_t size, size_t nmemb,
|
||||
void* userdata) {
|
||||
size_t ms = size * nmemb;
|
||||
((std::string*)userdata)->append(ptr, ms);
|
||||
return ms;
|
||||
}
|
||||
|
||||
static size_t rd7i_handle_file(char* ptr, size_t size, size_t nmemb,
|
||||
void* out) {
|
||||
size_t ms = size * nmemb;
|
||||
((std::ofstream*)out)->write(reinterpret_cast<const char*>(ptr), ms);
|
||||
return ms;
|
||||
}
|
||||
|
||||
struct rd7i_net_dl {
|
||||
unsigned long long current = 0;
|
||||
unsigned long long total = 1;
|
||||
void Reset() {
|
||||
current = 0;
|
||||
total = 1;
|
||||
}
|
||||
};
|
||||
|
||||
static rd7i_net_dl rd7i_net_dl_spec;
|
||||
|
||||
static int rd7i_handle_curl_progress(CURL* hnd, curl_off_t dltotal,
|
||||
curl_off_t dlnow, curl_off_t ultotal,
|
||||
curl_off_t ulnow) {
|
||||
rd7i_net_dl_spec.total = dltotal;
|
||||
rd7i_net_dl_spec.current = dlnow;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rd7i_setup_curl_context(CURL* hnd, const std::string& url,
|
||||
void* userptr, bool mem) {
|
||||
std::string user_agent =
|
||||
rd7i_app_name + "/RenderD7 (Version: " + std::string(RENDERD7VSTRING) +
|
||||
")";
|
||||
|
||||
if (!mem) {
|
||||
curl_easy_setopt(hnd, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt(hnd, CURLOPT_ACCEPT_ENCODING, "gzip");
|
||||
curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, rd7i_handle_curl_progress);
|
||||
}
|
||||
|
||||
curl_easy_setopt(hnd, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L);
|
||||
curl_easy_setopt(hnd, CURLOPT_USERAGENT, user_agent.c_str());
|
||||
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, userptr);
|
||||
curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
|
||||
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
|
||||
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION,
|
||||
mem ? rd7i_handle_data : rd7i_handle_file);
|
||||
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
|
||||
curl_easy_setopt(hnd, CURLOPT_STDERR, stdout);
|
||||
}
|
||||
|
||||
static bool rd7i_curl_is_busy = false;
|
||||
static bool rd7i_apir_is_busy = false;
|
||||
|
||||
namespace RenderD7 {
|
||||
namespace Net {
|
||||
Error Download(const std::string& url, std::string& data) {
|
||||
if (rd7i_curl_is_busy) return Error_Busy;
|
||||
Error ret = rd7i_check_wifi();
|
||||
if (ret != 0) {
|
||||
if (ret == 1) {
|
||||
return Error_NoWifi;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
rd7i_curl_is_busy = true;
|
||||
rd7i_net_dl_spec.Reset();
|
||||
ret = rd7i_soc_init();
|
||||
if (ret) {
|
||||
rd7i_curl_is_busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto hnd = curl_easy_init();
|
||||
rd7i_setup_curl_context(hnd, url, &data, true);
|
||||
|
||||
CURLcode curl_res = curl_easy_perform(hnd);
|
||||
curl_easy_cleanup(hnd);
|
||||
|
||||
if (curl_res != CURLE_OK) {
|
||||
data.clear();
|
||||
rd7i_soc_deinit();
|
||||
rd7i_curl_is_busy = false;
|
||||
return ((static_cast<Error>(curl_res) << 32) |
|
||||
static_cast<Error>(Error_Curl));
|
||||
}
|
||||
|
||||
rd7i_soc_deinit();
|
||||
rd7i_curl_is_busy = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Error Download2File(const std::string& url, const std::string& path) {
|
||||
if (rd7i_curl_is_busy) return Error_Busy;
|
||||
Error ret = rd7i_check_wifi();
|
||||
if (ret != 0) {
|
||||
if (ret == 1) {
|
||||
return Error_NoWifi;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
rd7i_curl_is_busy = true;
|
||||
rd7i_net_dl_spec.Reset();
|
||||
ret = rd7i_soc_init();
|
||||
if (ret) {
|
||||
rd7i_curl_is_busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// std::filesystem::create_directories(
|
||||
// std::filesystem::path(path).remove_filename());
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
|
||||
if (!file.is_open()) {
|
||||
rd7i_curl_is_busy = false;
|
||||
return Error_Write;
|
||||
}
|
||||
|
||||
auto hnd = curl_easy_init();
|
||||
rd7i_setup_curl_context(hnd, url, &file, false);
|
||||
|
||||
CURLcode curl_res = curl_easy_perform(hnd);
|
||||
curl_easy_cleanup(hnd);
|
||||
|
||||
file.close();
|
||||
if (curl_res != CURLE_OK) {
|
||||
rd7i_soc_deinit();
|
||||
if (RenderD7::FS::FileExist(path)) {
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
rd7i_curl_is_busy = false;
|
||||
return ((static_cast<Error>(curl_res) << 32) |
|
||||
static_cast<Error>(Error_Curl));
|
||||
}
|
||||
|
||||
rd7i_soc_deinit();
|
||||
rd7i_curl_is_busy = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Error GitDownloadRelease(const std::string& url, const std::string& asset_name,
|
||||
const std::string& path, bool prerelease) {
|
||||
if (rd7i_apir_is_busy) return Error_Busy;
|
||||
Error ret = rd7i_check_wifi();
|
||||
if (ret != 0) {
|
||||
if (ret == 1) {
|
||||
return Error_NoWifi;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
rd7i_apir_is_busy = true;
|
||||
std::regex parse("github\\.com\\/(.+)\\/(.+)");
|
||||
std::smatch res;
|
||||
std::regex_search(url, res, parse);
|
||||
|
||||
std::string user = res[1].str();
|
||||
std::string repo = res[2].str();
|
||||
|
||||
std::stringstream req;
|
||||
req << "https://api.github.com/repos/" << user << "/" << repo
|
||||
<< (prerelease ? "/releases" : "/releases/latest");
|
||||
|
||||
std::string buf;
|
||||
ret = Download(req.str(), buf);
|
||||
if (ret) {
|
||||
rd7i_apir_is_busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pret = 0;
|
||||
std::string freq;
|
||||
if (nlohmann::json::accept(buf)) {
|
||||
nlohmann::json api = nlohmann::json::parse(buf);
|
||||
if (!api.size()) pret = -1;
|
||||
if (pret != -1) {
|
||||
if (prerelease) api = api[0];
|
||||
if (api["assets"].is_array()) {
|
||||
for (const auto& asset : api["assets"]) {
|
||||
if (asset.is_object() && asset["name"].is_string() &&
|
||||
asset["browser_download_url"].is_string()) {
|
||||
if (std::regex_match(std::string(asset["name"]),
|
||||
std::regex(asset_name))) {
|
||||
freq = asset["browser_download_url"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pret = -1;
|
||||
}
|
||||
|
||||
if (pret != 0 || freq.empty()) {
|
||||
rd7i_apir_is_busy = false;
|
||||
return Error_Git;
|
||||
}
|
||||
|
||||
ret = Download2File(freq, path);
|
||||
rd7i_apir_is_busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error JsonApiRequest(const std::string& api_url, nlohmann::json& res) {
|
||||
if (rd7i_apir_is_busy) return Error_Busy;
|
||||
Error ret = rd7i_check_wifi();
|
||||
if (ret != 0) {
|
||||
if (ret == 1) {
|
||||
return Error_NoWifi;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
rd7i_apir_is_busy = true;
|
||||
|
||||
std::string buf;
|
||||
ret = Download(api_url, buf);
|
||||
if (ret) {
|
||||
rd7i_apir_is_busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (nlohmann::json::accept(buf)) {
|
||||
res = nlohmann::json::parse(buf);
|
||||
if (!res.size()) {
|
||||
rd7i_apir_is_busy = false;
|
||||
return Error_Invalid;
|
||||
}
|
||||
} else {
|
||||
rd7i_apir_is_busy = false;
|
||||
return Error_Invalid;
|
||||
}
|
||||
|
||||
rd7i_apir_is_busy = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long GetProgressCurrent() { return rd7i_net_dl_spec.current; }
|
||||
unsigned long long GetProgressTotal() {
|
||||
// As curl sets total to 0 we need
|
||||
// to return a 1 as devide by zeroi will crash
|
||||
if (rd7i_net_dl_spec.total <= 0) return 1;
|
||||
return rd7i_net_dl_spec.total;
|
||||
}
|
||||
} // namespace Net
|
||||
} // namespace RenderD7
|
@ -16,26 +16,25 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <3ds.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <renderd7/Tasks.hpp>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
static std::vector<Thread> threads;
|
||||
static std::vector<std::shared_ptr<std::thread>> threads;
|
||||
|
||||
void RenderD7::Tasks::create(ThreadFunc entrypoint) {
|
||||
s32 prio = 0;
|
||||
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||
Thread thread = threadCreate((ThreadFunc)entrypoint, NULL, 64 * 1024,
|
||||
prio - 1, -2, false);
|
||||
threads.push_back(thread);
|
||||
int RenderD7::Tasks::Create(std::function<void()> fun) {
|
||||
auto thrd = std::make_shared<std::thread>(fun);
|
||||
threads.push_back(thrd);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
void RenderD7::Tasks::destroy(void) {
|
||||
for (u32 i = 0; i < threads.size(); i++) {
|
||||
threadJoin(threads.at(i), U64_MAX);
|
||||
threadFree(threads.at(i));
|
||||
void RenderD7::Tasks::DestroyAll() {
|
||||
for (auto& it : threads) {
|
||||
if (it && it->joinable()) {
|
||||
it->join();
|
||||
}
|
||||
}
|
||||
// Delete Pointers
|
||||
threads.clear();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include <renderd7/FileSystem.hpp>
|
||||
#include <renderd7/external/json.hpp>
|
||||
#include <renderd7/internal_db.hpp>
|
||||
#include <renderd7/renderd7.hpp>
|
||||
|
||||
/// Base ///
|
||||
@ -71,6 +72,7 @@ bool rd7i_idb_running = false;
|
||||
bool rd7i_graphics_on = false;
|
||||
float rd7_draw2_tsm = 1.2f;
|
||||
bool rd7i_amdt = false;
|
||||
void *rd7i_soc_buf = nullptr;
|
||||
|
||||
/// Global ///
|
||||
// Outdated HidApi (HidV2Patched)
|
||||
@ -94,6 +96,31 @@ C3D_RenderTarget *rd7_top;
|
||||
C3D_RenderTarget *rd7_top_right;
|
||||
C3D_RenderTarget *rd7_bottom;
|
||||
|
||||
RenderD7::Net::Error rd7i_soc_init() {
|
||||
if (rd7i_soc_buf != nullptr) {
|
||||
return 0;
|
||||
}
|
||||
rd7i_soc_buf = memalign(0x1000, 0x100000);
|
||||
if (!rd7i_soc_buf) {
|
||||
return RenderD7::Net::Error_Memory;
|
||||
}
|
||||
Result ret = socInit((u32 *)rd7i_soc_buf, 0x100000);
|
||||
if (R_FAILED(ret)) {
|
||||
free(rd7i_soc_buf);
|
||||
return ((static_cast<RenderD7::Net::Error>(ret) << 32) |
|
||||
static_cast<RenderD7::Net::Error>(RenderD7::Net::Error_CtrStatus));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rd7i_soc_deinit() {
|
||||
if (rd7i_soc_buf) {
|
||||
socExit();
|
||||
free(rd7i_soc_buf);
|
||||
}
|
||||
rd7i_soc_buf = nullptr;
|
||||
}
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
Logger() = default;
|
||||
@ -157,10 +184,10 @@ class tcp_server {
|
||||
|
||||
#define stupid(x) &x, sizeof(x)
|
||||
#define rd7i_reacttion(x) \
|
||||
({ \
|
||||
{ \
|
||||
int code = x; \
|
||||
server.snd(stupid(code)); \
|
||||
})
|
||||
}
|
||||
|
||||
struct pak32 {
|
||||
pak32() {}
|
||||
@ -206,30 +233,16 @@ struct pak32 {
|
||||
unsigned int tbs;
|
||||
};
|
||||
|
||||
#define SOC_ALIGN 0x1000
|
||||
#define SOC_BUFFERSIZE 0x100000
|
||||
|
||||
static u32 *SOC_buffer = NULL;
|
||||
static bool rd7i_idb_fp = false;
|
||||
|
||||
void KillIdbServer() {
|
||||
rd7i_idb_fp = true;
|
||||
rd7i_idb_server.join(100);
|
||||
socExit();
|
||||
rd7i_soc_deinit();
|
||||
}
|
||||
|
||||
void ServerThread(RenderD7::Parameter param) {
|
||||
Result ret;
|
||||
SOC_buffer = (u32 *)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||
|
||||
if (SOC_buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now intialise soc:u service
|
||||
if ((ret = socInit(SOC_buffer, SOC_BUFFERSIZE)) != 0) {
|
||||
return;
|
||||
}
|
||||
if (rd7i_soc_init()) return;
|
||||
rd7i_idb_running = true;
|
||||
rd7i_idb_fp = false;
|
||||
atexit(KillIdbServer);
|
||||
|
@ -451,7 +451,8 @@ int RenderD7::GetRandomInt(int b, int e) {
|
||||
}
|
||||
|
||||
bool RenderD7::FS::FileExist(const std::string &path) {
|
||||
return std::filesystem::exists(path);
|
||||
return std::filesystem::exists(path) &&
|
||||
std::filesystem::is_regular_file(path);
|
||||
}
|
||||
|
||||
int RenderD7::GetFps() { return (int)rd7i_framerate; }
|
||||
|
Loading…
Reference in New Issue
Block a user