Skip to content

Commit

Permalink
* Add initial work on update checker.
Browse files Browse the repository at this point in the history
  • Loading branch information
iProgramMC committed May 12, 2024
1 parent ab5225a commit 976f775
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/discord/Frontend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ class Frontend
virtual void OnAttachmentFailed(bool bIsProfilePicture, const std::string& additData) = 0;
virtual void OnRequestDone(NetRequest* pRequest) = 0;
virtual void OnLoadedPins(Snowflake channel, const std::string& data) = 0;
virtual void OnUpdateAvailable(const std::string& url, const std::string& version) = 0;
virtual void OnFailedToSendMessage(Snowflake channel, Snowflake message) = 0;
virtual void OnFailedToUploadFile(const std::string& file, int error) = 0;
virtual void OnFailedToCheckForUpdates(int result, const std::string& response) = 0;

// Error messages
virtual void OnGenericError(const std::string& message) = 0;
Expand Down
16 changes: 16 additions & 0 deletions src/discord/LocalSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ bool LocalSettings::Load()
if (m_height < 600)
m_height = 600;
}

if (j.contains("CheckUpdates"))
m_bCheckUpdates = j["CheckUpdates"];
else
m_bAskToCheckUpdates = true;

if (j.contains("RemindUpdateCheckOn"))
m_remindUpdatesOn = (time_t) (long long) j["RemindUpdateCheckOn"];

return true;
}
Expand All @@ -103,6 +111,8 @@ bool LocalSettings::Save()
j["ReplyMentionDefault"] = m_bReplyMentionDefault;
j["StartMaximized"] = m_bStartMaximized;
j["SaveWindowSize"] = m_bSaveWindowSize;
j["CheckUpdates"] = m_bCheckUpdates;
j["RemindUpdateCheckOn"] = (long long)(m_remindUpdatesOn);
if (m_bSaveWindowSize) {
j["WindowWidth"] = m_width;
j["WindowHeight"] = m_height;
Expand All @@ -128,3 +138,9 @@ bool LocalSettings::CheckTrustedDomain(const std::string& url)
SplitURL(url, domain, resource);
return m_trustedDomains.find(domain) != m_trustedDomains.end();
}

void LocalSettings::StopUpdateCheckTemporarily()
{
// TODO:
// m_remindUpdatesOn = time(NULL) + time_t(72LL * 60 * 60);
}
18 changes: 18 additions & 0 deletions src/discord/LocalSettings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <string>
#include <set>
#include <ctime>

enum eMessageStyle
{
Expand Down Expand Up @@ -71,6 +72,20 @@ class LocalSettings
void SetDiscordCDN(const std::string& str) {
m_discordCdn = str;
}
void SetCheckUpdates(bool b) {
m_bCheckUpdates = true;
m_bAskToCheckUpdates = false;
}
bool CheckUpdates() const {
if (!m_bCheckUpdates)
return false;

return time(NULL) >= m_remindUpdatesOn;
}
bool AskToCheckUpdates() const {
return m_bAskToCheckUpdates;
}
void StopUpdateCheckTemporarily();

private:
std::string m_token;
Expand All @@ -82,6 +97,9 @@ class LocalSettings
bool m_bSaveWindowSize = false;
bool m_bStartMaximized = false;
bool m_bIsFirstStart = false;
bool m_bCheckUpdates = false;
bool m_bAskToCheckUpdates = false;
time_t m_remindUpdatesOn = 0;
int m_width = 1000;
int m_height = 700;
};
Expand Down
91 changes: 91 additions & 0 deletions src/discord/UpdateChecker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include "UpdateChecker.hpp"
#include "Util.hpp"
#include <nlohmann/json.h>

std::string UpdateChecker::GetUpdateAPIURL()
{
return "https://api.github.com/repos/DiscordMessenger/dm/releases/latest";
}

void UpdateChecker::StartCheckingForUpdates()
{
GetHTTPClient()->PerformRequest(true, NetRequest::GET, GetUpdateAPIURL(), 0, 0, "", "", "", OnRequestDone);
}

void UpdateChecker::DownloadUpdate(const std::string& url)
{
DbgPrintF("Downloading update: %s", url.c_str());
}

#ifdef _MSC_VER
#define IS_MINGW false
#else
#define IS_MINGW true
#endif

void UpdateChecker::OnRequestDone(NetRequest* pReq)
{
if (pReq->result != HTTP_OK) {
GetFrontend()->OnFailedToCheckForUpdates(pReq->result, pReq->response);
return;
}

nlohmann::json& j = nlohmann::json::parse(pReq->response);

// This is specific to the GitHub API. If moving away from GitHub, redo this:
std::string tagName = j["tag_name"];
std::string downloadUrl = "";

const bool isMinGW = IS_MINGW;

//
// GUIDE TO MAKING A RELEASE: (if iProgramInCpp ever forgets how to, or you wanna make a fork)
//
// 1. Give it a tag that is the exact version of the app. ("v1.01" for V1.01, for instance)
// 2. Upload two files: DiscordMessenger-V$.$$-MinGW.zip and DiscordMessenger-V$.$$-MSVC.zip
// (note, they are case sensitive!)
// 3. Publish the release
// 4. Enjoy!
//

for (auto& asset : j["assets"])
{
std::string url = asset["browser_download_url"];

bool isTheOne;
if (isMinGW)
isTheOne = strstr(url.c_str(), "MinGW") != nullptr;
else
isTheOne = strstr(url.c_str(), "MSVC") != nullptr;

if (isTheOne) {
downloadUrl = url;
break;
}
}

if (tagName.empty()) {
GetFrontend()->OnFailedToCheckForUpdates(-2, "Latest release's tag name is empty.");
return;
}

if (downloadUrl.empty()) {
GetFrontend()->OnFailedToCheckForUpdates(-2, std::string("Latest release doesn't have a valid ") + (isMinGW ? "MinGW" : "MSVC") + " download.");
return;
}

if (tagName[0] != 'v') {
GetFrontend()->OnFailedToCheckForUpdates(-3, "Latest release's tag name is invalid.");
return;
}

tagName[0] = 'V';

// Ok, now parse it as a float
float f = std::strtof(tagName.c_str() + 1, NULL);

if (f > GetAppVersion()) {
// Ta-da! We have found an update.
GetFrontend()->OnUpdateAvailable(downloadUrl, tagName);
}
}
15 changes: 15 additions & 0 deletions src/discord/UpdateChecker.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Frontend.hpp"
#include "HTTPClient.hpp"

class UpdateChecker
{
public:
static std::string GetUpdateAPIURL();
static void StartCheckingForUpdates();
static void DownloadUpdate(const std::string& url);

private:
static void OnRequestDone(NetRequest*);
};
7 changes: 5 additions & 2 deletions src/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@
#define IDS_URL_EMPTY 692
#define IDS_CONFIRM_SET_URLS 693
#define IDS_CONFIRM_OFFICIAL_URLS 694
#define IDS_CHECK_UPDATES 695
#define IDS_NEW_VERSION_AVAILABLE 696
#define IDS_FAILED_UPDATE_CHECK 697
#define IDS_FAILED_TO_UPLOAD 698
#define IDC_OPTIONS_TABS 801
#define IDC_MY_ACCOUNT_BOX 802
#define IDC_MY_ACCOUNT_NAME 803
Expand Down Expand Up @@ -267,7 +271,6 @@
#define IDC_REVERTTODEFAULT 866
#define IDC_UPDATE 867
#define IDC_ICON_WARN_CONNECT 868
#define IDC_ICON_WARN_CONNECT2 869
#define IDC_ICON_WARN_WEBSOCKETSTUFF 869
#define ID_FILE_PREFERENCES 1001
#define ID_FILE_STOPALLSPEECH 1002
Expand Down Expand Up @@ -345,7 +348,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 70
#define _APS_NEXT_RESOURCE_VALUE 71
#define _APS_NEXT_COMMAND_VALUE 1069
#define _APS_NEXT_CONTROL_VALUE 869
#define _APS_NEXT_SYMED_VALUE 40000
Expand Down
5 changes: 5 additions & 0 deletions src/resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,11 @@ BEGIN
IDS_CONFIRM_SET_URLS "You are about to be logged out. Are you sure you want to override the backend URLs, routing traffic through a service potentially other than Discord?"
IDS_CONFIRM_OFFICIAL_URLS
"You are about to be logged out. Are you sure you want to revert to the official Discord backend URLs?"
IDS_CHECK_UPDATES "Do you want to check for updates every time Discord Messenger starts up?\n\nThis will use the official unauthenticated GitHub API to fetch the latest release of Discord Messenger.\n\nYour setting will be saved and you will not be asked again, but you can change this setting in the Preferences in the File menu."
IDS_NEW_VERSION_AVAILABLE
"Discord Messenger has had a new update!\n\nYour version: %s\nLatest version: %s\n\nWould you like to download the new version?\n\nNote: No web browser window will be opened, the app itself will download the files into a location you choose.\nNote: You won't be bugged again for 3 days."
IDS_FAILED_UPDATE_CHECK "Failed to check for updates! (error %d, message '%s').\n\nTrying again when the app restarts."
IDS_FAILED_TO_UPLOAD "Error! Can't upload file %s, got error %d."
END

#endif // English (United States) resources
Expand Down
33 changes: 31 additions & 2 deletions src/windows/Frontend_Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "ProfilePopout.hpp"
#include "QRCodeDialog.hpp"
#include "PinnedMessageViewer.hpp"
#include "../discord/UpdateChecker.hpp"
#include "../discord/LocalSettings.hpp"

const std::string g_UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.284 Chrome/120.0.6099.283 Electron/28.2.3 Safari/537.36";

Expand Down Expand Up @@ -122,6 +124,21 @@ void Frontend_Win32::OnLoadedPins(Snowflake channel, const std::string& data)
PmvOnLoadedPins(channel, data);
}

void Frontend_Win32::OnUpdateAvailable(const std::string& url, const std::string& version)
{
TCHAR buff[2048];
LPTSTR tstr1 = ConvertCppStringToTString(GetAppVersionString());
LPTSTR tstr2 = ConvertCppStringToTString(version);
WAsnprintf(buff, _countof(buff), TmGetTString(IDS_NEW_VERSION_AVAILABLE), tstr1, tstr2);
free(tstr1);
free(tstr2);

if (MessageBox(g_Hwnd, buff, TmGetTString(IDS_PROGRAM_NAME), MB_ICONINFORMATION | MB_YESNO) == IDYES)
UpdateChecker::DownloadUpdate(url);

GetLocalSettings()->StopUpdateCheckTemporarily();
}

void Frontend_Win32::OnFailedToSendMessage(Snowflake channel, Snowflake message)
{
FailedMessageParams parms;
Expand All @@ -133,8 +150,20 @@ void Frontend_Win32::OnFailedToSendMessage(Snowflake channel, Snowflake message)
void Frontend_Win32::OnFailedToUploadFile(const std::string& file, int error)
{
TCHAR buff[4096];
WAsnprintf(buff, _countof(buff), TEXT("Cannot upload file " ASCIIZ_STR_FMT ", error %d"), file.c_str(), error);
MessageBox(g_Hwnd, buff, TmGetTString(IDS_PROGRAM_NAME), MB_OK);
LPTSTR tstr = ConvertCppStringToTString(file);
WAsnprintf(buff, _countof(buff), TmGetTString(IDS_FAILED_TO_UPLOAD), tstr, error);
free(tstr);
MessageBox(g_Hwnd, buff, TmGetTString(IDS_PROGRAM_NAME), MB_ICONERROR | MB_OK);
}

void Frontend_Win32::OnFailedToCheckForUpdates(int result, const std::string& response)
{
TCHAR buff[2048];
LPTSTR tstr = ConvertCppStringToTString(response);
WAsnprintf(buff, _countof(buff), TmGetTString(IDS_FAILED_UPDATE_CHECK), result, tstr);
free(tstr);

MessageBox(g_Hwnd, buff, TmGetTString(IDS_PROGRAM_NAME), MB_ICONERROR | MB_OK);
}

void Frontend_Win32::OnAttachmentDownloaded(bool bIsProfilePicture, const uint8_t* pData, size_t nSize, const std::string& additData)
Expand Down
2 changes: 2 additions & 0 deletions src/windows/Frontend_Win32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class Frontend_Win32 : public Frontend
void OnStartTyping(Snowflake userID, Snowflake guildID, Snowflake channelID, time_t startTime) override;
void OnRequestDone(NetRequest* pRequest) override;
void OnLoadedPins(Snowflake channel, const std::string& data) override;
void OnUpdateAvailable(const std::string& url, const std::string& version) override;
void OnFailedToSendMessage(Snowflake channel, Snowflake message) override;
void OnFailedToUploadFile(const std::string& file, int error) override;
void OnFailedToCheckForUpdates(int result, const std::string& response) override;
void OnGenericError(const std::string& message) override;
void OnJsonException(const std::string& message) override;
void OnCantViewChannel(const std::string& channelName) override;
Expand Down
1 change: 1 addition & 0 deletions src/windows/LoadingMessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ LRESULT CALLBACK LoadingMessage::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP
break;
}
case WM_DESTROY: {
pThis->m_hwnd = NULL;
if (pThis->m_timer_id)
KillTimer(hWnd, pThis->m_timer_id);
pThis->m_timer_id = 0;
Expand Down
20 changes: 19 additions & 1 deletion src/windows/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "Frontend_Win32.hpp"
#include "../discord/LocalSettings.hpp"
#include "../discord/WebsocketClient.hpp"
#include "../discord/UpdateChecker.hpp"

#include <system_error>

Expand Down Expand Up @@ -802,7 +803,7 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (GetLocalSettings()->IsFirstStart())
{
MessageBox(
NULL,
hWnd,
TmGetTString(IDS_WELCOME_MSG),
TmGetTString(IDS_PROGRAM_NAME),
MB_ICONINFORMATION | MB_OK
Expand All @@ -815,6 +816,23 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
}

if (GetLocalSettings()->AskToCheckUpdates())
{
bool check = MessageBox(
hWnd,
TmGetTString(IDS_CHECK_UPDATES),
TmGetTString(IDS_PROGRAM_NAME),
MB_ICONQUESTION | MB_YESNO
) == IDYES;

GetLocalSettings()->SetCheckUpdates(check);
}

if (GetLocalSettings()->CheckUpdates())
{
UpdateChecker::StartCheckingForUpdates();
}

if (g_SendIcon) DeleteObject(g_SendIcon);
if (g_JumpIcon) DeleteObject(g_JumpIcon);
if (g_CancelIcon) DeleteObject(g_CancelIcon);
Expand Down
2 changes: 2 additions & 0 deletions vs/DiscordMessenger.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@
<ClInclude Include="..\src\discord\SettingsManager.hpp" />
<ClInclude Include="..\src\discord\Snowflake.hpp" />
<ClInclude Include="..\src\discord\TextInterface.hpp" />
<ClInclude Include="..\src\discord\UpdateChecker.hpp" />
<ClInclude Include="..\src\discord\Util.hpp" />
<ClInclude Include="..\src\discord\WebsocketClient.hpp" />
<ClInclude Include="..\src\resource.h" />
Expand Down Expand Up @@ -320,6 +321,7 @@
<ClCompile Include="..\src\discord\MessageCache.cpp" />
<ClCompile Include="..\src\discord\ProfileCache.cpp" />
<ClCompile Include="..\src\discord\SettingsManager.cpp" />
<ClCompile Include="..\src\discord\UpdateChecker.cpp" />
<ClCompile Include="..\src\discord\Util.cpp" />
<ClCompile Include="..\src\discord\WebsocketClient.cpp" />
<ClCompile Include="..\src\windows\AboutDialog.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions vs/DiscordMessenger.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@
<ClInclude Include="..\src\windows\QuickSwitcher.hpp">
<Filter>Header Files\Windows</Filter>
</ClInclude>
<ClInclude Include="..\src\discord\UpdateChecker.hpp">
<Filter>Header Files\Windows</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\windows\ProfileView.cpp">
Expand Down Expand Up @@ -634,5 +637,8 @@
<ClCompile Include="..\src\discord\DiscordAPI.cpp">
<Filter>Source Files\Discord</Filter>
</ClCompile>
<ClCompile Include="..\src\discord\UpdateChecker.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
</ItemGroup>
</Project>

0 comments on commit 976f775

Please sign in to comment.