Normalize line endings in already existing files
This commit is contained in:
+272
-272
@@ -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 ®istryKeyName,
|
||||
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 ®istryKeyName,
|
||||
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 ®istryKeyName,
|
||||
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 ®istryKeyName,
|
||||
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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user