From 911589111e1774a66c66c11013c41b78b523445b Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Tue, 21 Sep 2021 11:29:48 -0300 Subject: [PATCH 01/10] Add Sentry as an alternative to handling minidumps manually (#2857) --- CMakeLists.txt | 6 ++++++ src/app/CMakeLists.txt | 14 +++++++++++++- src/app/app.cpp | 2 ++ src/app/send_crash.h | 6 +++++- src/main/main.cpp | 36 +++++++++++++++++++++++++++++++++++- 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 749f8359c..3af0bd074 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,8 +79,14 @@ option(ENABLE_UI "Compile UI (turn off to compile CLI-only version)" o option(FULLSCREEN_PLATFORM "Enable fullscreen by default" off) option(ENABLE_CLANG_TIDY "Enable static analysis" off) option(ENABLE_CCACHE "Use CCache to improve recompilation speed (optional)" on) +option(ENABLE_SENTRY "Use Sentry SDK to report crashes" off) set(CUSTOM_WEBSITE_URL "" CACHE STRING "Enable custom local webserver to check updates") +if(ENABLE_SENTRY) + set(SENTRY_DIR "" CACHE STRING "Sentry native location") + set(SENTRY_DNS "" CACHE STRING "Sentry DNS URL") +endif() + if(ENABLE_NEWS OR ENABLE_UPDATER) set(REQUIRE_CURL ON) else() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 826072348..24af3321d 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -402,6 +402,11 @@ if(ENABLE_UI) endif() endif() +set(send_crash_files) +if(NOT ENABLE_SENTRY) + set(send_crash_files send_crash.cpp) +endif() + add_library(app-lib active_site_handler.cpp app.cpp @@ -575,7 +580,6 @@ add_library(app-lib res/resources_loader.cpp resource_finder.cpp restore_visible_layers.cpp - send_crash.cpp shade.cpp site.cpp snap_to_grid.cpp @@ -617,6 +621,7 @@ add_library(app-lib util/wrap_point.cpp xml_document.cpp xml_exception.cpp + ${send_crash_files} ${ui_app_files} ${app_platform_files} ${data_recovery_files} @@ -677,3 +682,10 @@ if(ENABLE_STEAM) add_definitions(-DENABLE_STEAM) target_link_libraries(app-lib steam-lib) endif() + +if(ENABLE_SENTRY) + target_compile_definitions(app-lib PUBLIC -DENABLE_SENTRY -DSENTRY_BUILD_STATIC=1) + target_compile_definitions(app-lib PUBLIC -DSENTRY_DNS="${SENTRY_DNS}" -DSENTRY_BUILD_STATIC=1) + add_subdirectory(${SENTRY_DIR} sentry) + target_link_libraries(app-lib sentry) +endif() diff --git a/src/app/app.cpp b/src/app/app.cpp index 814c99ab0..905a2202a 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -418,8 +418,10 @@ void App::run() checkUpdate.launch(); #endif +#if !ENABLE_SENTRY app::SendCrash sendCrash; sendCrash.search(); +#endif // Keep the console alive the whole program execute (just in case // we've to print errors). diff --git a/src/app/send_crash.h b/src/app/send_crash.h index 01c29d5f0..c8b9ce3fc 100644 --- a/src/app/send_crash.h +++ b/src/app/send_crash.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020 Igara Studio S.A. +// Copyright (C) 2020-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -16,6 +16,8 @@ namespace app { +#if !ENABLE_SENTRY + class SendCrash #ifdef ENABLE_UI : public INotificationDelegate @@ -43,6 +45,8 @@ namespace app { std::string m_dumpFilename; }; +#endif // !ENABLE_SENTRY + } // namespace app #endif // APP_SEND_CRASH_H_INCLUDED diff --git a/src/main/main.cpp b/src/main/main.cpp index 1c18a3df7..c8af5c2a1 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -16,10 +16,16 @@ #include "app/send_crash.h" #include "base/exception.h" #include "base/memory.h" -#include "base/memory_dump.h" #include "base/system_console.h" #include "os/error.h" #include "os/system.h" +#include "ver/info.h" + +#if ENABLE_SENTRY + #include "sentry.h" +#else + #include "base/memory_dump.h" +#endif #include <clocale> #include <cstdlib> @@ -59,6 +65,28 @@ namespace { }; #endif +#if ENABLE_SENTRY + class Sentry { + public: + Sentry() { + sentry_options_t* options = sentry_options_new(); + sentry_options_set_dsn(options, SENTRY_DNS); + + std::string release = "aseprite@"; + release += get_app_version(); + sentry_options_set_release(options, release.c_str()); + +#if _DEBUG + sentry_options_set_debug(options, 1); +#endif + sentry_init(options); + } + ~Sentry() { + sentry_close(); + } + }; +#endif + } // Aseprite entry point. (Called from "os" library.) @@ -78,13 +106,18 @@ int app_main(int argc, char* argv[]) #endif try { +#if ENABLE_SENTRY + Sentry sentry; +#else base::MemoryDump memoryDump; +#endif MemLeak memleak; base::SystemConsole systemConsole; app::AppOptions options(argc, const_cast<const char**>(argv)); os::SystemRef system(os::make_system()); app::App app; +#if !ENABLE_SENTRY // Change the memory dump filename to save on disk (.dmp // file). Note: Only useful on Windows. { @@ -92,6 +125,7 @@ int app_main(int argc, char* argv[]) if (!fn.empty()) memoryDump.setFileName(fn); } +#endif const int code = app.initialize(options); From 8b215235c775eb8c2ca8f653dfffbbe47ef68755 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Wed, 22 Sep 2021 18:34:23 -0300 Subject: [PATCH 02/10] Minor fix for app-lib flags in CMakeLists.txt file --- src/app/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 24af3321d..2040a86e7 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -684,8 +684,10 @@ if(ENABLE_STEAM) endif() if(ENABLE_SENTRY) - target_compile_definitions(app-lib PUBLIC -DENABLE_SENTRY -DSENTRY_BUILD_STATIC=1) - target_compile_definitions(app-lib PUBLIC -DSENTRY_DNS="${SENTRY_DNS}" -DSENTRY_BUILD_STATIC=1) + target_compile_definitions(app-lib PUBLIC + -DENABLE_SENTRY + -DSENTRY_BUILD_STATIC=1 + -DSENTRY_DNS="${SENTRY_DNS}") add_subdirectory(${SENTRY_DIR} sentry) target_link_libraries(app-lib sentry) endif() From 024cd73f624486aba389d2b676f67d0169e11d06 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Wed, 22 Sep 2021 19:48:44 -0300 Subject: [PATCH 03/10] Change location for crash data (e.g. %AppData%/Aseprite/crashdb) --- src/app/sentry_wrapper.h | 67 ++++++++++++++++++++++++++++++++++++++++ src/main/main.cpp | 30 +++--------------- 2 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 src/app/sentry_wrapper.h diff --git a/src/app/sentry_wrapper.h b/src/app/sentry_wrapper.h new file mode 100644 index 000000000..3eb9805f0 --- /dev/null +++ b/src/app/sentry_wrapper.h @@ -0,0 +1,67 @@ +// Aseprite +// Copyright (C) 2021 Igara Studio S.A. +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifndef APP_SENTRY_WRAPPER_H +#define APP_SENTRY_WRAPPER_H + +#if !ENABLE_SENTRY + #error ENABLE_SENTRY must be defined +#endif + +#include "app/resource_finder.h" +#include "base/string.h" + +#include "sentry.h" + +namespace app { + +class Sentry { +public: + void init() + { + sentry_options_t* options = sentry_options_new(); + sentry_options_set_dsn(options, SENTRY_DNS); + + std::string release = "aseprite@"; + release += get_app_version(); + sentry_options_set_release(options, release.c_str()); + +#if _DEBUG + sentry_options_set_debug(options, 1); +#endif + + setupDirs(options); + + if (sentry_init(options) == 0) + m_init = true; + } + + ~Sentry() + { + if (m_init) + sentry_close(); + } + +private: + void setupDirs(sentry_options_t* options) + { + ResourceFinder rf; + rf.includeUserDir("crashdb"); + std::string dir = rf.getFirstOrCreateDefault(); + +#if SENTRY_PLATFORM_WINDOWS + sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str()); +#else + sentry_options_set_database_path(options, dir.c_str()); +#endif + } + + bool m_init = false; +}; + +} // namespace app + +#endif // APP_SENTRY_WRAPPER_H diff --git a/src/main/main.cpp b/src/main/main.cpp index c8af5c2a1..e7940e7c2 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -22,7 +22,7 @@ #include "ver/info.h" #if ENABLE_SENTRY - #include "sentry.h" + #include "app/sentry_wrapper.h" #else #include "base/memory_dump.h" #endif @@ -65,28 +65,6 @@ namespace { }; #endif -#if ENABLE_SENTRY - class Sentry { - public: - Sentry() { - sentry_options_t* options = sentry_options_new(); - sentry_options_set_dsn(options, SENTRY_DNS); - - std::string release = "aseprite@"; - release += get_app_version(); - sentry_options_set_release(options, release.c_str()); - -#if _DEBUG - sentry_options_set_debug(options, 1); -#endif - sentry_init(options); - } - ~Sentry() { - sentry_close(); - } - }; -#endif - } // Aseprite entry point. (Called from "os" library.) @@ -107,7 +85,7 @@ int app_main(int argc, char* argv[]) try { #if ENABLE_SENTRY - Sentry sentry; + app::Sentry sentry; #else base::MemoryDump memoryDump; #endif @@ -117,7 +95,9 @@ int app_main(int argc, char* argv[]) os::SystemRef system(os::make_system()); app::App app; -#if !ENABLE_SENTRY +#if ENABLE_SENTRY + sentry.init(); +#else // Change the memory dump filename to save on disk (.dmp // file). Note: Only useful on Windows. { From 6cafec8d0647d28d369235090a99b534593f6d6c Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 12:55:30 -0300 Subject: [PATCH 04/10] Move Sentry class impl to a .cpp file --- src/app/CMakeLists.txt | 4 ++- src/app/sentry_wrapper.cpp | 59 ++++++++++++++++++++++++++++++++++++++ src/app/sentry_wrapper.h | 42 ++------------------------- 3 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 src/app/sentry_wrapper.cpp diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 2040a86e7..1de4c0d21 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -403,7 +403,9 @@ if(ENABLE_UI) endif() set(send_crash_files) -if(NOT ENABLE_SENTRY) +if(ENABLE_SENTRY) + set(send_crash_files sentry_wrapper.cpp) +else() set(send_crash_files send_crash.cpp) endif() diff --git a/src/app/sentry_wrapper.cpp b/src/app/sentry_wrapper.cpp new file mode 100644 index 000000000..06411b10b --- /dev/null +++ b/src/app/sentry_wrapper.cpp @@ -0,0 +1,59 @@ +// Aseprite +// Copyright (C) 2021 Igara Studio S.A. +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app/sentry_wrapper.h" + +#include "app/resource_finder.h" +#include "base/string.h" +#include "ver/info.h" + +#include "sentry.h" + +namespace app { + +void Sentry::init() +{ + sentry_options_t* options = sentry_options_new(); + sentry_options_set_dsn(options, SENTRY_DNS); + + std::string release = "aseprite@"; + release += get_app_version(); + sentry_options_set_release(options, release.c_str()); + +#if _DEBUG + sentry_options_set_debug(options, 1); +#endif + + setupDirs(options); + + if (sentry_init(options) == 0) + m_init = true; +} + +Sentry::~Sentry() +{ + if (m_init) + sentry_close(); +} + +void Sentry::setupDirs(sentry_options_t* options) +{ + ResourceFinder rf; + rf.includeUserDir("crashdb"); + std::string dir = rf.getFirstOrCreateDefault(); + +#if SENTRY_PLATFORM_WINDOWS + sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str()); +#else + sentry_options_set_database_path(options, dir.c_str()); +#endif +} + +} // namespace app diff --git a/src/app/sentry_wrapper.h b/src/app/sentry_wrapper.h index 3eb9805f0..eac861848 100644 --- a/src/app/sentry_wrapper.h +++ b/src/app/sentry_wrapper.h @@ -11,53 +11,17 @@ #error ENABLE_SENTRY must be defined #endif -#include "app/resource_finder.h" -#include "base/string.h" - #include "sentry.h" namespace app { class Sentry { public: - void init() - { - sentry_options_t* options = sentry_options_new(); - sentry_options_set_dsn(options, SENTRY_DNS); - - std::string release = "aseprite@"; - release += get_app_version(); - sentry_options_set_release(options, release.c_str()); - -#if _DEBUG - sentry_options_set_debug(options, 1); -#endif - - setupDirs(options); - - if (sentry_init(options) == 0) - m_init = true; - } - - ~Sentry() - { - if (m_init) - sentry_close(); - } + void init(); + ~Sentry(); private: - void setupDirs(sentry_options_t* options) - { - ResourceFinder rf; - rf.includeUserDir("crashdb"); - std::string dir = rf.getFirstOrCreateDefault(); - -#if SENTRY_PLATFORM_WINDOWS - sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str()); -#else - sentry_options_set_database_path(options, dir.c_str()); -#endif - } + void setupDirs(sentry_options_t* options); bool m_init = false; }; From 0c604ca4baef0658bc5f48fb44be0b081c372aaf Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 15:14:03 -0300 Subject: [PATCH 05/10] Ask for consent to share crash data --- data/extensions/aseprite-theme/theme.xml | 3 ++ data/strings/en.ini | 5 ++++ data/widgets/home_view.xml | 4 ++- data/widgets/options.xml | 3 ++ src/app/commands/cmd_options.cpp | 21 ++++++++++++++ src/app/sentry_wrapper.cpp | 27 +++++++++++++++++ src/app/sentry_wrapper.h | 5 ++++ src/app/ui/home_view.cpp | 37 +++++++++++++++++++++++- src/app/ui/home_view.h | 6 +++- src/app/ui/main_window.cpp | 7 +++++ src/app/ui/main_window.h | 3 ++ 11 files changed, 118 insertions(+), 3 deletions(-) diff --git a/data/extensions/aseprite-theme/theme.xml b/data/extensions/aseprite-theme/theme.xml index e7067f6e9..8e5064c6e 100644 --- a/data/extensions/aseprite-theme/theme.xml +++ b/data/extensions/aseprite-theme/theme.xml @@ -723,6 +723,9 @@ <style id="workspace_tabs"> <background color="workspace" /> </style> + <style id="workspace_check_box" extends="check_box" padding="4"> + <text color="workspace_text" align="left middle" x="14" /> + </style> <style id="tab"> <background part="tab_normal" align="middle" /> <background part="tab_active" align="middle" state="focus" /> diff --git a/data/strings/en.ini b/data/strings/en.ini index b8050c61f..839d3dbc8 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -731,6 +731,11 @@ Recover files from crashed sessions or closed sprite that were not saved in previous sessions. END +share_crashdb = Share crash data with Aseprite developers +share_crashdb_tooltip = <<<END +Give consent to share crash data with Aseprite developers +automatically to fix bugs for all users. +END recent_files = Recent files: recent_folders = Recent folders: news = News: diff --git a/data/widgets/home_view.xml b/data/widgets/home_view.xml index 2074d588c..9389c0ebb 100644 --- a/data/widgets/home_view.xml +++ b/data/widgets/home_view.xml @@ -1,5 +1,5 @@ <!-- Aseprite --> -<!-- Copyright (C) 2019 Igara Studio S.A. --> +<!-- Copyright (C) 2019-2021 Igara Studio S.A. --> <!-- Copyright (C) 2001-2017 David Capello --> <gui> <vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true"> @@ -14,6 +14,8 @@ </vbox> <boxfiller /> <vbox border="4"> + <check id="share_crashdb" text="@.share_crashdb" + tooltip="@.share_crashdb_tooltip" style="workspace_check_box" /> <link id="check_update" text="" style="workspace_link" /> </vbox> </hbox> diff --git a/data/widgets/options.xml b/data/widgets/options.xml index 6a2dc27be..43854fd45 100644 --- a/data/widgets/options.xml +++ b/data/widgets/options.xml @@ -68,6 +68,9 @@ text="@.color_bar_entries_separator" tooltip="@.color_bar_entries_separator" pref="color_bar.entries_separator" /> + <check id="share_crashdb" + text="@home_view.share_crashdb" + tooltip="@home_view.share_crashdb_tooltip" /> <separator horizontal="true" /> <link id="locate_file" text="@.locate_file" /> diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp index 0be02c97b..055707554 100644 --- a/src/app/commands/cmd_options.cpp +++ b/src/app/commands/cmd_options.cpp @@ -27,6 +27,7 @@ #include "app/resource_finder.h" #include "app/tx.h" #include "app/ui/color_button.h" +#include "app/ui/main_window.h" #include "app/ui/pref_widget.h" #include "app/ui/separator_in_view.h" #include "app/ui/skin/skin_theme.h" @@ -42,6 +43,10 @@ #include "render/render.h" #include "ui/ui.h" +#if ENABLE_SENTRY +#include "app/sentry_wrapper.h" +#endif + #include "options.xml.h" namespace app { @@ -490,6 +495,13 @@ public: else locateCrashFolder()->setVisible(false); + // Share crashdb +#if ENABLE_SENTRY + shareCrashdb()->setSelected(Sentry::consentGiven()); +#else + shareCrashdb()->setVisible(false); +#endif + // Undo preferences limitUndo()->Click.connect([this]{ onLimitUndoCheck(); }); limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0); @@ -541,6 +553,15 @@ public: sendMessage(msg); } + // Share crashdb +#if ENABLE_SENTRY + if (shareCrashdb()->isSelected()) + Sentry::giveConsent(); + else + Sentry::revokeConsent(); + App::instance()->mainWindow()->updateConsentCheckbox(); +#endif + // Update language Strings::instance()->setCurrentLanguage( language()->getItemText(language()->getSelectedItemIndex())); diff --git a/src/app/sentry_wrapper.cpp b/src/app/sentry_wrapper.cpp index 06411b10b..3154faa6c 100644 --- a/src/app/sentry_wrapper.cpp +++ b/src/app/sentry_wrapper.cpp @@ -33,6 +33,9 @@ void Sentry::init() setupDirs(options); + // We require the user consent to upload files. + sentry_options_set_require_user_consent(options, 1); + if (sentry_init(options) == 0) m_init = true; } @@ -43,6 +46,30 @@ Sentry::~Sentry() sentry_close(); } +// static +bool Sentry::requireConsent() +{ + return (sentry_user_consent_get() != SENTRY_USER_CONSENT_GIVEN); +} + +// static +bool Sentry::consentGiven() +{ + return (sentry_user_consent_get() == SENTRY_USER_CONSENT_GIVEN); +} + +// static +void Sentry::giveConsent() +{ + sentry_user_consent_give(); +} + +// static +void Sentry::revokeConsent() +{ + sentry_user_consent_revoke(); +} + void Sentry::setupDirs(sentry_options_t* options) { ResourceFinder rf; diff --git a/src/app/sentry_wrapper.h b/src/app/sentry_wrapper.h index eac861848..6a78df3e2 100644 --- a/src/app/sentry_wrapper.h +++ b/src/app/sentry_wrapper.h @@ -20,6 +20,11 @@ public: void init(); ~Sentry(); + static bool requireConsent(); + static bool consentGiven(); + static void giveConsent(); + static void revokeConsent(); + private: void setupDirs(sentry_options_t* options); diff --git a/src/app/ui/home_view.cpp b/src/app/ui/home_view.cpp index f8b8e82cc..69e4fdcf3 100644 --- a/src/app/ui/home_view.cpp +++ b/src/app/ui/home_view.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019-2020 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -38,6 +38,10 @@ #include "app/ui/news_listbox.h" #endif +#if ENABLE_SENTRY +#include "app/sentry_wrapper.h" +#endif + namespace app { using namespace ui; @@ -66,6 +70,22 @@ HomeView::HomeView() #endif checkUpdate()->setVisible(false); + shareCrashdb()->setVisible(false); + +#if ENABLE_SENTRY + // Show this option in home tab only when we require consent for the + // first time and there is crash data available to report + if (Sentry::requireConsent()) { + shareCrashdb()->setVisible(true); + shareCrashdb()->Click.connect( + [this]{ + if (shareCrashdb()->isSelected()) + Sentry::giveConsent(); + else + Sentry::revokeConsent(); + }); + } +#endif InitTheme.connect( [this]{ @@ -101,6 +121,21 @@ void HomeView::dataRecoverySessionsAreReady() #endif } +#if ENABLE_SENTRY +void HomeView::updateConsentCheckbox() +{ + if (Sentry::requireConsent()) { + shareCrashdb()->setVisible(true); + shareCrashdb()->setSelected(false); + } + else if (Sentry::consentGiven()) { + shareCrashdb()->setVisible(false); + shareCrashdb()->setSelected(true); + } + layout(); +} +#endif + std::string HomeView::getTabText() { return Strings::home_view_title(); diff --git a/src/app/ui/home_view.h b/src/app/ui/home_view.h index a6f071a86..e07842b2d 100644 --- a/src/app/ui/home_view.h +++ b/src/app/ui/home_view.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of @@ -46,6 +46,10 @@ namespace app { // function is called. void dataRecoverySessionsAreReady(); +#if ENABLE_SENTRY + void updateConsentCheckbox(); +#endif + // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index 61ba7ba3d..080d161ab 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -223,6 +223,13 @@ CheckUpdateDelegate* MainWindow::getCheckUpdateDelegate() } #endif +#if ENABLE_SENTRY +void MainWindow::updateConsentCheckbox() +{ + getHomeView()->updateConsentCheckbox(); +} +#endif + void MainWindow::showNotification(INotificationDelegate* del) { m_notifications->addLink(del); diff --git a/src/app/ui/main_window.h b/src/app/ui/main_window.h index f6213bf7b..9db1452a0 100644 --- a/src/app/ui/main_window.h +++ b/src/app/ui/main_window.h @@ -66,6 +66,9 @@ namespace app { #ifdef ENABLE_UPDATER CheckUpdateDelegate* getCheckUpdateDelegate(); #endif +#if ENABLE_SENTRY + void updateConsentCheckbox(); +#endif void start(); void showNotification(INotificationDelegate* del); From f6322a137331036dc434d37b8327ba7b2755b02d Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 15:27:09 -0300 Subject: [PATCH 06/10] Don't show "Aseprite is up to date" when there is no new version --- data/strings/en.ini | 1 - src/app/ui/home_view.cpp | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/data/strings/en.ini b/data/strings/en.ini index 839d3dbc8..352f1c7c3 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -740,7 +740,6 @@ recent_files = Recent files: recent_folders = Recent folders: news = News: checking_updates = Checking Updates... -is_up_to_date = {0} is up to date new_version_available = New {0} v{1} available! [import_sprite_sheet] diff --git a/src/app/ui/home_view.cpp b/src/app/ui/home_view.cpp index 69e4fdcf3..7a95f0720 100644 --- a/src/app/ui/home_view.cpp +++ b/src/app/ui/home_view.cpp @@ -211,9 +211,7 @@ void HomeView::onCheckingUpdates() void HomeView::onUpToDate() { - checkUpdate()->setText( - fmt::format(Strings::home_view_is_up_to_date(), get_app_name())); - checkUpdate()->setVisible(true); + checkUpdate()->setVisible(false); layout(); } From 18bebeaba8716103a00e46d933c4c790a116c5fe Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 19:41:40 -0300 Subject: [PATCH 07/10] Minor fix in share crash data tooltip --- data/strings/en.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data/strings/en.ini b/data/strings/en.ini index 352f1c7c3..fbfa87cda 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -733,8 +733,9 @@ previous sessions. END share_crashdb = Share crash data with Aseprite developers share_crashdb_tooltip = <<<END -Give consent to share crash data with Aseprite developers -automatically to fix bugs for all users. +Check to share crash data with Aseprite developers automatically. +This will help to find new bugs and improve the general stability +of Aseprite for all users. END recent_files = Recent files: recent_folders = Recent folders: From 8512ea6f984b73322b5ac5570105f772ea5fd392 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 19:47:21 -0300 Subject: [PATCH 08/10] Add Sentry license --- docs/LICENSES.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/LICENSES.md b/docs/LICENSES.md index 46794370f..6776e8242 100644 --- a/docs/LICENSES.md +++ b/docs/LICENSES.md @@ -951,6 +951,31 @@ possible. They may also add themselves to the list below. */ ``` +# [Sentry](https://sentry.io) + +``` +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + # [skia](https://skia.org) ``` From c6c1393402bccd2b96b3a6401b7c9cd33e93d9a0 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 20:40:02 -0300 Subject: [PATCH 09/10] Show consent to share crash data only when there are something to share --- src/app/sentry_wrapper.cpp | 21 ++++++++++++++++++++- src/app/sentry_wrapper.h | 7 +++++++ src/app/ui/home_view.cpp | 3 ++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/app/sentry_wrapper.cpp b/src/app/sentry_wrapper.cpp index 3154faa6c..0dd6a8cf0 100644 --- a/src/app/sentry_wrapper.cpp +++ b/src/app/sentry_wrapper.cpp @@ -11,6 +11,7 @@ #include "app/sentry_wrapper.h" #include "app/resource_finder.h" +#include "base/fs.h" #include "base/string.h" #include "ver/info.h" @@ -18,6 +19,9 @@ namespace app { +// Directory where Sentry database is saved. +std::string Sentry::m_dbdir; + void Sentry::init() { sentry_options_t* options = sentry_options_new(); @@ -70,17 +74,32 @@ void Sentry::revokeConsent() sentry_user_consent_revoke(); } +// static +bool Sentry::areThereCrashesToReport() +{ + if (m_dbdir.empty()) + return false; + + for (auto f : base::list_files(base::join_path(m_dbdir, "completed"))) { + if (base::get_file_extension(f) == "dmp") + return true; // At least one .dmp file in the completed/ directory + } + return false; +} + void Sentry::setupDirs(sentry_options_t* options) { ResourceFinder rf; rf.includeUserDir("crashdb"); - std::string dir = rf.getFirstOrCreateDefault(); + const std::string dir = rf.getFirstOrCreateDefault(); #if SENTRY_PLATFORM_WINDOWS sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str()); #else sentry_options_set_database_path(options, dir.c_str()); #endif + + m_dbdir = dir; } } // namespace app diff --git a/src/app/sentry_wrapper.h b/src/app/sentry_wrapper.h index 6a78df3e2..97873016c 100644 --- a/src/app/sentry_wrapper.h +++ b/src/app/sentry_wrapper.h @@ -13,6 +13,8 @@ #include "sentry.h" +#include <string> + namespace app { class Sentry { @@ -25,10 +27,15 @@ public: static void giveConsent(); static void revokeConsent(); + // Returns true if there are some crash to report. Used to display + // the "give consent" check box for first time. + static bool areThereCrashesToReport(); + private: void setupDirs(sentry_options_t* options); bool m_init = false; + static std::string m_dbdir; }; } // namespace app diff --git a/src/app/ui/home_view.cpp b/src/app/ui/home_view.cpp index 7a95f0720..482773b8c 100644 --- a/src/app/ui/home_view.cpp +++ b/src/app/ui/home_view.cpp @@ -75,7 +75,8 @@ HomeView::HomeView() #if ENABLE_SENTRY // Show this option in home tab only when we require consent for the // first time and there is crash data available to report - if (Sentry::requireConsent()) { + if (Sentry::requireConsent() && + Sentry::areThereCrashesToReport()) { shareCrashdb()->setVisible(true); shareCrashdb()->Click.connect( [this]{ From f07dc53d8311740c229d99eef09821c05df04ba9 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Thu, 23 Sep 2021 21:06:19 -0300 Subject: [PATCH 10/10] Use our anonymous UUID to identify Sentry users --- src/app/check_update.cpp | 22 ++++++++++++++++++---- src/app/sentry_wrapper.cpp | 8 ++++++++ src/app/sentry_wrapper.h | 2 ++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/app/check_update.cpp b/src/app/check_update.cpp index 2fe2d7714..6490cacf0 100644 --- a/src/app/check_update.cpp +++ b/src/app/check_update.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020 Igara Studio S.A. +// Copyright (C) 2020-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of @@ -21,6 +21,10 @@ #include "base/version.h" #include "ver/info.h" +#if ENABLE_SENTRY + #include "app/sentry_wrapper.h" +#endif + #include <ctime> #include <sstream> @@ -113,6 +117,14 @@ CheckUpdateThreadLauncher::~CheckUpdateThreadLauncher() void CheckUpdateThreadLauncher::launch() { + if (m_uuid.empty()) + m_uuid = m_preferences.updater.uuid(); + +#if ENABLE_SENTRY + if (!m_uuid.empty()) + Sentry::setUserID(m_uuid); +#endif + // In this case we are in the "wait days" period, so we don't check // for updates. if (!m_doCheck) { @@ -120,9 +132,6 @@ void CheckUpdateThreadLauncher::launch() return; } - if (m_uuid.empty()) - m_uuid = m_preferences.updater.uuid(); - m_delegate->onCheckingUpdates(); m_bgJob.reset(new CheckUpdateBackgroundJob); @@ -168,6 +177,11 @@ void CheckUpdateThreadLauncher::onMonitoringTick() if (!m_response.getUuid().empty()) { m_uuid = m_response.getUuid(); m_preferences.updater.uuid(m_uuid); + +#if ENABLE_SENTRY + if (!m_uuid.empty()) + Sentry::setUserID(m_uuid); +#endif } // Set the date of the last "check for updates" and the "WaitDays" parameter. diff --git a/src/app/sentry_wrapper.cpp b/src/app/sentry_wrapper.cpp index 0dd6a8cf0..40e3427d6 100644 --- a/src/app/sentry_wrapper.cpp +++ b/src/app/sentry_wrapper.cpp @@ -50,6 +50,14 @@ Sentry::~Sentry() sentry_close(); } +// static +void Sentry::setUserID(const std::string& uuid) +{ + sentry_value_t user = sentry_value_new_object(); + sentry_value_set_by_key(user, "id", sentry_value_new_string(uuid.c_str())); + sentry_set_user(user); +} + // static bool Sentry::requireConsent() { diff --git a/src/app/sentry_wrapper.h b/src/app/sentry_wrapper.h index 97873016c..c833f9f9d 100644 --- a/src/app/sentry_wrapper.h +++ b/src/app/sentry_wrapper.h @@ -22,6 +22,8 @@ public: void init(); ~Sentry(); + static void setUserID(const std::string& uuid); + static bool requireConsent(); static bool consentGiven(); static void giveConsent();