Merge pull request #8391 from AlexanderOtavka/qml-atp

Add support for ATP protocol to QML
This commit is contained in:
Brad Hefta-Gaub 2016-08-10 09:16:20 -07:00 committed by GitHub
commit d736857ecb
10 changed files with 175 additions and 13 deletions

View file

@ -25,6 +25,7 @@
#include <NumericalConstants.h>
#include <Finally.h>
#include <PathUtils.h>
#include <NetworkAccessManager.h>
#include "OffscreenGLCanvas.h"
#include "GLEscrow.h"
@ -55,6 +56,22 @@ private:
friend class OffscreenQmlSurface;
};
class QmlNetworkAccessManager : public NetworkAccessManager {
public:
friend class QmlNetworkAccessManagerFactory;
protected:
QmlNetworkAccessManager(QObject* parent) : NetworkAccessManager(parent) { }
};
class QmlNetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory {
public:
QNetworkAccessManager* create(QObject* parent);
};
QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
return new QmlNetworkAccessManager(parent);
}
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
@ -402,6 +419,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// Create a QML engine.
_qmlEngine = new QQmlEngine;
_qmlEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
auto importList = _qmlEngine->importPathList();
importList.insert(importList.begin(), PathUtils::resourcesPath());
_qmlEngine->setImportPathList(importList);

View file

@ -33,12 +33,7 @@ bool AssetResourceRequest::urlIsAssetHash() const {
}
void AssetResourceRequest::doSend() {
auto parts = _url.path().split(".", QString::SkipEmptyParts);
auto hash = parts.length() > 0 ? parts[0] : "";
auto extension = parts.length() > 1 ? parts[1] : "";
// We'll either have a hash or an ATP path to a file (that maps to a hash)
if (urlIsAssetHash()) {
// We've detected that this is a hash - simply use AssetClient to request that asset
auto parts = _url.path().split(".", QString::SkipEmptyParts);

View file

@ -0,0 +1,88 @@
//
// AtpReply.cpp
// libraries/networking/src
//
// Created by Zander Otavka on 8/4/16.
// Copyright 2016 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 "ResourceManager.h"
#include "AtpReply.h"
AtpReply::AtpReply(const QUrl& url, QObject* parent) :
_resourceRequest(ResourceManager::createResourceRequest(parent, url)) {
setOperation(QNetworkAccessManager::GetOperation);
connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress);
connect(_resourceRequest, &AssetResourceRequest::finished, this, &AtpReply::handleRequestFinish);
_resourceRequest->send();
}
AtpReply::~AtpReply() {
if (_resourceRequest) {
_resourceRequest->deleteLater();
_resourceRequest = nullptr;
}
}
qint64 AtpReply::bytesAvailable() const {
return _content.size() - _readOffset + QIODevice::bytesAvailable();
}
qint64 AtpReply::readData(char* data, qint64 maxSize) {
if (_readOffset < _content.size()) {
qint64 readSize = qMin(maxSize, _content.size() - _readOffset);
memcpy(data, _content.constData() + _readOffset, readSize);
_readOffset += readSize;
return readSize;
} else {
return -1;
}
}
void AtpReply::handleRequestFinish() {
Q_ASSERT(_resourceRequest->getState() == ResourceRequest::State::Finished);
switch (_resourceRequest->getResult()) {
case ResourceRequest::Result::Success:
setError(NoError, "Success");
_content = _resourceRequest->getData();
break;
case ResourceRequest::Result::InvalidURL:
setError(ContentNotFoundError, "Invalid URL");
break;
case ResourceRequest::Result::NotFound:
setError(ContentNotFoundError, "Not found");
break;
case ResourceRequest::Result::ServerUnavailable:
setError(ServiceUnavailableError, "Service unavailable");
break;
case ResourceRequest::Result::AccessDenied:
setError(ContentAccessDenied, "Access denied");
break;
case ResourceRequest::Result::Timeout:
setError(TimeoutError, "Timeout");
break;
default:
setError(UnknownNetworkError, "Unknown error");
break;
}
open(ReadOnly | Unbuffered);
setHeader(QNetworkRequest::ContentLengthHeader, QVariant(_content.size()));
if (error() != NoError) {
emit error(error());
}
setFinished(true);
emit readyRead();
emit finished();
_resourceRequest->deleteLater();
_resourceRequest = nullptr;
}

View file

@ -0,0 +1,40 @@
//
// AtpReply.h
// libraries/networking/src
//
// Created by Zander Otavka on 8/4/16.
// Copyright 2016 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
//
#ifndef hifi_AtpReply_h
#define hifi_AtpReply_h
#include <QtNetwork/QNetworkReply>
#include <QUrl>
#include "AssetResourceRequest.h"
class AtpReply : public QNetworkReply {
Q_OBJECT
public:
AtpReply(const QUrl& url, QObject* parent = Q_NULLPTR);
~AtpReply();
qint64 bytesAvailable() const override;
void abort() override { }
bool isSequential() const override { return true; }
protected:
qint64 readData(char* data, qint64 maxSize) override;
private:
void handleRequestFinish();
ResourceRequest* _resourceRequest { nullptr };
QByteArray _content;
qint64 _readOffset { 0 };
};
#endif // hifi_AtpReply_h

View file

@ -1,6 +1,6 @@
//
// NetworkAccessManager.cpp
//
// libraries/networking/src
//
// Created by Clement on 7/1/14.
// Copyright 2014 High Fidelity, Inc.
@ -11,6 +11,7 @@
#include <QThreadStorage>
#include "AtpReply.h"
#include "NetworkAccessManager.h"
QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
@ -23,3 +24,13 @@ QNetworkAccessManager& NetworkAccessManager::getInstance() {
return *networkAccessManagers.localData();
}
QNetworkReply* NetworkAccessManager::createRequest(Operation operation, const QNetworkRequest& request, QIODevice* device) {
if (request.url().scheme() == "atp" && operation == GetOperation) {
return new AtpReply(request.url());
//auto url = request.url().toString();
//return QNetworkAccessManager::createRequest(operation, request, device);
} else {
return QNetworkAccessManager::createRequest(operation, request, device);
}
}

View file

@ -1,6 +1,6 @@
//
// NetworkAccessManager.h
//
// libraries/networking/src
//
// Created by Clement on 7/1/14.
// Copyright 2014 High Fidelity, Inc.
@ -13,12 +13,17 @@
#define hifi_NetworkAccessManager_h
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtQml/QQmlNetworkAccessManagerFactory>
/// Wrapper around QNetworkAccessManager to restrict at one instance by thread
class NetworkAccessManager : public QObject {
class NetworkAccessManager : public QNetworkAccessManager {
Q_OBJECT
public:
static QNetworkAccessManager& getInstance();
protected:
NetworkAccessManager(QObject* parent = Q_NULLPTR) : QNetworkAccessManager(parent) {}
virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* device = Q_NULLPTR) override;
};
#endif // hifi_NetworkAccessManager_h

View file

@ -12,12 +12,13 @@
#ifndef hifi_OAuthNetworkAccessManager_h
#define hifi_OAuthNetworkAccessManager_h
#include <QNetworkAccessManager>
#include "NetworkAccessManager.h"
class OAuthNetworkAccessManager : public QNetworkAccessManager {
class OAuthNetworkAccessManager : public NetworkAccessManager {
public:
static OAuthNetworkAccessManager* getInstance();
protected:
OAuthNetworkAccessManager(QObject* parent = Q_NULLPTR) : NetworkAccessManager(parent) { }
virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& req, QIODevice* outgoingData = 0);
};

View file

@ -462,6 +462,7 @@ int ResourceCache::getPendingRequestCount() {
}
bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
Q_ASSERT(!resource.isNull());
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
if (_requestsActive >= _requestLimit) {

View file

@ -167,6 +167,7 @@ void ScriptCache::scriptContentAvailable() {
Lock lock(_containerLock);
allCallbacks = _contentCallbacks.values(url);
_contentCallbacks.remove(url);
Q_ASSERT(req->getState() == ResourceRequest::Finished);
success = req->getResult() == ResourceRequest::Success;
if (success) {

View file

@ -59,9 +59,10 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) {
properties = context->argument(0).toVariant().toMap();
}
QString url = properties[SOURCE_PROPERTY].toString();
if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:")) {
properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url).toString();
QUrl url { properties[SOURCE_PROPERTY].toString() };
if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" &&
url.scheme() != "atp") {
properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString();
}
return properties;