diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
| commit | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (patch) | |
| tree | 8a984fa143c38fccad461a77792d6864f3e82cd3 /meshmc/libraries/ganalytics | |
| parent | 934382c8a1ce738589dee9ee0f14e1cec812770e (diff) | |
| parent | fad6a1066616b69d7f5fef01178efdf014c59537 (diff) | |
| download | Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.tar.gz Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.zip | |
Add 'meshmc/' from commit 'fad6a1066616b69d7f5fef01178efdf014c59537'
git-subtree-dir: meshmc
git-subtree-mainline: 934382c8a1ce738589dee9ee0f14e1cec812770e
git-subtree-split: fad6a1066616b69d7f5fef01178efdf014c59537
Diffstat (limited to 'meshmc/libraries/ganalytics')
| -rw-r--r-- | meshmc/libraries/ganalytics/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/LICENSE.txt | 24 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/README.md | 34 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/include/ganalytics.h | 92 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/src/ganalytics.cpp | 262 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/src/ganalytics_worker.cpp | 267 | ||||
| -rw-r--r-- | meshmc/libraries/ganalytics/src/ganalytics_worker.h | 84 |
7 files changed, 780 insertions, 0 deletions
diff --git a/meshmc/libraries/ganalytics/CMakeLists.txt b/meshmc/libraries/ganalytics/CMakeLists.txt new file mode 100644 index 0000000000..a5c3125ddd --- /dev/null +++ b/meshmc/libraries/ganalytics/CMakeLists.txt @@ -0,0 +1,17 @@ +project(ganalytics) + +find_package(Qt6Core) +find_package(Qt6Gui) +find_package(Qt6Network) + +set(ganalytics_SOURCES +src/ganalytics.cpp +src/ganalytics_worker.cpp +src/ganalytics_worker.h +include/ganalytics.h +) + +add_library(ganalytics STATIC ${ganalytics_SOURCES}) +target_link_libraries(ganalytics Qt6::Core Qt6::Gui Qt6::Network) +target_include_directories(ganalytics PUBLIC include) +target_link_libraries(ganalytics systeminfo) diff --git a/meshmc/libraries/ganalytics/LICENSE.txt b/meshmc/libraries/ganalytics/LICENSE.txt new file mode 100644 index 0000000000..795497ffe6 --- /dev/null +++ b/meshmc/libraries/ganalytics/LICENSE.txt @@ -0,0 +1,24 @@ +Copyright (c) 2014-2015, University of Applied Sciences Augsburg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the University of Applied Sciences Augsburg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +OODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +UT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/meshmc/libraries/ganalytics/README.md b/meshmc/libraries/ganalytics/README.md new file mode 100644 index 0000000000..d7e1e33c7d --- /dev/null +++ b/meshmc/libraries/ganalytics/README.md @@ -0,0 +1,34 @@ +qt-google-analytics +================ + +Qt5 classes for providing google analytics usage in a Qt/QML application. + +## Building +Include ```qt-google-analytics.pri``` in your .pro file. + +## Using +Please make sure you have set your application information using ```QApplication::setApplicationName``` and ```QApplication::setApplicationVersion```. + +### In C++: +``` +GAnalytics tracker("UA-my-id"); +tracker.sendScreenView("Main Screen"); +``` + +### In QtQuick: +Register the class on the C++ side using ```qmlRegisterType<GAnalytics>("analytics", 0, 1, "Tracker");``` +``` +Tracker { + id: tracker + trackingID: "UA-my-id" +} + +[...] +tracker.sendScreenView("Main Screen") +``` + +There is also an example application in the examples folder. + +## License +Copyright (c) 2014-2016, University of Applied Sciences Augsburg. +All rights reserved. Distributed under the terms and conditions of the BSD License. See separate LICENSE.txt. diff --git a/meshmc/libraries/ganalytics/include/ganalytics.h b/meshmc/libraries/ganalytics/include/ganalytics.h new file mode 100644 index 0000000000..8c6550a922 --- /dev/null +++ b/meshmc/libraries/ganalytics/include/ganalytics.h @@ -0,0 +1,92 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QObject> +#include <QVariantMap> + +class QNetworkAccessManager; +class GAnalyticsWorker; + +class GAnalytics : public QObject +{ + Q_OBJECT + Q_ENUMS(LogLevel) + + public: + explicit GAnalytics(const QString& trackingID, const QString& clientID, + const int version, QObject* parent = 0); + ~GAnalytics(); + + public: + enum LogLevel { Debug, Info, Error }; + + int version(); + + void setLogLevel(LogLevel logLevel); + LogLevel logLevel() const; + + // Getter and Setters + void setViewportSize(const QString& viewportSize); + QString viewportSize() const; + + void setLanguage(const QString& language); + QString language() const; + + void setAnonymizeIPs(bool anonymize); + bool anonymizeIPs(); + + void setSendInterval(int milliseconds); + int sendInterval() const; + + void enable(bool state = true); + bool isEnabled(); + + /// Get or set the network access manager. If none is set, the class creates + /// its own on the first request + void setNetworkAccessManager(QNetworkAccessManager* networkAccessManager); + QNetworkAccessManager* networkAccessManager() const; + + public slots: + void sendScreenView(const QString& screenName, + const QVariantMap& customValues = QVariantMap()); + void sendEvent(const QString& category, const QString& action, + const QString& label = QString(), + const QVariant& value = QVariant(), + const QVariantMap& customValues = QVariantMap()); + void sendException(const QString& exceptionDescription, + bool exceptionFatal = true, + const QVariantMap& customValues = QVariantMap()); + void startSession(); + void endSession(); + + private: + GAnalyticsWorker* d; + + friend QDataStream& operator<<(QDataStream& outStream, + const GAnalytics& analytics); + friend QDataStream& operator>>(QDataStream& inStream, + GAnalytics& analytics); +}; + +QDataStream& operator<<(QDataStream& outStream, const GAnalytics& analytics); +QDataStream& operator>>(QDataStream& inStream, GAnalytics& analytics); diff --git a/meshmc/libraries/ganalytics/src/ganalytics.cpp b/meshmc/libraries/ganalytics/src/ganalytics.cpp new file mode 100644 index 0000000000..fe4b7b77b0 --- /dev/null +++ b/meshmc/libraries/ganalytics/src/ganalytics.cpp @@ -0,0 +1,262 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "ganalytics.h" +#include "ganalytics_worker.h" +#include "sys.h" + +#include <QDataStream> +#include <QDebug> +#include <QLocale> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QQueue> +#include <QSettings> +#include <QTimer> +#include <QUrlQuery> +#include <QUuid> + +GAnalytics::GAnalytics(const QString& trackingID, const QString& clientID, + const int version, QObject* parent) + : QObject(parent) +{ + d = new GAnalyticsWorker(this); + d->m_trackingID = trackingID; + d->m_clientID = clientID; + d->m_version = version; +} + +/** + * Destructor of class GAnalytics. + */ +GAnalytics::~GAnalytics() +{ + delete d; +} + +void GAnalytics::setLogLevel(GAnalytics::LogLevel logLevel) +{ + d->m_logLevel = logLevel; +} + +GAnalytics::LogLevel GAnalytics::logLevel() const +{ + return d->m_logLevel; +} + +// SETTER and GETTER +void GAnalytics::setViewportSize(const QString& viewportSize) +{ + d->m_viewportSize = viewportSize; +} + +QString GAnalytics::viewportSize() const +{ + return d->m_viewportSize; +} + +void GAnalytics::setLanguage(const QString& language) +{ + d->m_language = language; +} + +QString GAnalytics::language() const +{ + return d->m_language; +} + +void GAnalytics::setAnonymizeIPs(bool anonymize) +{ + d->m_anonymizeIPs = anonymize; +} + +bool GAnalytics::anonymizeIPs() +{ + return d->m_anonymizeIPs; +} + +void GAnalytics::setSendInterval(int milliseconds) +{ + d->m_timer.setInterval(milliseconds); +} + +int GAnalytics::sendInterval() const +{ + return (d->m_timer.interval()); +} + +bool GAnalytics::isEnabled() +{ + return d->m_isEnabled; +} + +void GAnalytics::enable(bool state) +{ + d->enable(state); +} + +int GAnalytics::version() +{ + return d->m_version; +} + +void GAnalytics::setNetworkAccessManager( + QNetworkAccessManager* networkAccessManager) +{ + if (d->networkManager != networkAccessManager) { + // Delete the old network manager if it was our child + if (d->networkManager && d->networkManager->parent() == this) { + d->networkManager->deleteLater(); + } + + d->networkManager = networkAccessManager; + } +} + +QNetworkAccessManager* GAnalytics::networkAccessManager() const +{ + return d->networkManager; +} + +static void appendCustomValues(QUrlQuery& query, + const QVariantMap& customValues) +{ + for (QVariantMap::const_iterator iter = customValues.begin(); + iter != customValues.end(); ++iter) { + query.addQueryItem(iter.key(), iter.value().toString()); + } +} + +/** + * Sent screen view is called when the user changed the applications view. + * These action of the user should be noticed and reported. Therefore + * a QUrlQuery is build in this method. It holts all the parameter for + * a http POST. The UrlQuery will be stored in a message Queue. + */ +void GAnalytics::sendScreenView(const QString& screenName, + const QVariantMap& customValues) +{ + d->logMessage(Info, QString("ScreenView: %1").arg(screenName)); + + QUrlQuery query = d->buildStandardPostQuery("screenview"); + query.addQueryItem("cd", screenName); + query.addQueryItem("an", d->m_appName); + query.addQueryItem("av", d->m_appVersion); + appendCustomValues(query, customValues); + + d->enqueQueryWithCurrentTime(query); +} + +/** + * This method is called whenever a button was pressed in the application. + * A query for a POST message will be created to report this event. The + * created query will be stored in a message queue. + */ +void GAnalytics::sendEvent(const QString& category, const QString& action, + const QString& label, const QVariant& value, + const QVariantMap& customValues) +{ + QUrlQuery query = d->buildStandardPostQuery("event"); + query.addQueryItem("an", d->m_appName); + query.addQueryItem("av", d->m_appVersion); + query.addQueryItem("ec", category); + query.addQueryItem("ea", action); + if (!label.isEmpty()) + query.addQueryItem("el", label); + if (value.isValid()) + query.addQueryItem("ev", value.toString()); + + appendCustomValues(query, customValues); + + d->enqueQueryWithCurrentTime(query); +} + +/** + * Method is called after an exception was raised. It builds a + * query for a POST message. These query will be stored in a + * message queue. + */ +void GAnalytics::sendException(const QString& exceptionDescription, + bool exceptionFatal, + const QVariantMap& customValues) +{ + QUrlQuery query = d->buildStandardPostQuery("exception"); + query.addQueryItem("an", d->m_appName); + query.addQueryItem("av", d->m_appVersion); + + query.addQueryItem("exd", exceptionDescription); + + if (exceptionFatal) { + query.addQueryItem("exf", "1"); + } else { + query.addQueryItem("exf", "0"); + } + appendCustomValues(query, customValues); + + d->enqueQueryWithCurrentTime(query); +} + +/** + * Session starts. This event will be sent by a POST message. + * Query is setup in this method and stored in the message + * queue. + */ +void GAnalytics::startSession() +{ + QVariantMap customValues; + customValues.insert("sc", "start"); + sendEvent("Session", "Start", QString(), QVariant(), customValues); +} + +/** + * Session ends. This event will be sent by a POST message. + * Query is setup in this method and stored in the message + * queue. + */ +void GAnalytics::endSession() +{ + QVariantMap customValues; + customValues.insert("sc", "end"); + sendEvent("Session", "End", QString(), QVariant(), customValues); +} + +/** + * Qut stream to persist class GAnalytics. + */ +QDataStream& operator<<(QDataStream& outStream, const GAnalytics& analytics) +{ + outStream << analytics.d->persistMessageQueue(); + + return outStream; +} + +/** + * In stream to read GAnalytics from file. + */ +QDataStream& operator>>(QDataStream& inStream, GAnalytics& analytics) +{ + QList<QString> dataList; + inStream >> dataList; + analytics.d->readMessagesFromFile(dataList); + + return inStream; +} diff --git a/meshmc/libraries/ganalytics/src/ganalytics_worker.cpp b/meshmc/libraries/ganalytics/src/ganalytics_worker.cpp new file mode 100644 index 0000000000..115b39d5d4 --- /dev/null +++ b/meshmc/libraries/ganalytics/src/ganalytics_worker.cpp @@ -0,0 +1,267 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "ganalytics.h" +#include "ganalytics_worker.h" +#include "sys.h" + +#include <QCoreApplication> +#include <QNetworkAccessManager> +#include <QNetworkReply> + +#include <QGuiApplication> +#include <QScreen> + +const QLatin1String + GAnalyticsWorker::dateTimeFormat("yyyy,MM,dd-hh:mm::ss:zzz"); + +GAnalyticsWorker::GAnalyticsWorker(GAnalytics* parent) + : QObject(parent), q(parent), m_logLevel(GAnalytics::Error) +{ + m_appName = QCoreApplication::instance()->applicationName(); + m_appVersion = QCoreApplication::instance()->applicationVersion(); + m_request.setUrl(QUrl("https://www.google-analytics.com/collect")); + m_request.setHeader(QNetworkRequest::ContentTypeHeader, + "application/x-www-form-urlencoded"); + m_request.setHeader(QNetworkRequest::UserAgentHeader, getUserAgent()); + + m_language = QLocale::system().name().toLower().replace("_", "-"); + m_screenResolution = getScreenResolution(); + + m_timer.setInterval(m_timerInterval); + connect(&m_timer, &QTimer::timeout, this, &GAnalyticsWorker::postMessage); +} + +void GAnalyticsWorker::enable(bool state) +{ + // state change to the same is not valid. + if (m_isEnabled == state) { + return; + } + + m_isEnabled = state; + if (m_isEnabled) { + // enable -> start doing things :) + m_timer.start(); + } else { + // disable -> stop the timer + m_timer.stop(); + } +} + +void GAnalyticsWorker::logMessage(GAnalytics::LogLevel level, + const QString& message) +{ + if (m_logLevel > level) { + return; + } + + qDebug() << "[Analytics]" << message; +} + +/** + * Build the POST query. Adds all parameter to the query + * which are used in every POST. + * @param type Type of POST message. The event which is to post. + * @return query Most used parameter in a query for a POST. + */ +QUrlQuery GAnalyticsWorker::buildStandardPostQuery(const QString& type) +{ + QUrlQuery query; + query.addQueryItem("v", "1"); + query.addQueryItem("tid", m_trackingID); + query.addQueryItem("cid", m_clientID); + if (!m_userID.isEmpty()) { + query.addQueryItem("uid", m_userID); + } + query.addQueryItem("t", type); + query.addQueryItem("ul", m_language); + query.addQueryItem("vp", m_viewportSize); + query.addQueryItem("sr", m_screenResolution); + if (m_anonymizeIPs) { + query.addQueryItem("aip", "1"); + } + return query; +} + +/** + * Get primary screen resolution. + * @return A QString like "800x600". + */ +QString GAnalyticsWorker::getScreenResolution() +{ + QScreen* screen = QGuiApplication::primaryScreen(); + QSize size = screen->size(); + + return QString("%1x%2").arg(size.width()).arg(size.height()); +} + +/** + * Try to gain information about the system where this application + * is running. It needs to get the name and version of the operating + * system, the language and screen resolution. + * All this information will be send in POST messages. + * @return agent A QString with all the information formatted for a POST + * message. + */ +QString GAnalyticsWorker::getUserAgent() +{ + return QString("%1/%2").arg(m_appName).arg(m_appVersion); +} + +/** + * The message queue contains a list of QueryBuffer object. + * QueryBuffer holds a QUrlQuery object and a QDateTime object. + * These both object are freed from the buffer object and + * inserted as QString objects in a QList. + * @return dataList The list with concartinated queue data. + */ +QList<QString> GAnalyticsWorker::persistMessageQueue() +{ + QList<QString> dataList; + foreach (QueryBuffer buffer, m_messageQueue) { + dataList << buffer.postQuery.toString(); + dataList << buffer.time.toString(dateTimeFormat); + } + return dataList; +} + +/** + * Reads persistent messages from a file. + * Gets all message data as a QList<QString>. + * Two lines in the list build a QueryBuffer object. + */ +void GAnalyticsWorker::readMessagesFromFile(const QList<QString>& dataList) +{ + QListIterator<QString> iter(dataList); + while (iter.hasNext()) { + QString queryString = iter.next(); + QString dateString = iter.next(); + QUrlQuery query; + query.setQuery(queryString); + QDateTime dateTime = QDateTime::fromString(dateString, dateTimeFormat); + QueryBuffer buffer; + buffer.postQuery = query; + buffer.time = dateTime; + m_messageQueue.enqueue(buffer); + } +} + +/** + * Takes a QUrlQuery object and wrapp it together with + * a QTime object into a QueryBuffer struct. These struct + * will be stored in the message queue. + */ +void GAnalyticsWorker::enqueQueryWithCurrentTime(const QUrlQuery& query) +{ + QueryBuffer buffer; + buffer.postQuery = query; + buffer.time = QDateTime::currentDateTime(); + + m_messageQueue.enqueue(buffer); +} + +/** + * This function is called by a timer interval. + * The function tries to send a messages from the queue. + * If message was successfully send then this function + * will be called back to send next message. + * If message queue contains more than one message then + * the connection will kept open. + * The message POST is asyncroniously when the server + * answered a signal will be emitted. + */ +void GAnalyticsWorker::postMessage() +{ + if (m_messageQueue.isEmpty()) { + // queue empty -> try sending later + m_timer.start(); + return; + } else { + // queue has messages -> stop timer and start sending + m_timer.stop(); + } + + QString connection = "close"; + if (m_messageQueue.count() > 1) { + connection = "keep-alive"; + } + + QueryBuffer buffer = m_messageQueue.head(); + QDateTime sendTime = QDateTime::currentDateTime(); + qint64 timeDiff = buffer.time.msecsTo(sendTime); + + if (timeDiff > fourHours) { + // too old. + m_messageQueue.dequeue(); + emit postMessage(); + return; + } + + buffer.postQuery.addQueryItem("qt", QString::number(timeDiff)); + m_request.setRawHeader("Connection", connection.toUtf8()); + m_request.setHeader(QNetworkRequest::ContentLengthHeader, + buffer.postQuery.toString().length()); + + logMessage(GAnalytics::Debug, + "Query string = " + buffer.postQuery.toString()); + + // Create a new network access manager if we don't have one yet + if (networkManager == NULL) { + networkManager = new QNetworkAccessManager(this); + } + + QNetworkReply* reply = networkManager->post( + m_request, buffer.postQuery.query(QUrl::EncodeUnicode).toUtf8()); + connect(reply, SIGNAL(finished()), this, SLOT(postMessageFinished())); +} + +/** + * NetworkAccsessManager has finished to POST a message. + * If POST message was successfully send then the message + * query should be removed from queue. + * SIGNAL "postMessage" will be emitted to send next message + * if there is any. + * If message couldn't be send then next try is when the + * timer emits its signal. + */ +void GAnalyticsWorker::postMessageFinished() +{ + QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); + + int httpStausCode = + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (httpStausCode < 200 || httpStausCode > 299) { + logMessage( + GAnalytics::Error, + QString("Error posting message: %1").arg(reply->errorString())); + + // An error ocurred. Try sending later. + m_timer.start(); + return; + } else { + logMessage(GAnalytics::Debug, "Message sent"); + } + + m_messageQueue.dequeue(); + postMessage(); + reply->deleteLater(); +} diff --git a/meshmc/libraries/ganalytics/src/ganalytics_worker.h b/meshmc/libraries/ganalytics/src/ganalytics_worker.h new file mode 100644 index 0000000000..8acace3759 --- /dev/null +++ b/meshmc/libraries/ganalytics/src/ganalytics_worker.h @@ -0,0 +1,84 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QUrlQuery> +#include <QDateTime> +#include <QTimer> +#include <QNetworkRequest> +#include <QQueue> + +struct QueryBuffer { + QUrlQuery postQuery; + QDateTime time; +}; + +class GAnalyticsWorker : public QObject +{ + Q_OBJECT + + public: + explicit GAnalyticsWorker(GAnalytics* parent = 0); + + GAnalytics* q; + + QNetworkAccessManager* networkManager = nullptr; + + QQueue<QueryBuffer> m_messageQueue; + QTimer m_timer; + QNetworkRequest m_request; + GAnalytics::LogLevel m_logLevel; + + QString m_trackingID; + QString m_clientID; + QString m_userID; + QString m_appName; + QString m_appVersion; + QString m_language; + QString m_screenResolution; + QString m_viewportSize; + + bool m_anonymizeIPs = false; + bool m_isEnabled = false; + int m_timerInterval = 30000; + int m_version = 0; + + const static int fourHours = 4 * 60 * 60 * 1000; + const static QLatin1String dateTimeFormat; + + public: + void logMessage(GAnalytics::LogLevel level, const QString& message); + + QUrlQuery buildStandardPostQuery(const QString& type); + QString getScreenResolution(); + QString getUserAgent(); + QList<QString> persistMessageQueue(); + void readMessagesFromFile(const QList<QString>& dataList); + + void enqueQueryWithCurrentTime(const QUrlQuery& query); + void setIsSending(bool doSend); + void enable(bool state); + + public slots: + void postMessage(); + void postMessageFinished(); +}; |
