Normalize line endings in already existing files

This commit is contained in:
Leon Richardt
2019-09-08 22:27:57 +02:00
parent 8064f8a49e
commit b06eb9df83
157 changed files with 15175 additions and 15175 deletions
+272 -272
View File
@@ -1,272 +1,272 @@
#include "singletons/NativeMessaging.hpp"
#include "Application.hpp"
#include "providers/twitch/TwitchServer.hpp"
#include "singletons/Paths.hpp"
#include "util/PostToThread.hpp"
#include <QCoreApplication>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
namespace ipc = boost::interprocess;
#ifdef Q_OS_WIN
# include <QProcess>
# include <Windows.h>
# include "singletons/WindowManager.hpp"
# include "widgets/AttachedWindow.hpp"
#endif
#include <iostream>
#define EXTENSION_ID "glknmaideaikkmemifbfkhnomoknepka"
#define MESSAGE_SIZE 1024
namespace chatterino {
void registerNmManifest(Paths &paths, const QString &manifestFilename,
const QString &registryKeyName,
const QJsonDocument &document);
void registerNmHost(Paths &paths)
{
if (paths.isPortable())
return;
auto getBaseDocument = [&] {
QJsonObject obj;
obj.insert("name", "com.chatterino.chatterino");
obj.insert("description", "Browser interaction with chatterino.");
obj.insert("path", QCoreApplication::applicationFilePath());
obj.insert("type", "stdio");
return obj;
};
// chrome
{
QJsonDocument document;
auto obj = getBaseDocument();
QJsonArray allowed_origins_arr = {"chrome-extension://" EXTENSION_ID
"/"};
obj.insert("allowed_origins", allowed_origins_arr);
document.setObject(obj);
registerNmManifest(paths, "/native-messaging-manifest-chrome.json",
"HKCU\\Software\\Google\\Chrome\\NativeMessagingHost"
"s\\com.chatterino.chatterino",
document);
}
// firefox
{
QJsonDocument document;
auto obj = getBaseDocument();
QJsonArray allowed_extensions = {"chatterino_native@chatterino.com"};
obj.insert("allowed_extensions", allowed_extensions);
document.setObject(obj);
registerNmManifest(paths, "/native-messaging-manifest-firefox.json",
"HKCU\\Software\\Mozilla\\NativeMessagingHosts\\com."
"chatterino.chatterino",
document);
}
}
void registerNmManifest(Paths &paths, const QString &manifestFilename,
const QString &registryKeyName,
const QJsonDocument &document)
{
(void)registryKeyName;
// save the manifest
QString manifestPath = paths.miscDirectory + manifestFilename;
QFile file(manifestPath);
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
file.write(document.toJson());
file.flush();
#ifdef Q_OS_WIN
// clang-format off
QProcess::execute("REG ADD \"" + registryKeyName + "\" /ve /t REG_SZ /d \"" + manifestPath + "\" /f");
// clang-format on
#endif
}
std::string &getNmQueueName(Paths &paths)
{
static std::string name =
"chatterino_gui" + paths.applicationFilePathHash.toStdString();
return name;
}
// CLIENT
void NativeMessagingClient::sendMessage(const QByteArray &array)
{
try
{
ipc::message_queue messageQueue(ipc::open_only, "chatterino_gui");
messageQueue.try_send(array.data(), size_t(array.size()), 1);
// messageQueue.timed_send(array.data(), size_t(array.size()), 1,
// boost::posix_time::second_clock::local_time() +
// boost::posix_time::seconds(10));
}
catch (ipc::interprocess_exception &ex)
{
qDebug() << "send to gui process:" << ex.what();
}
}
void NativeMessagingClient::writeToCout(const QByteArray &array)
{
auto *data = array.data();
auto size = uint32_t(array.size());
std::cout.write(reinterpret_cast<char *>(&size), 4);
std::cout.write(data, size);
std::cout.flush();
}
// SERVER
void NativeMessagingServer::start()
{
this->thread.start();
}
void NativeMessagingServer::ReceiverThread::run()
{
ipc::message_queue::remove("chatterino_gui");
ipc::message_queue messageQueue(ipc::open_or_create, "chatterino_gui", 100,
MESSAGE_SIZE);
while (true)
{
try
{
auto buf = std::make_unique<char[]>(MESSAGE_SIZE);
auto retSize = ipc::message_queue::size_type();
auto priority = static_cast<unsigned int>(0);
messageQueue.receive(buf.get(), MESSAGE_SIZE, retSize, priority);
auto document = QJsonDocument::fromJson(
QByteArray::fromRawData(buf.get(), retSize));
this->handleMessage(document.object());
}
catch (ipc::interprocess_exception &ex)
{
qDebug() << "received from gui process:" << ex.what();
}
}
}
void NativeMessagingServer::ReceiverThread::handleMessage(
const QJsonObject &root)
{
auto app = getApp();
QString action = root.value("action").toString();
if (action.isNull())
{
qDebug() << "NM action was null";
return;
}
qDebug() << root;
if (action == "select")
{
QString _type = root.value("type").toString();
bool attach = root.value("attach").toBool();
bool attachFullscreen = root.value("attach_fullscreen").toBool();
QString name = root.value("name").toString();
#ifdef USEWINSDK
AttachedWindow::GetArgs args;
args.winId = root.value("winId").toString();
args.yOffset = root.value("yOffset").toInt(-1);
args.width = root.value("size").toObject().value("width").toInt(-1);
args.height = root.value("size").toObject().value("height").toInt(-1);
args.fullscreen = attachFullscreen;
qDebug() << args.width << args.height << args.winId;
if (_type.isNull() || args.winId.isNull())
{
qDebug() << "NM type, name or winId missing";
attach = false;
attachFullscreen = false;
return;
}
#endif
if (_type == "twitch")
{
postToThread([=] {
if (!name.isEmpty())
{
app->twitch.server->watchingChannel.reset(
app->twitch.server->getOrAddChannel(name));
}
if (attach || attachFullscreen)
{
#ifdef USEWINSDK
// if (args.height != -1) {
auto *window =
AttachedWindow::get(::GetForegroundWindow(), args);
if (!name.isEmpty())
{
window->setChannel(
app->twitch.server->getOrAddChannel(name));
}
// }
// window->show();
#endif
}
});
}
else
{
qDebug() << "NM unknown channel type";
}
}
else if (action == "detach")
{
QString winId = root.value("winId").toString();
if (winId.isNull())
{
qDebug() << "NM winId missing";
return;
}
#ifdef USEWINSDK
postToThread([winId] {
qDebug() << "NW detach";
AttachedWindow::detach(winId);
});
#endif
}
else
{
qDebug() << "NM unknown action " + action;
}
}
} // namespace chatterino
#include "singletons/NativeMessaging.hpp"
#include "Application.hpp"
#include "providers/twitch/TwitchServer.hpp"
#include "singletons/Paths.hpp"
#include "util/PostToThread.hpp"
#include <QCoreApplication>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
namespace ipc = boost::interprocess;
#ifdef Q_OS_WIN
# include <QProcess>
# include <Windows.h>
# include "singletons/WindowManager.hpp"
# include "widgets/AttachedWindow.hpp"
#endif
#include <iostream>
#define EXTENSION_ID "glknmaideaikkmemifbfkhnomoknepka"
#define MESSAGE_SIZE 1024
namespace chatterino {
void registerNmManifest(Paths &paths, const QString &manifestFilename,
const QString &registryKeyName,
const QJsonDocument &document);
void registerNmHost(Paths &paths)
{
if (paths.isPortable())
return;
auto getBaseDocument = [&] {
QJsonObject obj;
obj.insert("name", "com.chatterino.chatterino");
obj.insert("description", "Browser interaction with chatterino.");
obj.insert("path", QCoreApplication::applicationFilePath());
obj.insert("type", "stdio");
return obj;
};
// chrome
{
QJsonDocument document;
auto obj = getBaseDocument();
QJsonArray allowed_origins_arr = {"chrome-extension://" EXTENSION_ID
"/"};
obj.insert("allowed_origins", allowed_origins_arr);
document.setObject(obj);
registerNmManifest(paths, "/native-messaging-manifest-chrome.json",
"HKCU\\Software\\Google\\Chrome\\NativeMessagingHost"
"s\\com.chatterino.chatterino",
document);
}
// firefox
{
QJsonDocument document;
auto obj = getBaseDocument();
QJsonArray allowed_extensions = {"chatterino_native@chatterino.com"};
obj.insert("allowed_extensions", allowed_extensions);
document.setObject(obj);
registerNmManifest(paths, "/native-messaging-manifest-firefox.json",
"HKCU\\Software\\Mozilla\\NativeMessagingHosts\\com."
"chatterino.chatterino",
document);
}
}
void registerNmManifest(Paths &paths, const QString &manifestFilename,
const QString &registryKeyName,
const QJsonDocument &document)
{
(void)registryKeyName;
// save the manifest
QString manifestPath = paths.miscDirectory + manifestFilename;
QFile file(manifestPath);
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
file.write(document.toJson());
file.flush();
#ifdef Q_OS_WIN
// clang-format off
QProcess::execute("REG ADD \"" + registryKeyName + "\" /ve /t REG_SZ /d \"" + manifestPath + "\" /f");
// clang-format on
#endif
}
std::string &getNmQueueName(Paths &paths)
{
static std::string name =
"chatterino_gui" + paths.applicationFilePathHash.toStdString();
return name;
}
// CLIENT
void NativeMessagingClient::sendMessage(const QByteArray &array)
{
try
{
ipc::message_queue messageQueue(ipc::open_only, "chatterino_gui");
messageQueue.try_send(array.data(), size_t(array.size()), 1);
// messageQueue.timed_send(array.data(), size_t(array.size()), 1,
// boost::posix_time::second_clock::local_time() +
// boost::posix_time::seconds(10));
}
catch (ipc::interprocess_exception &ex)
{
qDebug() << "send to gui process:" << ex.what();
}
}
void NativeMessagingClient::writeToCout(const QByteArray &array)
{
auto *data = array.data();
auto size = uint32_t(array.size());
std::cout.write(reinterpret_cast<char *>(&size), 4);
std::cout.write(data, size);
std::cout.flush();
}
// SERVER
void NativeMessagingServer::start()
{
this->thread.start();
}
void NativeMessagingServer::ReceiverThread::run()
{
ipc::message_queue::remove("chatterino_gui");
ipc::message_queue messageQueue(ipc::open_or_create, "chatterino_gui", 100,
MESSAGE_SIZE);
while (true)
{
try
{
auto buf = std::make_unique<char[]>(MESSAGE_SIZE);
auto retSize = ipc::message_queue::size_type();
auto priority = static_cast<unsigned int>(0);
messageQueue.receive(buf.get(), MESSAGE_SIZE, retSize, priority);
auto document = QJsonDocument::fromJson(
QByteArray::fromRawData(buf.get(), retSize));
this->handleMessage(document.object());
}
catch (ipc::interprocess_exception &ex)
{
qDebug() << "received from gui process:" << ex.what();
}
}
}
void NativeMessagingServer::ReceiverThread::handleMessage(
const QJsonObject &root)
{
auto app = getApp();
QString action = root.value("action").toString();
if (action.isNull())
{
qDebug() << "NM action was null";
return;
}
qDebug() << root;
if (action == "select")
{
QString _type = root.value("type").toString();
bool attach = root.value("attach").toBool();
bool attachFullscreen = root.value("attach_fullscreen").toBool();
QString name = root.value("name").toString();
#ifdef USEWINSDK
AttachedWindow::GetArgs args;
args.winId = root.value("winId").toString();
args.yOffset = root.value("yOffset").toInt(-1);
args.width = root.value("size").toObject().value("width").toInt(-1);
args.height = root.value("size").toObject().value("height").toInt(-1);
args.fullscreen = attachFullscreen;
qDebug() << args.width << args.height << args.winId;
if (_type.isNull() || args.winId.isNull())
{
qDebug() << "NM type, name or winId missing";
attach = false;
attachFullscreen = false;
return;
}
#endif
if (_type == "twitch")
{
postToThread([=] {
if (!name.isEmpty())
{
app->twitch.server->watchingChannel.reset(
app->twitch.server->getOrAddChannel(name));
}
if (attach || attachFullscreen)
{
#ifdef USEWINSDK
// if (args.height != -1) {
auto *window =
AttachedWindow::get(::GetForegroundWindow(), args);
if (!name.isEmpty())
{
window->setChannel(
app->twitch.server->getOrAddChannel(name));
}
// }
// window->show();
#endif
}
});
}
else
{
qDebug() << "NM unknown channel type";
}
}
else if (action == "detach")
{
QString winId = root.value("winId").toString();
if (winId.isNull())
{
qDebug() << "NM winId missing";
return;
}
#ifdef USEWINSDK
postToThread([winId] {
qDebug() << "NW detach";
AttachedWindow::detach(winId);
});
#endif
}
else
{
qDebug() << "NM unknown action " + action;
}
}
} // namespace chatterino
+38 -38
View File
@@ -1,38 +1,38 @@
#pragma once
#include <QThread>
namespace chatterino {
class Application;
class Paths;
void registerNmHost(Paths &paths);
std::string &getNmQueueName(Paths &paths);
class NativeMessagingClient final
{
public:
void sendMessage(const QByteArray &array);
void writeToCout(const QByteArray &array);
};
class NativeMessagingServer final
{
public:
void start();
private:
class ReceiverThread : public QThread
{
public:
void run() override;
private:
void handleMessage(const QJsonObject &root);
};
ReceiverThread thread;
};
} // namespace chatterino
#pragma once
#include <QThread>
namespace chatterino {
class Application;
class Paths;
void registerNmHost(Paths &paths);
std::string &getNmQueueName(Paths &paths);
class NativeMessagingClient final
{
public:
void sendMessage(const QByteArray &array);
void writeToCout(const QByteArray &array);
};
class NativeMessagingServer final
{
public:
void start();
private:
class ReceiverThread : public QThread
{
public:
void run() override;
private:
void handleMessage(const QJsonObject &root);
};
ReceiverThread thread;
};
} // namespace chatterino
+315 -315
View File
@@ -1,315 +1,315 @@
#include "Updates.hpp"
#include "Settings.hpp"
#include "common/NetworkRequest.hpp"
#include "common/Outcome.hpp"
#include "common/Version.hpp"
#include "singletons/Paths.hpp"
#include "util/CombinePath.hpp"
#include "util/PostToThread.hpp"
#include <QDebug>
#include <QDesktopServices>
#include <QMessageBox>
#include <QProcess>
namespace chatterino {
namespace {
QString currentBranch()
{
return getSettings()->betaUpdates ? "beta" : "stable";
}
} // namespace
Updates::Updates()
: currentVersion_(CHATTERINO_VERSION)
, updateGuideLink_("https://chatterino.com")
{
qDebug() << "init UpdateManager";
}
Updates &Updates::getInstance()
{
// fourtf: don't add this class to the application class
static Updates instance;
return instance;
}
const QString &Updates::getCurrentVersion() const
{
return currentVersion_;
}
const QString &Updates::getOnlineVersion() const
{
return onlineVersion_;
}
void Updates::installUpdates()
{
if (this->status_ != UpdateAvailable)
{
assert(false);
return;
}
#ifdef Q_OS_MACOS
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"A link will open in your browser. Download and install to update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
#elif defined Q_OS_LINUX
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Automatic updates are currently not available on "
"linux. Please redownload the app to update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateGuideLink_);
#elif defined Q_OS_WIN
if (getPaths()->isPortable())
{
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Chatterino is downloading the update "
"in the background and will run the "
"updater once it is finished.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
NetworkRequest(this->updatePortable_)
.timeout(600000)
.onError([this](int) -> bool {
this->setStatus_(DownloadFailed);
postToThread([] {
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed while trying to download the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
box->raise();
});
return true;
})
.onSuccess([this](auto result) -> Outcome {
QByteArray object = result.getData();
auto filename =
combinePath(getPaths()->miscDirectory, "update.zip");
QFile file(filename);
file.open(QIODevice::Truncate | QIODevice::WriteOnly);
if (file.write(object) == -1)
{
this->setStatus_(WriteFileFailed);
return Failure;
}
file.flush();
file.close();
QProcess::startDetached(
combinePath(QCoreApplication::applicationDirPath(),
"updater.1/ChatterinoUpdater.exe"),
{filename, "restart"});
QApplication::exit(0);
return Success;
})
.execute();
this->setStatus_(Downloading);
}
else
{
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Chatterino is downloading the update "
"in the background and will run the "
"updater once it is finished.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
NetworkRequest(this->updateExe_)
.timeout(600000)
.onError([this](int) -> bool {
this->setStatus_(DownloadFailed);
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to download the update. \n\nTry manually "
"downloading the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
return true;
})
.onSuccess([this](auto result) -> Outcome {
QByteArray object = result.getData();
auto filename =
combinePath(getPaths()->miscDirectory, "Update.exe");
QFile file(filename);
file.open(QIODevice::Truncate | QIODevice::WriteOnly);
if (file.write(object) == -1)
{
this->setStatus_(WriteFileFailed);
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to save the update file. This could be due to "
"window settings or antivirus software.\n\nTry "
"manually "
"downloading the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
return Failure;
}
file.flush();
file.close();
if (QProcess::startDetached(filename))
{
QApplication::exit(0);
}
else
{
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to execute update binary. This could be due to "
"window "
"settings or antivirus software.\n\nTry manually "
"downloading "
"the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
}
return Success;
})
.execute();
this->setStatus_(Downloading);
}
#endif
}
void Updates::checkForUpdates()
{
QString url =
"https://notitia.chatterino.com/version/chatterino/" CHATTERINO_OS "/" +
currentBranch();
NetworkRequest(url)
.timeout(60000)
.onSuccess([this](auto result) -> Outcome {
auto object = result.parseJson();
/// Version available on every platform
QJsonValue version_val = object.value("version");
if (!version_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
#if defined Q_OS_WIN || defined Q_OS_MACOS
/// Windows downloads an installer for the new version
QJsonValue updateExe_val = object.value("updateexe");
if (!updateExe_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
this->updateExe_ = updateExe_val.toString();
/// Windows portable
QJsonValue portable_val = object.value("portable_download");
if (!portable_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
this->updatePortable_ = portable_val.toString();
#elif defined Q_OS_LINUX
QJsonValue updateGuide_val = object.value("updateguide");
if (updateGuide_val.isString())
{
this->updateGuideLink_ = updateGuide_val.toString();
}
#else
return Failure;
#endif
/// Current version
this->onlineVersion_ = version_val.toString();
/// Update available :)
if (this->currentVersion_ != this->onlineVersion_)
{
this->setStatus_(UpdateAvailable);
}
else
{
this->setStatus_(NoUpdateAvailable);
}
return Failure;
})
.execute();
this->setStatus_(Searching);
}
Updates::Status Updates::getStatus() const
{
return this->status_;
}
bool Updates::shouldShowUpdateButton() const
{
switch (this->getStatus())
{
case UpdateAvailable:
case SearchFailed:
case Downloading:
case DownloadFailed:
case WriteFileFailed:
return true;
default:
return false;
}
}
bool Updates::isError() const
{
switch (this->getStatus())
{
case SearchFailed:
case DownloadFailed:
case WriteFileFailed:
return true;
default:
return false;
}
}
void Updates::setStatus_(Status status)
{
if (this->status_ != status)
{
this->status_ = status;
postToThread([this, status] { this->statusUpdated.invoke(status); });
}
}
} // namespace chatterino
#include "Updates.hpp"
#include "Settings.hpp"
#include "common/NetworkRequest.hpp"
#include "common/Outcome.hpp"
#include "common/Version.hpp"
#include "singletons/Paths.hpp"
#include "util/CombinePath.hpp"
#include "util/PostToThread.hpp"
#include <QDebug>
#include <QDesktopServices>
#include <QMessageBox>
#include <QProcess>
namespace chatterino {
namespace {
QString currentBranch()
{
return getSettings()->betaUpdates ? "beta" : "stable";
}
} // namespace
Updates::Updates()
: currentVersion_(CHATTERINO_VERSION)
, updateGuideLink_("https://chatterino.com")
{
qDebug() << "init UpdateManager";
}
Updates &Updates::getInstance()
{
// fourtf: don't add this class to the application class
static Updates instance;
return instance;
}
const QString &Updates::getCurrentVersion() const
{
return currentVersion_;
}
const QString &Updates::getOnlineVersion() const
{
return onlineVersion_;
}
void Updates::installUpdates()
{
if (this->status_ != UpdateAvailable)
{
assert(false);
return;
}
#ifdef Q_OS_MACOS
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"A link will open in your browser. Download and install to update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
#elif defined Q_OS_LINUX
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Automatic updates are currently not available on "
"linux. Please redownload the app to update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateGuideLink_);
#elif defined Q_OS_WIN
if (getPaths()->isPortable())
{
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Chatterino is downloading the update "
"in the background and will run the "
"updater once it is finished.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
NetworkRequest(this->updatePortable_)
.timeout(600000)
.onError([this](int) -> bool {
this->setStatus_(DownloadFailed);
postToThread([] {
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed while trying to download the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
box->raise();
});
return true;
})
.onSuccess([this](auto result) -> Outcome {
QByteArray object = result.getData();
auto filename =
combinePath(getPaths()->miscDirectory, "update.zip");
QFile file(filename);
file.open(QIODevice::Truncate | QIODevice::WriteOnly);
if (file.write(object) == -1)
{
this->setStatus_(WriteFileFailed);
return Failure;
}
file.flush();
file.close();
QProcess::startDetached(
combinePath(QCoreApplication::applicationDirPath(),
"updater.1/ChatterinoUpdater.exe"),
{filename, "restart"});
QApplication::exit(0);
return Success;
})
.execute();
this->setStatus_(Downloading);
}
else
{
QMessageBox *box =
new QMessageBox(QMessageBox::Information, "Chatterino Update",
"Chatterino is downloading the update "
"in the background and will run the "
"updater once it is finished.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->show();
NetworkRequest(this->updateExe_)
.timeout(600000)
.onError([this](int) -> bool {
this->setStatus_(DownloadFailed);
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to download the update. \n\nTry manually "
"downloading the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
return true;
})
.onSuccess([this](auto result) -> Outcome {
QByteArray object = result.getData();
auto filename =
combinePath(getPaths()->miscDirectory, "Update.exe");
QFile file(filename);
file.open(QIODevice::Truncate | QIODevice::WriteOnly);
if (file.write(object) == -1)
{
this->setStatus_(WriteFileFailed);
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to save the update file. This could be due to "
"window settings or antivirus software.\n\nTry "
"manually "
"downloading the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
return Failure;
}
file.flush();
file.close();
if (QProcess::startDetached(filename))
{
QApplication::exit(0);
}
else
{
QMessageBox *box = new QMessageBox(
QMessageBox::Information, "Chatterino Update",
"Failed to execute update binary. This could be due to "
"window "
"settings or antivirus software.\n\nTry manually "
"downloading "
"the update.");
box->setAttribute(Qt::WA_DeleteOnClose);
box->exec();
QDesktopServices::openUrl(this->updateExe_);
}
return Success;
})
.execute();
this->setStatus_(Downloading);
}
#endif
}
void Updates::checkForUpdates()
{
QString url =
"https://notitia.chatterino.com/version/chatterino/" CHATTERINO_OS "/" +
currentBranch();
NetworkRequest(url)
.timeout(60000)
.onSuccess([this](auto result) -> Outcome {
auto object = result.parseJson();
/// Version available on every platform
QJsonValue version_val = object.value("version");
if (!version_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
#if defined Q_OS_WIN || defined Q_OS_MACOS
/// Windows downloads an installer for the new version
QJsonValue updateExe_val = object.value("updateexe");
if (!updateExe_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
this->updateExe_ = updateExe_val.toString();
/// Windows portable
QJsonValue portable_val = object.value("portable_download");
if (!portable_val.isString())
{
this->setStatus_(SearchFailed);
qDebug() << "error updating";
return Failure;
}
this->updatePortable_ = portable_val.toString();
#elif defined Q_OS_LINUX
QJsonValue updateGuide_val = object.value("updateguide");
if (updateGuide_val.isString())
{
this->updateGuideLink_ = updateGuide_val.toString();
}
#else
return Failure;
#endif
/// Current version
this->onlineVersion_ = version_val.toString();
/// Update available :)
if (this->currentVersion_ != this->onlineVersion_)
{
this->setStatus_(UpdateAvailable);
}
else
{
this->setStatus_(NoUpdateAvailable);
}
return Failure;
})
.execute();
this->setStatus_(Searching);
}
Updates::Status Updates::getStatus() const
{
return this->status_;
}
bool Updates::shouldShowUpdateButton() const
{
switch (this->getStatus())
{
case UpdateAvailable:
case SearchFailed:
case Downloading:
case DownloadFailed:
case WriteFileFailed:
return true;
default:
return false;
}
}
bool Updates::isError() const
{
switch (this->getStatus())
{
case SearchFailed:
case DownloadFailed:
case WriteFileFailed:
return true;
default:
return false;
}
}
void Updates::setStatus_(Status status)
{
if (this->status_ != status)
{
this->status_ = status;
postToThread([this, status] { this->statusUpdated.invoke(status); });
}
}
} // namespace chatterino
+50 -50
View File
@@ -1,50 +1,50 @@
#pragma once
#include <QString>
#include <pajlada/signals/signal.hpp>
namespace chatterino {
class Updates
{
Updates();
public:
enum Status {
None,
Searching,
UpdateAvailable,
NoUpdateAvailable,
SearchFailed,
Downloading,
DownloadFailed,
WriteFileFailed,
};
// fourtf: don't add this class to the application class
static Updates &getInstance();
void checkForUpdates();
const QString &getCurrentVersion() const;
const QString &getOnlineVersion() const;
void installUpdates();
Status getStatus() const;
bool shouldShowUpdateButton() const;
bool isError() const;
pajlada::Signals::Signal<Status> statusUpdated;
private:
QString currentVersion_;
QString onlineVersion_;
Status status_ = None;
QString updateExe_;
QString updatePortable_;
QString updateGuideLink_;
void setStatus_(Status status);
};
} // namespace chatterino
#pragma once
#include <QString>
#include <pajlada/signals/signal.hpp>
namespace chatterino {
class Updates
{
Updates();
public:
enum Status {
None,
Searching,
UpdateAvailable,
NoUpdateAvailable,
SearchFailed,
Downloading,
DownloadFailed,
WriteFileFailed,
};
// fourtf: don't add this class to the application class
static Updates &getInstance();
void checkForUpdates();
const QString &getCurrentVersion() const;
const QString &getOnlineVersion() const;
void installUpdates();
Status getStatus() const;
bool shouldShowUpdateButton() const;
bool isError() const;
pajlada::Signals::Signal<Status> statusUpdated;
private:
QString currentVersion_;
QString onlineVersion_;
Status status_ = None;
QString updateExe_;
QString updatePortable_;
QString updateGuideLink_;
void setStatus_(Status status);
};
} // namespace chatterino