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
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
if (APPLE)
@ -68,7 +68,7 @@ endif()
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.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)
if (Qt5Widgets_FOUND)

View file

@ -8,10 +8,14 @@
/* 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) */
#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 */
#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
* Allow translators to specify external .qm file for testing
* 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

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 "driveformatthread.h"
#include "localfileextractthread.h"
#include "downloadstatstelemetry.h"
#include <archive.h>
#include <archive_entry.h>
#include <QFileInfo>
@ -112,13 +113,15 @@ void ImageWriter::setEngine(QQmlApplicationEngine *engine)
}
/* 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;
_downloadLen = downloadLen;
_extrLen = extrLen;
_expectedHash = expectedHash;
_multipleFilesInZip = multifilesinzip;
_parentCategory = parentcategory;
_osName = osname;
if (!_downloadLen && url.isLocalFile())
{
@ -191,6 +194,9 @@ void ImageWriter::startWrite()
else if (compressed)
{
_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
{

View file

@ -28,7 +28,7 @@ public:
void setEngine(QQmlApplicationEngine *engine);
/* 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 */
Q_INVOKABLE void setDst(const QString &device, quint64 deviceSize = 0);
@ -120,7 +120,7 @@ protected slots:
protected:
QUrl _src, _repo;
QString _dst, _cacheFileName;
QString _dst, _cacheFileName, _parentCategory, _osName;
QByteArray _expectedHash, _cachedFileHash;
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
DriveListModel _drivelist;

View file

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

View file

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