1
0
mirror of synced 2024-11-12 02:00:52 +01:00

feat: Added statistics and crash log uploading (#1149)

Co-authored-by: Justus Garbe <gihihoh@gmail.com>
This commit is contained in:
Nik 2023-06-20 11:55:56 +02:00 committed by GitHub
parent 54061c56bf
commit f703b15165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 401 additions and 94 deletions

View File

@ -10,7 +10,6 @@ option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of t
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_DISABLE_UPDATE_CHECK "Disables built-in update check" OFF)
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
@ -58,3 +57,4 @@ add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure packaging
createPackage()
generatePDBs()

View File

@ -73,10 +73,6 @@ macro(addDefines)
endif ()
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
if (NOT IMHEX_DISABLE_UPDATE_CHECK)
add_compile_definitions(HEX_UPDATE_CHECK)
endif()
endmacro()
# Detect current OS / System
@ -237,11 +233,8 @@ macro(createPackage)
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
)
if(_u_deps)
message(WARNING "There were unresolved dependencies for binary: \"${_u_deps}\"!")
endif()
if(_c_deps_FILENAMES)
message(WARNING "There were conflicting dependencies for library: \"${_c_deps}\"!")
message(WARNING "Conflicting dependencies for library: \"${_c_deps}\"!")
endif()
foreach(_file ${_r_deps})
@ -580,3 +573,42 @@ macro(addBundledLibraries)
endif ()
endif ()
endmacro()
function(generatePDBs)
if (NOT WIN32)
return()
endif ()
include(FetchContent)
FetchContent_Declare(
cv2pdb
URL "https://github.com/rainers/cv2pdb/releases/download/v0.52/cv2pdb-0.52.zip"
DOWNLOAD_EXTRACT_TIMESTAMP ON
)
FetchContent_Populate(cv2pdb)
set(PDBS_TO_GENERATE main libimhex ${PLUGINS})
add_custom_target(pdbs)
foreach (PDB ${PDBS_TO_GENERATE})
if (PDB STREQUAL "main")
set(GENERATED_PDB imhex)
else ()
set(GENERATED_PDB ${PDB})
endif ()
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb
WORKING_DIRECTORY ${cv2pdb_SOURCE_DIR}
COMMAND
(${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb &&
${cv2pdb_SOURCE_DIR}/cv2pdb64.exe
$<TARGET_FILE:${PDB}>
${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb) || (exit 0)
DEPENDS $<TARGET_FILE:${PDB}>
COMMAND_EXPAND_LISTS)
target_sources(imhex_all PRIVATE ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb)
install(FILES ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb DESTINATION ".")
endforeach ()
endfunction()

@ -1 +1 @@
Subproject commit 49489507989d767d131342cf3e2c192288cecf14
Subproject commit 128bed69ea0cf4a904e17f5690aa751b6e4b8568

View File

@ -506,6 +506,12 @@ namespace hex {
* @return Whether ImHex is running in portable mode
*/
bool isPortableVersion();
std::string getOSName();
std::string getOSVersion();
std::string getArchitecture();
}
}

View File

@ -196,13 +196,14 @@ namespace hex {
});
}
template<typename T = std::string>
std::future<Result<T>> uploadFile(std::vector<u8> data, const std::string &mimeName = "filename") {
return std::async(std::launch::async, [this, data = std::move(data), mimeName]{
std::future<Result<T>> uploadFile(std::vector<u8> data, const std::string &mimeName = "filename", const std::fs::path &fileName = "data.bin") {
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
curl_mime *mime = curl_mime_init(this->m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
curl_mime_filename(part, "data.bin");
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
curl_mime_filename(part, fileNameStr.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);

View File

@ -4,6 +4,9 @@
#include <hex/api/event.hpp>
#include <hex/api/task.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/fmt.hpp>
#include <wolv/io/file.hpp>
#include <utility>
#include <unistd.h>
@ -16,6 +19,8 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#else
#include <sys/utsname.h>
#endif
namespace hex {
@ -516,6 +521,71 @@ namespace hex {
bool isPortableVersion() {
return impl::s_portableVersion;
}
std::string getOSName() {
#if defined(OS_WINDOWS)
return "Windows";
#elif defined(OS_LINUX)
return "Linux";
#elif defined(OS_MACOS)
return "macOS";
#else
return "Unknown";
#endif
}
std::string getOSVersion() {
#if defined(OS_WINDOWS)
OSVERSIONINFOA info;
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
::GetVersionExA(&info);
return hex::format("{}.{}.{}", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber);
#elif defined(OS_LINUX) || defined(OS_MACOS)
struct utsname details;
if (uname(&details) != 0) {
return "Unknown";
}
return std::string(details.release) + " " + std::string(details.version);
#else
return "Unknown";
#endif
}
std::string getArchitecture() {
#if defined(OS_WINDOWS)
SYSTEM_INFO info;
::GetNativeSystemInfo(&info);
switch (info.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
return "x86_64";
case PROCESSOR_ARCHITECTURE_ARM:
return "ARM";
case PROCESSOR_ARCHITECTURE_ARM64:
return "ARM64";
case PROCESSOR_ARCHITECTURE_IA64:
return "IA64";
case PROCESSOR_ARCHITECTURE_INTEL:
return "x86";
default:
return "Unknown";
}
#elif defined(OS_LINUX) || defined(OS_MACOS)
struct utsname details;
if (uname(&details) != 0) {
return "Unknown";
}
return std::string(details.machine);
#else
return "Unknown";
#endif
}
}
}

View File

@ -1,5 +1,6 @@
#include <hex/helpers/stacktrace.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp>
#if defined(OS_WINDOWS)
@ -24,8 +25,8 @@
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
SymInitialize(process, nullptr, true);
SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_LOAD_ANYTHING);
SymInitialize(process, nullptr, TRUE);
DWORD image;
STACKFRAME64 stackFrame;
@ -47,27 +48,32 @@
SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
break;
if (stackFrame.AddrReturn.Offset == stackFrame.AddrPC.Offset)
break;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
auto symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 displacementSymbol = 0;
const char* symbolName;
if (SymFromAddr(process, stackFrame.AddrPC.Offset, &displacementSymbol, symbol)) {
symbolName = symbol->Name;
std::string symbolName;
if (SymFromAddr(process, stackFrame.AddrPC.Offset, &displacementSymbol, symbol) == TRUE) {
symbolName = hex::format("{} (0x{:X})", symbol->Name, symbol->Address);
} else {
symbolName = "??";
}
SymSetOptions(SYMOPT_LOAD_LINES);
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacementLine = 0;
u32 lineNumber;
const char* fileName;
std::string fileName;
if (SymGetLineFromAddr64(process, stackFrame.AddrPC.Offset, &displacementLine, &line)) {
if (SymGetLineFromAddr64(process, stackFrame.AddrPC.Offset, &displacementLine, &line) == TRUE) {
lineNumber = line.LineNumber;
fileName = line.FileName;
} else {

View File

@ -1,4 +1,6 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/api/task.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/stacktrace.hpp>
@ -6,7 +8,7 @@
#include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp>
#include "window.hpp"
#include <window.hpp>
#include <nlohmann/json.hpp>
@ -15,6 +17,10 @@
#include <exception>
#include <csignal>
#if defined (OS_MACOS)
#include <sys/utsname.h>
#endif
namespace hex::crash {
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
@ -44,20 +50,34 @@ namespace hex::crash {
file.writeString(crashData.dump(4));
file.close();
log::info("Wrote crash.json file to {}", wolv::util::toUTF8String(file.getPath()));
return;
}
}
log::warn("Could not write crash.json file !");
}
static void printStackTrace() {
for (const auto &stackFrame : stacktrace::getStackTrace()) {
if (stackFrame.line == 0)
log::fatal(" {}", stackFrame.function);
else
log::fatal(" ({}:{}) | {}", stackFrame.file, stackFrame.line, stackFrame.function);
}
}
// Custom signal handler to print various information and a stacktrace when the application crashes
static void signalHandler(int signalNumber, const std::string &signalName) {
// Reset the signal handler to the default handler
for(auto signal : Signals) std::signal(signal, SIG_DFL);
log::fatal("Terminating with signal '{}' ({})", signalName, signalNumber);
// Trigger the crash callback
crashCallback(hex::format("Received signal '{}' ({})", signalName, signalNumber));
printStackTrace();
// Trigger an event so that plugins can handle crashes
// It may affect things (like the project path),
// so we do this after saving the crash file
@ -68,17 +88,6 @@ namespace hex::crash {
log::fatal("Uncaught exception thrown!");
}
// Reset the signal handler to the default handler
for(auto signal : Signals) std::signal(signal, SIG_DFL);
// Print stack trace
for (const auto &stackFrame : stacktrace::getStackTrace()) {
if (stackFrame.line == 0)
log::fatal(" {}", stackFrame.function);
else
log::fatal(" ({}:{}) | {}", stackFrame.file, stackFrame.line, stackFrame.function);
}
// Trigger a breakpoint if we're in a debug build or raise the signal again for the default handler to handle it
#if defined(DEBUG)
assert(!"Debug build, triggering breakpoint");
@ -116,6 +125,8 @@ namespace hex::crash {
// Handle crash callback
crashCallback(hex::format("Uncaught exception: {}", exceptionStr));
printStackTrace();
// Reset signal handlers prior to calling the original handler, because it may raise a signal
for(auto signal : Signals) std::signal(signal, SIG_DFL);

View File

@ -27,17 +27,17 @@
#include <wolv/io/fs.hpp>
#include <wolv/io/file.hpp>
#include <wolv/hash/uuid.hpp>
namespace hex::init {
using namespace std::literals::string_literals;
#if defined(HEX_UPDATE_CHECK)
static bool checkForUpdates() {
int showCheckForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2);
int checkForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2);
// Check if we should check for updates
if (showCheckForUpdates == 1){
if (checkForUpdates == 1){
HttpRequest request("GET", GitHubApiURL + "/releases/latest"s);
request.setTimeout(2000);
@ -69,10 +69,36 @@ namespace hex::init {
if (latestVersion != currVersion)
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
// Check if there is a telemetry uuid
std::string uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
if(uuid.empty()) {
// Generate a new uuid
uuid = wolv::hash::generateUUID();
// Save
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid);
}
// Make telemetry request
nlohmann::json telemetry = {
{"uuid", uuid},
{"version", IMHEX_VERSION},
{"os", fmt::format("{}/{}/{}", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture()) }
};
HttpRequest telemetryRequest("POST", ImHexApiURL + "/telemetry"s);
telemetryRequest.setTimeout(2000);
telemetryRequest.setBody(telemetry.dump());
telemetryRequest.addHeader("Content-Type", "application/json");
// Execute request
response = telemetryRequest.execute().get();
if (response.getStatusCode() != 200)
return false;
}
return true;
}
#endif
bool setupEnvironment() {
hex::log::debug("Using romfs: '{}'", romfs::name());
@ -508,9 +534,7 @@ namespace hex::init {
#endif
{ "Loading settings", loadSettings, false },
{ "Loading plugins", loadPlugins, false },
#if defined(HEX_UPDATE_CHECK)
{ "Checking for updates", checkForUpdates, true },
#endif
{ "Loading fonts", loadFonts, true },
};
}

View File

@ -39,9 +39,9 @@ int main(int argc, char **argv, char **envp) {
{
Window::initNative();
hex::log::info("Welcome to ImHex {}!", IMHEX_VERSION);
log::info("Welcome to ImHex {}!", IMHEX_VERSION);
#if defined(GIT_BRANCH) && defined(GIT_COMMIT_HASH_SHORT)
hex::log::info("Compiled using commit {}@{}", GIT_BRANCH, GIT_COMMIT_HASH_SHORT);
log::info("Compiled using commit {}@{}", GIT_BRANCH, GIT_COMMIT_HASH_SHORT);
#endif
init::WindowSplash splashWindow;
@ -56,13 +56,18 @@ int main(int argc, char **argv, char **envp) {
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
}
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
log::info("Using '{}' GPU", ImHexApi::System::getGPUVendor());
// Clean up everything after the main window is closed
ON_SCOPE_EXIT {
auto exitHandler = [](auto){
for (const auto &[name, task, async] : init::getExitTasks())
task();
TaskManager::exit();
};
ON_SCOPE_EXIT { exitHandler(0); };
// Main window
{
Window window;

View File

@ -295,7 +295,6 @@ namespace hex {
log::fatal("Exception raised: 0x{:08X}", exception->ExceptionRecord->ExceptionCode);
if (exception->ExceptionRecord->ExceptionCode == STATUS_HEAP_CORRUPTION) {
log::fatal("Heap corruption detected!");
std::raise(SIGABRT);
}
}

View File

@ -0,0 +1,105 @@
#include <hex/ui/popup.hpp>
#include <hex/api/localization.hpp>
#include <wolv/hash/uuid.hpp>
#include <functional>
#include <string>
namespace hex::plugin::builtin {
class PopupTelemetryRequest : public Popup<PopupTelemetryRequest> {
public:
PopupTelemetryRequest()
: hex::Popup<PopupTelemetryRequest>("hex.builtin.common.question", false) {
// Check if there is a telemetry uuid
this->m_uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
if(this->m_uuid.empty()) {
// Generate a new uuid
this->m_uuid = wolv::hash::generateUUID();
// Save
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", this->m_uuid);
}
}
void drawContent() override {
static std::string message = "hex.builtin.welcome.server_contact_text"_lang;
ImGui::TextFormattedWrapped("{}", message.c_str());
ImGui::NewLine();
if(ImGui::CollapsingHeader("hex.builtin.welcome.server_contact.data_collected_title"_lang)) {
if(ImGui::BeginTable("hex.builtin.welcome.server_contact.data_collected_table"_lang, 2,
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollX | ImGuiTableFlags_NoHostExtendY,
ImVec2(ImGui::GetContentRegionAvail().x, 80_scaled))) {
ImGui::TableSetupColumn("hex.builtin.welcome.server_contact.data_collected_table.key"_lang);
ImGui::TableSetupColumn("hex.builtin.welcome.server_contact.data_collected_table.value"_lang, ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.uuid"_lang);
ImGui::TableNextColumn();
ImGui::TextWrapped("%s", this->m_uuid.c_str());
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.version"_lang);
ImGui::TableNextColumn();
ImGui::TextUnformatted(IMHEX_VERSION);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.os"_lang);
ImGui::TableNextColumn();
ImGui::TextWrapped("%s/%s/%s", ImHexApi::System::getOSName().c_str(), ImHexApi::System::getOSVersion().c_str(), ImHexApi::System::getArchitecture().c_str());
ImGui::EndTable();
}
}
ImGui::NewLine();
const auto width = ImGui::GetWindowWidth();
const auto buttonSize = ImVec2(width / 3 - ImGui::GetStyle().FramePadding.x * 3, 0);
const auto buttonPos = [&](u8 index) { return ImGui::GetStyle().FramePadding.x + (buttonSize.x + ImGui::GetStyle().FramePadding.x * 3) * index; };
ImGui::SetCursorPosX(buttonPos(0));
if (ImGui::Button("hex.builtin.common.allow"_lang, buttonSize)) {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 1);
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1);
this->close();
}
ImGui::SameLine();
ImGui::SetCursorPosX(buttonPos(1));
if (ImGui::Button("hex.builtin.welcome.server_contact.crash_logs_only"_lang, buttonSize)) {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0);
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1);
this->close();
}
ImGui::SameLine();
ImGui::SetCursorPosX(buttonPos(2));
if (ImGui::Button("hex.builtin.common.deny"_lang, buttonSize)) {
this->close();
}
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
}
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
return ImGuiWindowFlags_AlwaysAutoResize;
}
[[nodiscard]] ImVec2 getMinSize() const override {
return scaled({ 500, 100 });
}
[[nodiscard]] ImVec2 getMaxSize() const override {
return scaled({ 500, 400 });
}
private:
std::string m_uuid;
};
}

View File

@ -443,7 +443,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "Allgemein",
"hex.builtin.setting.general.auto_load_patterns": "Automatisches Laden unterstützter Pattern",
"hex.builtin.setting.general.check_for_updates": "Automatisch nach Updates beim Start suchen",
"hex.builtin.setting.general.server_contact": "Update checks und Statistiken zulassen",
"hex.builtin.setting.general.enable_unicode": "Alle Unicode Zeichen laden",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -901,7 +901,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "Hexadezimal (8 bits)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 Farbe",
"hex.builtin.welcome.check_for_updates_text": "Möchtest du beim Start automatisch nach Updates suchen?\nMögliche Updates werden auf der Registerkarte 'Update' des Willkommensbildschirms angezeigt.",
"hex.builtin.welcome.server_contact_text": "Möchtest du die Kommunikation mit ImHex Servern zulassen?\n\nDies erlaubt das automatische suchen nach Updates und das hochladen\nvon anonymen crash logs im falle eines absturzes.",
"hex.builtin.welcome.customize.settings.desc": "Ändere ImHex's Einstellungen",
"hex.builtin.welcome.customize.settings.title": "Einstellungen",
"hex.builtin.welcome.header.customize": "Anpassen",

View File

@ -10,6 +10,7 @@
"hex.builtin.command.web.desc": "Website lookup",
"hex.builtin.command.web.result": "Navigate to '{0}'",
"hex.builtin.common.address": "Address",
"hex.builtin.common.allow": "Allow",
"hex.builtin.common.begin": "Begin",
"hex.builtin.common.big": "Big",
"hex.builtin.common.big_endian": "Big Endian",
@ -21,6 +22,7 @@
"hex.builtin.common.comment": "Comment",
"hex.builtin.common.count": "Count",
"hex.builtin.common.decimal": "Decimal",
"hex.builtin.common.deny": "Deny",
"hex.builtin.common.dont_show_again": "Don't show again",
"hex.builtin.common.encoding.ascii": "ASCII",
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
@ -440,12 +442,13 @@
"hex.builtin.setting.font.font_size.tooltip": "The font size can only be adjusted when a custom font has been selected above.\n\nThis is because ImHex uses a pixel-perfect bitmap font by default. Scaling it by any non-integer factor will only cause it to become blurry.",
"hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_load_patterns": "Auto-load supported pattern",
"hex.builtin.setting.general.check_for_updates": "Check for updates on startup",
"hex.builtin.setting.general.server_contact": "Enable update checks and usage statistics",
"hex.builtin.setting.general.enable_unicode": "Load all unicode characters",
"hex.builtin.setting.general.network_interface": "Enable network interface",
"hex.builtin.setting.general.save_recent_providers": "Save recently used providers",
"hex.builtin.setting.general.show_tips": "Show tips on startup",
"hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between providers",
"hex.builtin.setting.general.upload_crash_logs": "Upload crash reports",
"hex.builtin.setting.hex_editor": "Hex Editor",
"hex.builtin.setting.hex_editor.byte_padding": "Extra byte cell padding",
"hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row",
@ -903,7 +906,14 @@
"hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 Color",
"hex.builtin.welcome.check_for_updates_text": "Do you want to automatically check for updates on startup?\n Possible updates will be shown in the 'Update' tab of the welcome screen",
"hex.builtin.welcome.server_contact_text": "Do you want to allow the communication with ImHex's Servers?\n\n\nThis allows performing automatic update checks and uploads of very limited usage statistics, all of which are listed below.\n\nAlternatively you can also choose to only submit crash logs which help immensely with identifying and fixing bugs you might experience.\n\nAll information is processed by our own Servers and is not given out to any third-parties.\n\n\nYou can change these choices at any time in the settings.",
"hex.builtin.welcome.server_contact.data_collected_table.key": "Type",
"hex.builtin.welcome.server_contact.data_collected_table.value": "Value",
"hex.builtin.welcome.server_contact.data_collected_title": "Data that will be shared",
"hex.builtin.welcome.server_contact.data_collected.uuid": "Random ID",
"hex.builtin.welcome.server_contact.data_collected.version": "ImHex Version",
"hex.builtin.welcome.server_contact.data_collected.os": "Operating System",
"hex.builtin.welcome.server_contact.crash_logs_only": "Just crash logs",
"hex.builtin.welcome.customize.settings.desc": "Change preferences of ImHex",
"hex.builtin.welcome.customize.settings.title": "Settings",
"hex.builtin.welcome.header.customize": "Customize",
@ -935,6 +945,7 @@
"hex.builtin.popup.safety_backup.delete": "No, Delete",
"hex.builtin.popup.safety_backup.desc": "Oh no, ImHex crashed last time.\nDo you want to restore your past work?",
"hex.builtin.popup.safety_backup.log_file": "Log file: ",
"hex.builtin.popup.safety_backup.report_error": "Send crash log to developers",
"hex.builtin.popup.safety_backup.restore": "Yes, Restore",
"hex.builtin.popup.safety_backup.title": "Restore lost data",
"hex.builtin.welcome.start.create_file": "Create New File",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "El tamaño de la fuente de letra puede únicamente ajustarse cuando arriba se ha seleccionado una fuente personalizada.\n\nEsto se debe a que ImHex usa una fuente de mapa de bits pixel-perfect por defecto. Escalarla por un factor no entero sólamente causará que se vuelva borrosa.",
"hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_load_patterns": "Cargar automáticamente patterns soportados",
"hex.builtin.setting.general.check_for_updates": "Comprobar actualizaciones al inicio",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "Cargar todos los caracteres unicode",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "Guardar proveedores recientemente utilizados",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "Color RGBA8",
"hex.builtin.welcome.check_for_updates_text": "¿Quiere que se busquen actualizaciones automáticamente al inicio?\n Las posibles actualizaciones serán mostradas en la pestaña 'Actualizaciones' de la pantalla de inicio",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "Cambie preferencias de ImHex",
"hex.builtin.welcome.customize.settings.title": "Ajustes",
"hex.builtin.welcome.header.customize": "Personalizar",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "Generali",
"hex.builtin.setting.general.auto_load_patterns": "Auto-caricamento del pattern supportato",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "",
"hex.builtin.visualizer.hexii": "",
"hex.builtin.visualizer.rgba8": "",
"hex.builtin.welcome.check_for_updates_text": "",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "Cambia le preferenze di ImHex",
"hex.builtin.welcome.customize.settings.title": "Impostazioni",
"hex.builtin.welcome.header.customize": "Personalizza",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "基本",
"hex.builtin.setting.general.auto_load_patterns": "対応するパターンを自動で読み込む",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "16進数 ( 8 bits)",
"hex.builtin.visualizer.hexii": "",
"hex.builtin.visualizer.rgba8": "RGBA8",
"hex.builtin.welcome.check_for_updates_text": "",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "ImHexの設定を変更します",
"hex.builtin.welcome.customize.settings.title": "設定",
"hex.builtin.welcome.header.customize": "カスタマイズ",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "일반",
"hex.builtin.setting.general.auto_load_patterns": "지원하는 패턴 자동으로 로드",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "16진수 (8 비트)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 색상",
"hex.builtin.welcome.check_for_updates_text": "",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "ImHex의 설정을 변경합니다",
"hex.builtin.welcome.customize.settings.title": "설정",
"hex.builtin.welcome.header.customize": "커스터마이즈",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_load_patterns": "Padrão compatível com carregamento automático",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 Color",
"hex.builtin.welcome.check_for_updates_text": "",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "Mudar preferencias do ImHex",
"hex.builtin.welcome.customize.settings.title": "Configurações",
"hex.builtin.welcome.header.customize": "Customizar",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "通用",
"hex.builtin.setting.general.auto_load_patterns": "自动加载支持的模式",
"hex.builtin.setting.general.check_for_updates": "启动时检查更新",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "加载所有 Unicode 字符",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "十六进制8 位)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 颜色",
"hex.builtin.welcome.check_for_updates_text": "你想要在启动时自动检查更新吗?\n 可用的更新会在欢迎屏幕的“更新”中显示",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "更改 ImHex 的设置",
"hex.builtin.welcome.customize.settings.title": "设置",
"hex.builtin.welcome.header.customize": "自定义",

View File

@ -441,7 +441,7 @@
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.general": "一般",
"hex.builtin.setting.general.auto_load_patterns": "自動載入支援的模式",
"hex.builtin.setting.general.check_for_updates": "Check for updates on startup",
"hex.builtin.setting.general.server_contact": "",
"hex.builtin.setting.general.enable_unicode": "載入所有 unicode 字元",
"hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.save_recent_providers": "",
@ -899,7 +899,7 @@
"hex.builtin.visualizer.hexadecimal.8bit": "十六進位 (8 位元)",
"hex.builtin.visualizer.hexii": "HexII",
"hex.builtin.visualizer.rgba8": "RGBA8 顏色",
"hex.builtin.welcome.check_for_updates_text": "您要在啟動時自動檢查更新嗎?\n 可用更新將在歡迎畫面的「更新」分頁顯示。",
"hex.builtin.welcome.server_contact_text": "",
"hex.builtin.welcome.customize.settings.desc": "更改 ImHex 的設定",
"hex.builtin.welcome.customize.settings.title": "設定",
"hex.builtin.welcome.header.customize": "自訂",

View File

@ -40,24 +40,6 @@ namespace hex::plugin::builtin {
/* General */
/* Values of this setting :
0 - do not check for updates on startup
1 - check for updates on startup
2 - default value - ask the user if he wants to check for updates. This value should only be encountered on the first startup.
*/
#if defined(HEX_UPDATE_CHECK)
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting) == 1;
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
return true;
}
return false;
});
#endif
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting);
@ -124,6 +106,34 @@ namespace hex::plugin::builtin {
return false;
});
/*
Values of this setting :
0 - do not check for updates on startup
1 - check for updates on startup
2 - default value - ask the user if he wants to check for updates. This value should only be encountered on the first startup.
*/
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting) == 1;
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting) == 1;
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
return true;
}
return false;
});
/* Interface */
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", "Dark", [](auto name, nlohmann::json &setting) {

View File

@ -1,10 +1,12 @@
#include <hex.hpp>
#include <hex/helpers/http_requests.hpp>
#include <hex/api/event.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/localization.hpp>
#include <hex/api/plugin_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/api/layout_manager.hpp>
#include <hex/api_urls.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
@ -26,6 +28,7 @@
#include <content/popups/popup_notification.hpp>
#include <content/popups/popup_question.hpp>
#include <content/popups/popup_telemetry_request.hpp>
#include <content/recent.hpp>
#include <string>
@ -46,20 +49,28 @@ namespace hex::plugin::builtin {
std::fs::path m_logFilePath;
std::function<void()> m_restoreCallback;
std::function<void()> m_deleteCallback;
bool m_reportError = true;
public:
PopupRestoreBackup(std::fs::path logFilePath, std::function<void()> restoreCallback, std::function<void()> deleteCallback)
PopupRestoreBackup(const std::fs::path &logFilePath, const std::function<void()> &restoreCallback, const std::function<void()> &deleteCallback)
: Popup("hex.builtin.popup.safety_backup.title"),
m_logFilePath(logFilePath),
m_restoreCallback(restoreCallback),
m_deleteCallback(deleteCallback) { }
m_deleteCallback(deleteCallback) {
this->m_reportError = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1);
}
void drawContent() override {
ImGui::TextUnformatted("hex.builtin.popup.safety_backup.desc"_lang);
if (!this->m_logFilePath.empty()) {
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.popup.safety_backup.log_file"_lang);
ImGui::SameLine(0, 2_scaled);
if (ImGui::Hyperlink(this->m_logFilePath.filename().string().c_str())) {
fs::openFolderWithSelectionExternal(this->m_logFilePath);
}
ImGui::Checkbox("hex.builtin.popup.safety_backup.report_error"_lang, &this->m_reportError);
ImGui::NewLine();
}
@ -69,6 +80,31 @@ namespace hex::plugin::builtin {
this->m_restoreCallback();
this->m_deleteCallback();
if (this->m_reportError) {
wolv::io::File logFile(this->m_logFilePath, wolv::io::File::Mode::Read);
if (logFile.isValid()) {
// Read current log file data
auto data = logFile.readString();
// Anonymize the log file
{
for (u32 pathType = 0; pathType < u32(fs::ImHexPath::END); pathType++) {
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(pathType))) {
auto parent = wolv::util::toUTF8String(folder.parent_path());
data = wolv::util::replaceStrings(data, parent, "<*****>");
}
}
}
TaskManager::createBackgroundTask("Upload Crash report", [path = this->m_logFilePath, data](auto&){
HttpRequest request("POST", ImHexApiURL + std::string("/crash_upload"));
request.uploadFile(std::vector<u8>(data.begin(), data.end()), "file", path.filename()).wait();
});
}
}
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", i64(this->m_reportError));
this->close();
}
ImGui::SameLine();
@ -398,23 +434,14 @@ namespace hex::plugin::builtin {
loadDefaultLayout();
});
#if defined(HEX_UPDATE_CHECK)
EventManager::subscribe<EventWindowInitialized>([] {
// documentation of the value above the setting definition
auto showCheckForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2);
if (showCheckForUpdates == 2) {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 0);
PopupQuestion::open("hex.builtin.welcome.check_for_updates_text"_lang,
[] {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 1);
},
[] {
}
);
auto allowServerContact = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2);
if (allowServerContact == 2) {
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0);
PopupTelemetryRequest::open();
}
});
#endif
// Clear project context if we go back to the welcome screen
EventManager::subscribe<EventProviderChanged>([](hex::prv::Provider *oldProvider, hex::prv::Provider *newProvider) {
@ -452,7 +479,7 @@ namespace hex::plugin::builtin {
auto backupFilePath = path / BackupFileName;
bool hasBackupFile = wolv::io::fs::exists(backupFilePath);
PopupRestoreBackup::open(
// path of log file
crashFileData.value("logFile", ""),