Enable telemetry

- Phone back home image downloaded for image popularity research.
  Only in case image comes from our repository (NOT for custom images)
This commit is contained in:
Floris Bos 2020-11-26 22:26:15 +01:00
parent f6a8c4d943
commit 95ce718d41
9 changed files with 111 additions and 9 deletions

View file

@ -20,7 +20,7 @@ set(CMAKE_AUTORCC ON)
# Adding headers explicity so they are displayed in Qt Creator # Adding headers explicity so they are displayed in Qt Creator
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h drivelistmodelpollthread.h driveformatthread.h powersaveblocker.h set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h drivelistmodelpollthread.h driveformatthread.h powersaveblocker.h
downloadthread.h downloadextractthread.h localfileextractthread.h dependencies/mountutils/src/mountutils.hpp) downloadthread.h downloadextractthread.h localfileextractthread.h downloadstatstelemetry.h dependencies/mountutils/src/mountutils.hpp)
# Add dependencies # Add dependencies
if (APPLE) if (APPLE)
@ -68,7 +68,7 @@ endif()
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp" set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
"drivelistitem.cpp" "drivelistmodel.cpp" "drivelistmodelpollthread.cpp" "downloadthread.cpp" "downloadextractthread.cpp" "drivelistitem.cpp" "drivelistmodel.cpp" "drivelistmodelpollthread.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
"driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "qml.qrc") "driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "downloadstatstelemetry.cpp" "qml.qrc")
find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets) find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets)
if (Qt5Widgets_FOUND) if (Qt5Widgets_FOUND)

View file

@ -8,10 +8,14 @@
/* Repository URL */ /* Repository URL */
#define OSLIST_URL "https://downloads.raspberrypi.org/os_list_imagingutility.json" #define OSLIST_URL "https://downloads.raspberrypi.org/os_list_imagingutility_v2.json"
/* Time synchronization URL (only used on eglfs QPA platform, URL must be HTTP) */ /* Time synchronization URL (only used on eglfs QPA platform, URL must be HTTP) */
#define TIME_URL "http://downloads.raspberrypi.org/os_list_imagingutility.json?time_synchronization" #define TIME_URL "http://downloads.raspberrypi.org/os_list_imagingutility_v2.json?time_synchronization"
/* Phone home the name of images downloaded for image popularity ranking */
#define TELEMETRY_URL "https://rpi-imager-stats.raspberrypi.org/downloads?url=$imageurl&os=$parentcategory&image=$osname"
#define TELEMETRY_ENABLED_DEFAULT true
/* Hash algorithm for verifying (uncompressed image) checksum */ /* Hash algorithm for verifying (uncompressed image) checksum */
#define OSLIST_HASH_ALGORITHM QCryptographicHash::Sha256 #define OSLIST_HASH_ALGORITHM QCryptographicHash::Sha256

2
debian/changelog vendored
View file

@ -8,6 +8,8 @@ rpi-imager (1.5) unstable; urgency=medium
* Add update notification support * Add update notification support
* Allow translators to specify external .qm file for testing * Allow translators to specify external .qm file for testing
* Remove dependency on qml-module-qt-labs-settings * Remove dependency on qml-module-qt-labs-settings
* Enables telemetry collecting information about which images from
repository are most popular
-- Floris Bos <bos@je-eigen-domein.nl> Tue, 24 Nov 2020 10:38:21 +0100 -- Floris Bos <bos@je-eigen-domein.nl> Tue, 24 Nov 2020 10:38:21 +0100

View file

@ -0,0 +1,53 @@
#include "downloadstatstelemetry.h"
#include "config.h"
#include <QSettings>
#include <QDebug>
#include <QUrl>
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
DownloadStatsTelemetry::DownloadStatsTelemetry(const QByteArray &url, const QByteArray &parentcategory, const QByteArray &osname, QObject *parent)
: QThread(parent)
{
_url = QByteArray(TELEMETRY_URL).replace("$imageurl", QUrl::toPercentEncoding(url)).replace("$parentcategory", QUrl::toPercentEncoding(parentcategory)).replace("$osname", QUrl::toPercentEncoding(osname));
_useragent = "Mozilla/5.0 rpi-imager/" IMAGER_VERSION_STR;
}
void DownloadStatsTelemetry::run()
{
QSettings settings;
if (!settings.value("telemetry", TELEMETRY_ENABLED_DEFAULT).toBool())
return;
_c = curl_easy_init();
curl_easy_setopt(_c, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(_c, CURLOPT_WRITEFUNCTION, &DownloadStatsTelemetry::_curl_write_callback);
curl_easy_setopt(_c, CURLOPT_HEADERFUNCTION, &DownloadStatsTelemetry::_curl_header_callback);
curl_easy_setopt(_c, CURLOPT_URL, _url.constData());
curl_easy_setopt(_c, CURLOPT_USERAGENT, _useragent.constData());
curl_easy_setopt(_c, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(_c, CURLOPT_LOW_SPEED_TIME, 10);
curl_easy_setopt(_c, CURLOPT_LOW_SPEED_LIMIT, 10);
CURLcode ret = curl_easy_perform(_c);
curl_easy_cleanup(_c);
qDebug() << "Telemetry done. cURL status code =" << ret;
}
/* /dev/null write handler */
size_t DownloadStatsTelemetry::_curl_write_callback(char *, size_t size, size_t nmemb, void *)
{
return size * nmemb;
}
size_t DownloadStatsTelemetry::_curl_header_callback( void *ptr, size_t size, size_t nmemb, void *)
{
int len = size*nmemb;
QByteArray headerstr((char *) ptr, len);
//qDebug() << "Received telemetry header:" << headerstr;
return len;
}

31
downloadstatstelemetry.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef DOWNLOADSTATSTELEMETRY_H
#define DOWNLOADSTATSTELEMETRY_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
#include <QObject>
#include <QThread>
#include <curl/curl.h>
class DownloadStatsTelemetry : public QThread
{
Q_OBJECT
public:
explicit DownloadStatsTelemetry(const QByteArray &url, const QByteArray &parentcategory, const QByteArray &osname, QObject *parent = nullptr);
protected:
CURL *_c;
QByteArray _url, _useragent;
virtual void run();
static size_t _curl_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);
static size_t _curl_header_callback( void *ptr, size_t size, size_t nmemb, void *userdata);
signals:
public slots:
};
#endif // DOWNLOADSTATSTELEMETRY_H

View file

@ -9,6 +9,7 @@
#include "dependencies/drivelist/src/drivelist.hpp" #include "dependencies/drivelist/src/drivelist.hpp"
#include "driveformatthread.h" #include "driveformatthread.h"
#include "localfileextractthread.h" #include "localfileextractthread.h"
#include "downloadstatstelemetry.h"
#include <archive.h> #include <archive.h>
#include <archive_entry.h> #include <archive_entry.h>
#include <QFileInfo> #include <QFileInfo>
@ -112,13 +113,15 @@ void ImageWriter::setEngine(QQmlApplicationEngine *engine)
} }
/* Set URL to download from */ /* Set URL to download from */
void ImageWriter::setSrc(const QUrl &url, quint64 downloadLen, quint64 extrLen, QByteArray expectedHash, bool multifilesinzip) void ImageWriter::setSrc(const QUrl &url, quint64 downloadLen, quint64 extrLen, QByteArray expectedHash, bool multifilesinzip, QString parentcategory, QString osname)
{ {
_src = url; _src = url;
_downloadLen = downloadLen; _downloadLen = downloadLen;
_extrLen = extrLen; _extrLen = extrLen;
_expectedHash = expectedHash; _expectedHash = expectedHash;
_multipleFilesInZip = multifilesinzip; _multipleFilesInZip = multifilesinzip;
_parentCategory = parentcategory;
_osName = osname;
if (!_downloadLen && url.isLocalFile()) if (!_downloadLen && url.isLocalFile())
{ {
@ -191,6 +194,9 @@ void ImageWriter::startWrite()
else if (compressed) else if (compressed)
{ {
_thread = new DownloadExtractThread(urlstr, _dst.toLatin1(), _expectedHash, this); _thread = new DownloadExtractThread(urlstr, _dst.toLatin1(), _expectedHash, this);
DownloadStatsTelemetry *tele = new DownloadStatsTelemetry(urlstr, _parentCategory.toLatin1(), _osName.toLatin1(), this);
connect(tele, SIGNAL(finished()), tele, SLOT(deleteLater()));
tele->start();
} }
else else
{ {

View file

@ -28,7 +28,7 @@ public:
void setEngine(QQmlApplicationEngine *engine); void setEngine(QQmlApplicationEngine *engine);
/* Set URL to download from, and if known download length and uncompressed length */ /* Set URL to download from, and if known download length and uncompressed length */
Q_INVOKABLE void setSrc(const QUrl &url, quint64 downloadLen = 0, quint64 extrLen = 0, QByteArray expectedHash = "", bool multifilesinzip = false); Q_INVOKABLE void setSrc(const QUrl &url, quint64 downloadLen = 0, quint64 extrLen = 0, QByteArray expectedHash = "", bool multifilesinzip = false, QString parentcategory = "", QString osname = "");
/* Set device to write to */ /* Set device to write to */
Q_INVOKABLE void setDst(const QString &device, quint64 deviceSize = 0); Q_INVOKABLE void setDst(const QString &device, quint64 deviceSize = 0);
@ -120,7 +120,7 @@ protected slots:
protected: protected:
QUrl _src, _repo; QUrl _src, _repo;
QString _dst, _cacheFileName; QString _dst, _cacheFileName, _parentCategory, _osName;
QByteArray _expectedHash, _cachedFileHash; QByteArray _expectedHash, _cachedFileHash;
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow; quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
DriveListModel _drivelist; DriveListModel _drivelist;

View file

@ -57,5 +57,7 @@
<releases> <releases>
<release version="@IMAGER_VERSION_STR@" /> <release version="@IMAGER_VERSION_STR@" />
</releases> </releases>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1">
<content_attribute id="social-info">moderate</content_attribute>
</content_rating>
</component> </component>

View file

@ -261,6 +261,7 @@ ApplicationWindow {
height: parent.height-50 height: parent.height-50
padding: 0 padding: 0
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
property string categorySelected : ""
// background of title // background of title
Rectangle { Rectangle {
@ -936,13 +937,16 @@ ApplicationWindow {
else else
suboslist.currentIndex = -1 suboslist.currentIndex = -1
osswipeview.setCurrentIndex(1) osswipeview.setCurrentIndex(1)
ospopup.categorySelected = d.name
} else if (typeof(d.subitems_url) == "string" && d.subitems_url !== "") { } else if (typeof(d.subitems_url) == "string" && d.subitems_url !== "") {
if (d.subitems_url === "internal://back") if (d.subitems_url === "internal://back")
{ {
osswipeview.setCurrentIndex(0) osswipeview.setCurrentIndex(0)
ospopup.categorySelected = ""
} }
else else
{ {
ospopup.categorySelected = d.name
var suburl = d.subitems_url var suburl = d.subitems_url
if (subosmodel.count>1) if (subosmodel.count>1)
{ {
@ -994,7 +998,7 @@ ApplicationWindow {
} }
} }
} else { } else {
imageWriter.setSrc(d.url, d.image_download_size, d.extract_size, typeof(d.extract_sha256) != "undefined" ? d.extract_sha256 : "", typeof(d.contains_multiple_files) != "undefined" ? d.contains_multiple_files : false) imageWriter.setSrc(d.url, d.image_download_size, d.extract_size, typeof(d.extract_sha256) != "undefined" ? d.extract_sha256 : "", typeof(d.contains_multiple_files) != "undefined" ? d.contains_multiple_files : false, ospopup.categorySelected, d.name)
osbutton.text = d.name osbutton.text = d.name
ospopup.close() ospopup.close()
if (imageWriter.readyToWrite()) { if (imageWriter.readyToWrite()) {