mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 22:28:48 +02:00
thread the AssetUpload so it doesn't take over main
This commit is contained in:
parent
c277584f2e
commit
513cae0d40
10 changed files with 201 additions and 37 deletions
|
@ -80,11 +80,6 @@ void AssetServer::run() {
|
||||||
file.rename(_resourcesDirectory.absoluteFilePath(hash));
|
file.rename(_resourcesDirectory.absoluteFilePath(hash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!_isFinished) {
|
|
||||||
// since we're a while loop we need to help Qt's event processing
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetServer::handleAssetGetInfo(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
void AssetServer::handleAssetGetInfo(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
|
|
||||||
OctreePacketProcessor::OctreePacketProcessor() {
|
OctreePacketProcessor::OctreePacketProcessor() {
|
||||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||||
|
|
||||||
packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData,
|
packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
|
||||||
PacketType::EntityErase, PacketType::OctreeStats },
|
|
||||||
this, "handleOctreePacket");
|
this, "handleOctreePacket");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,15 @@
|
||||||
#include "AssetUploadDialogFactory.h"
|
#include "AssetUploadDialogFactory.h"
|
||||||
|
|
||||||
#include <AssetClient.h>
|
#include <AssetClient.h>
|
||||||
|
#include <AssetUpload.h>
|
||||||
|
#include <AssetUtils.h>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtWidgets/QMessageBox>
|
#include <QtWidgets/QDialogButtonBox>
|
||||||
#include <QtWidgets/QFileDialog>
|
#include <QtWidgets/QFileDialog>
|
||||||
|
#include <QtWidgets/QLabel>
|
||||||
|
#include <QtWidgets/QLineEdit>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() {
|
AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() {
|
||||||
static AssetUploadDialogFactory staticInstance;
|
static AssetUploadDialogFactory staticInstance;
|
||||||
|
@ -27,29 +32,63 @@ AssetUploadDialogFactory::AssetUploadDialogFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetUploadDialogFactory::showDialog() {
|
void AssetUploadDialogFactory::showDialog() {
|
||||||
auto filename = QFileDialog::getOpenFileUrl(nullptr, "Select a file to upload");
|
auto filename = QFileDialog::getOpenFileUrl(_dialogParent, "Select a file to upload");
|
||||||
|
|
||||||
if (!filename.isEmpty()) {
|
if (!filename.isEmpty()) {
|
||||||
qDebug() << "Selected filename for upload to asset-server: " << filename;
|
qDebug() << "Selected filename for upload to asset-server: " << filename;
|
||||||
|
|
||||||
QFile file { filename.path() };
|
auto assetClient = DependencyManager::get<AssetClient>();
|
||||||
|
auto upload = assetClient->createUpload(filename.path());
|
||||||
|
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (upload) {
|
||||||
|
// connect to the finished signal so we know when the AssetUpload is done
|
||||||
|
QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished);
|
||||||
|
|
||||||
QFileInfo fileInfo { filename.path() };
|
// start the upload now
|
||||||
auto extension = fileInfo.suffix();
|
upload->start();
|
||||||
|
|
||||||
auto data = file.readAll();
|
|
||||||
|
|
||||||
auto assetClient = DependencyManager::get<AssetClient>();
|
|
||||||
|
|
||||||
assetClient->uploadAsset(data, extension, [this, extension](bool result, QString hash) mutable {
|
|
||||||
if (result) {
|
|
||||||
QMessageBox::information(_dialogParent, "Upload Successful", "URL: apt:/" + hash + "." + extension);
|
|
||||||
} else {
|
|
||||||
QMessageBox::warning(_dialogParent, "Upload Failed", "There was an error uploading the file.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) {
|
||||||
|
if (true) {
|
||||||
|
// show message box for successful upload, with copiable text for ATP hash
|
||||||
|
QDialog* hashCopyDialog = new QDialog(_dialogParent);
|
||||||
|
|
||||||
|
// delete the dialog on close
|
||||||
|
hashCopyDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
// set the window title
|
||||||
|
hashCopyDialog->setWindowTitle(tr("Successful Asset Upload"));
|
||||||
|
|
||||||
|
// setup a layout for the contents of the dialog
|
||||||
|
QVBoxLayout* boxLayout = new QVBoxLayout;
|
||||||
|
|
||||||
|
// set the label text (this shows above the text box)
|
||||||
|
QLabel* lineEditLabel = new QLabel;
|
||||||
|
lineEditLabel->setText(QString("ATP URL for %1").arg(upload->getFilename()));
|
||||||
|
|
||||||
|
// setup the line edit to hold the copiable text
|
||||||
|
QLineEdit* lineEdit = new QLineEdit;
|
||||||
|
|
||||||
|
// set the ATP URL as the text value so it's copiable
|
||||||
|
lineEdit->insert(QString("%1://%2").arg(ATP_SCHEME).arg(hash));
|
||||||
|
|
||||||
|
// add the label and line edit to the dialog
|
||||||
|
boxLayout->addWidget(lineEditLabel);
|
||||||
|
boxLayout->addWidget(lineEdit);
|
||||||
|
|
||||||
|
// setup an OK button to close the dialog
|
||||||
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, hashCopyDialog, &QDialog::close);
|
||||||
|
boxLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
// set the new layout on the dialog
|
||||||
|
hashCopyDialog->setLayout(boxLayout);
|
||||||
|
|
||||||
|
// show the new dialog
|
||||||
|
hashCopyDialog->show();
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
class AssetUpload;
|
||||||
|
|
||||||
class AssetUploadDialogFactory : public QObject {
|
class AssetUploadDialogFactory : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -28,6 +30,8 @@ public:
|
||||||
void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; }
|
void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; }
|
||||||
public slots:
|
public slots:
|
||||||
void showDialog();
|
void showDialog();
|
||||||
|
private slots:
|
||||||
|
void handleUploadFinished(AssetUpload* upload, const QString& hash);
|
||||||
private:
|
private:
|
||||||
QWidget* _dialogParent { nullptr };
|
QWidget* _dialogParent { nullptr };
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "AssetRequest.h"
|
#include "AssetRequest.h"
|
||||||
|
#include "AssetUpload.h"
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
#include "PacketReceiver.h"
|
#include "PacketReceiver.h"
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ AssetClient::AssetClient() {
|
||||||
packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply");
|
packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply");
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetRequest* AssetClient::create(QString hash) {
|
AssetRequest* AssetClient::createRequest(QString hash) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
AssetRequest* req;
|
AssetRequest* req;
|
||||||
QMetaObject::invokeMethod(this, "create",
|
QMetaObject::invokeMethod(this, "create",
|
||||||
|
@ -46,15 +47,32 @@ AssetRequest* AssetClient::create(QString hash) {
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto assetClient = DependencyManager::get<AssetClient>();
|
return new AssetRequest(this, hash);
|
||||||
auto request = new AssetRequest(assetClient.data(), hash);
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssetUpload* AssetClient::createUpload(QString filename) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
AssetUpload* upload;
|
||||||
|
QMetaObject::invokeMethod(this, "createUpload",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(AssetUpload*, upload),
|
||||||
|
Q_ARG(QString, filename));
|
||||||
|
return upload;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
|
if (assetServer) {
|
||||||
|
return new AssetUpload(this, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback) {
|
bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback) {
|
||||||
if (hash.length() != HASH_HEX_LENGTH) {
|
if (hash.length() != HASH_HEX_LENGTH) {
|
||||||
qDebug() << "Invalid hash size";
|
qDebug() << "Invalid hash size";
|
||||||
|
@ -156,6 +174,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer<NLPacketList> packetList, S
|
||||||
bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCallback callback) {
|
bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCallback callback) {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto packetList = std::unique_ptr<NLPacketList>(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true));
|
auto packetList = std::unique_ptr<NLPacketList>(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true));
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "NLPacket.h"
|
#include "NLPacket.h"
|
||||||
|
|
||||||
class AssetRequest;
|
class AssetRequest;
|
||||||
|
class AssetUpload;
|
||||||
|
|
||||||
struct AssetInfo {
|
struct AssetInfo {
|
||||||
QString hash;
|
QString hash;
|
||||||
|
@ -36,11 +37,8 @@ class AssetClient : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
AssetClient();
|
AssetClient();
|
||||||
|
|
||||||
Q_INVOKABLE AssetRequest* create(QString hash);
|
Q_INVOKABLE AssetRequest* createRequest(QString hash);
|
||||||
bool getAssetInfo(QString hash, GetInfoCallback callback);
|
Q_INVOKABLE AssetUpload* createUpload(QString filename);
|
||||||
bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback);
|
|
||||||
bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback);
|
|
||||||
bool abortDataRequest(MessageID messageID);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleAssetGetInfoReply(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
void handleAssetGetInfoReply(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||||
|
@ -48,10 +46,18 @@ private slots:
|
||||||
void handleAssetUploadReply(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
void handleAssetUploadReply(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool getAssetInfo(QString hash, GetInfoCallback callback);
|
||||||
|
bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback);
|
||||||
|
bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback);
|
||||||
|
bool abortDataRequest(MessageID messageID);
|
||||||
|
|
||||||
static MessageID _currentID;
|
static MessageID _currentID;
|
||||||
QHash<MessageID, ReceivedAssetCallback> _pendingRequests;
|
QHash<MessageID, ReceivedAssetCallback> _pendingRequests;
|
||||||
QHash<MessageID, GetInfoCallback> _pendingInfoRequests;
|
QHash<MessageID, GetInfoCallback> _pendingInfoRequests;
|
||||||
QHash<MessageID, UploadResultCallback> _pendingUploads;
|
QHash<MessageID, UploadResultCallback> _pendingUploads;
|
||||||
|
|
||||||
|
friend class AssetRequest;
|
||||||
|
friend class AssetUpload;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,7 @@ void ATPResourceRequest::doSend() {
|
||||||
auto assetClient = DependencyManager::get<AssetClient>();
|
auto assetClient = DependencyManager::get<AssetClient>();
|
||||||
auto hash = _url.path();
|
auto hash = _url.path();
|
||||||
|
|
||||||
auto request = assetClient->create(hash);
|
auto request = assetClient->createRequest(hash);
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
return;
|
return;
|
||||||
|
|
53
libraries/networking/src/AssetUpload.cpp
Normal file
53
libraries/networking/src/AssetUpload.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// AssetUpload.cpp
|
||||||
|
// libraries/networking/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2015-08-26.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetUpload.h"
|
||||||
|
|
||||||
|
#include <QtCore/QFileInfo>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include "AssetClient.h"
|
||||||
|
|
||||||
|
AssetUpload::AssetUpload(QObject* object, const QString& filename) :
|
||||||
|
_filename(filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetUpload::start() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "start", Qt::AutoConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to open the file at the given filename
|
||||||
|
QFile file { _filename };
|
||||||
|
|
||||||
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
|
||||||
|
// file opened, read the data and grab the extension
|
||||||
|
auto extension = QFileInfo(_filename).suffix();
|
||||||
|
|
||||||
|
auto data = file.readAll();
|
||||||
|
|
||||||
|
// ask the AssetClient to upload the asset and emit the proper signals from the passed callback
|
||||||
|
auto assetClient = DependencyManager::get<AssetClient>();
|
||||||
|
|
||||||
|
assetClient->uploadAsset(data, extension, [this](bool result, QString hash){
|
||||||
|
if (result) {
|
||||||
|
// successful upload - emit finished with a point to ourselves and the resulting hash
|
||||||
|
emit finished(this, hash);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
47
libraries/networking/src/AssetUpload.h
Normal file
47
libraries/networking/src/AssetUpload.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// AssetUpload.h
|
||||||
|
// libraries/networking/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2015-08-26.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef hifi_AssetUpload_h
|
||||||
|
#define hifi_AssetUpload_h
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
// You should be able to upload an asset from any thread, and handle the responses in a safe way
|
||||||
|
// on your own thread. Everything should happen on AssetClient's thread, the caller should
|
||||||
|
// receive events by connecting to signals on an object that lives on AssetClient's threads.
|
||||||
|
|
||||||
|
class AssetUpload : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Result {
|
||||||
|
Success = 0,
|
||||||
|
Timeout,
|
||||||
|
TooLarge,
|
||||||
|
};
|
||||||
|
|
||||||
|
AssetUpload(QObject* parent, const QString& filename);
|
||||||
|
|
||||||
|
Q_INVOKABLE void start();
|
||||||
|
|
||||||
|
const QString& getFilename() const { return _filename; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(AssetUpload* upload, const QString& hash);
|
||||||
|
void progress(uint64_t totalReceived, uint64_t total);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AssetUpload_h
|
|
@ -24,4 +24,6 @@ enum AssetServerError : uint8_t {
|
||||||
INVALID_BYTE_RANGE,
|
INVALID_BYTE_RANGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const QString ATP_SCHEME = "atp";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue