Display resource-access events in marketplace item tester

Includes refactoring marketplace item tester into a single-page app.
This commit is contained in:
Kerry Ivan Kurian 2018-09-26 14:32:25 -07:00
parent 8e5bc1678f
commit 3b15548ea3
39 changed files with 841 additions and 378 deletions

View file

@ -222,7 +222,8 @@ void Agent::requestScript() {
return; return;
} }
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, scriptURL, true, -1, "Agent::requestScript");
if (!request) { if (!request) {
qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString(); qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString();

View file

@ -4,7 +4,7 @@
// //
// Load items not in the marketplace for testing purposes // Load items not in the marketplace for testing purposes
// //
// Created by Zach Fox on 2018-09-05 // Created by Kerry Ivan Kurian on 2018-09-05
// Copyright 2018 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
@ -26,7 +26,9 @@ Rectangle {
id: root id: root
property string installedApps property string installedApps
property string resourceAccessEventText
property var nextResourceObjectId: 0 property var nextResourceObjectId: 0
property var startDate
signal sendToScript(var message) signal sendToScript(var message)
HifiStylesUit.HifiConstants { id: hifi } HifiStylesUit.HifiConstants { id: hifi }
@ -51,9 +53,28 @@ Rectangle {
spinner.visible = false; spinner.visible = false;
break; break;
case "nextObjectIdInTest": case "nextObjectIdInTest":
print("!!!! message from script! " + JSON.stringify(message));
nextResourceObjectId = message.id; nextResourceObjectId = message.id;
spinner.visible = false; spinner.visible = false;
break; break;
case "resourceRequestEvent":
try {
var date = new Date(JSON.parse(message.data.date));
} catch(err) {
print("!!!!! Date conversion failed: " + JSON.stringify(message.data));
}
// XXX Eventually this date check goes away b/c we will
// be able to match up resouce access events to resource
// object ids, ignoring those that have -1 resource
// object ids.
if (date >= startDate) {
resourceAccessEventText += (
message.data.callerId + " " + message.data.extra +
" " + message.data.url +
" [" + date.toISOString() + "]\n"
);
}
break;
} }
} }
@ -64,7 +85,7 @@ Rectangle {
resource.match(/\.json\.gz$/) ? "content set" : resource.match(/\.json\.gz$/) ? "content set" :
resource.match(/\.json$/) ? "entity or wearable" : resource.match(/\.json$/) ? "entity or wearable" :
"unknown"); "unknown");
return { "id": nextResourceObjectId++, return { "resourceObjectId": nextResourceObjectId++,
"resource": resource, "resource": resource,
"assetType": assetType }; "assetType": assetType };
} }
@ -89,29 +110,67 @@ Rectangle {
return httpPattern.test(resource) ? resource : "file:///" + resource; return httpPattern.test(resource) ? resource : "file:///" + resource;
} }
function rezEntity(resource, entityType) { function rezEntity(resource, entityType, resourceObjectId) {
print("!!!! tester_rezClicked");
sendToScript({ sendToScript({
method: 'tester_rezClicked', method: 'tester_rezClicked',
itemHref: toUrl(resource), itemHref: toUrl(resource),
itemType: entityType}); itemType: entityType,
itemId: resourceObjectId });
} }
ListView { Component.onCompleted: startDate = new Date()
anchors.fill: parent
ColumnLayout {
id: rootColumn
spacing: 30
HifiStylesUit.RalewayRegular {
id: rootHeader
text: "Marketplace Item Tester"
height: 40
width: paintedWidth
size: 22
color: hifi.colors.black
anchors.top: parent.top
anchors.topMargin: 20
anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.bottomMargin: 40 }
Rectangle {
height: root.height - 100
width: root.width
anchors.left: parent.left
ScrollView {
id: scrollView
anchors.fill: parent
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.bottom: parent.top
anchors.bottomMargin: 20
anchors.leftMargin: 12
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn
frameVisible: false
contentItem: ListView {
spacing: 20
height: 200
model: resourceListModel model: resourceListModel
spacing: 5
interactive: false interactive: false
delegate: RowLayout { delegate: Column {
anchors.left: parent.left spacing: 8
width: parent.width
RowLayout {
id: listRow
width: scrollView.width - 20
anchors.rightMargin: scrollView.rightMargin
spacing: 5 spacing: 5
property var actions: { property var actions: {
"forward": function(resource, assetType){ "forward": function(resource, assetType, resourceObjectId){
switch(assetType) { switch(assetType) {
case "application": case "application":
Commerce.openApp(resource); Commerce.openApp(resource);
@ -125,7 +184,7 @@ Rectangle {
break; break;
case "entity": case "entity":
case "wearable": case "wearable":
rezEntity(resource, assetType); rezEntity(resource, assetType, resourceObjectId);
break; break;
default: default:
print("Marketplace item tester unsupported assetType " + assetType); print("Marketplace item tester unsupported assetType " + assetType);
@ -143,20 +202,22 @@ Rectangle {
} }
Column { Column {
Layout.preferredWidth: root.width * .6 Layout.preferredWidth: scrollView.width * .6
spacing: 5 spacing: 5
Text { Text {
width: listRow.width * .6
text: { text: {
var match = resource.match(/\/([^/]*)$/); var match = resource.match(/\/([^/]*)$/);
return match ? match[1] : resource; return match ? match[1] : resource;
} }
font.pointSize: 12 font.pointSize: 12
horizontalAlignment: Text.AlignBottom horizontalAlignment: Text.AlignBottom
wrapMode: Text.WrapAnywhere
} }
Text { Text {
width: listRow.width * .6
text: resource text: resource
font.pointSize: 8 font.pointSize: 8
width: root.width * .6
horizontalAlignment: Text.AlignBottom horizontalAlignment: Text.AlignBottom
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
} }
@ -165,7 +226,7 @@ Rectangle {
ComboBox { ComboBox {
id: comboBox id: comboBox
Layout.preferredWidth: root.width * .2 Layout.preferredWidth: listRow.width * .2
model: [ model: [
"application", "application",
@ -184,7 +245,7 @@ Rectangle {
assetType = model[currentIndex]; assetType = model[currentIndex];
sendToScript({ sendToScript({
method: "tester_updateResourceObjectAssetType", method: "tester_updateResourceObjectAssetType",
objectId: resourceListModel.get(index)["id"], objectId: resourceListModel.get(index)["resourceObjectId"],
assetType: assetType }); assetType: assetType });
}); });
} }
@ -212,30 +273,77 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
actions[modelData](resource, comboBox.currentText); listRow.actions[modelData](resource, comboBox.currentText, resourceObjectId);
} }
} }
} }
} }
} }
headerPositioning: ListView.OverlayHeader Rectangle {
header: HifiStylesUit.RalewayRegular { id: detailsContainer
id: rootHeader
text: "Marketplace Item Tester" width: scrollView.width - 20
height: 80 height: resourceDetails.isOpen ? 300 : 20
width: paintedWidth
size: 22
color: hifi.colors.black
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12
HifiStylesUit.HiFiGlyphs {
id: detailsToggle
anchors.top: parent.top
text: resourceDetails.isOpen ? hifi.glyphs.minimize : hifi.glyphs.maximize
color: hifi.colors.black
size: 22
verticalAlignment: Text.AlignBottom
MouseArea {
anchors.fill: parent
onClicked: resourceDetails.isOpen = !resourceDetails.isOpen
}
} }
footerPositioning: ListView.OverlayFooter TextArea {
footer: Row { id: resourceDetails
property var isOpen: false
width: detailsContainer.width - 20
height: detailsContainer.height
anchors.top: parent.top
anchors.left: detailsToggle.left
anchors.leftMargin: 20
verticalScrollBarPolicy: isOpen ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff
frameVisible: isOpen
readOnly: true
text: {
if (isOpen) {
return resourceAccessEventText
} else {
return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..."
}
}
font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal })
wrapMode: TextEdit.NoWrap
}
}
Rectangle {
width: listRow.width
height: 1
color: hifi.colors.black
}
}
}
}
}
Row {
id: rootActions id: rootActions
spacing: 20 spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
anchors.left: parent.left
anchors.leftMargin: root.width / 6 - 10
anchors.bottomMargin: 40
anchors.bottom: parent.bottom
property string currentAction property string currentAction
property var actions: { property var actions: {
@ -257,6 +365,7 @@ Rectangle {
// Alas, there is nothing we can do about that so charge // Alas, there is nothing we can do about that so charge
// ahead as though we are sure the present signal is one // ahead as though we are sure the present signal is one
// we expect. // we expect.
print("!!!! resource selected");
switch(currentAction) { switch(currentAction) {
case "load file": case "load file":
Window.browseChanged.disconnect(onResourceSelected); Window.browseChanged.disconnect(onResourceSelected);
@ -266,8 +375,11 @@ Rectangle {
break; break;
} }
if (resource) { if (resource) {
print("!!!! building resource object");
var resourceObj = buildResourceObj(resource); var resourceObj = buildResourceObj(resource);
print("!!!! installing resource object");
installResourceObj(resourceObj); installResourceObj(resourceObj);
print("!!!! notifying script of resource object");
sendToScript({ sendToScript({
method: 'tester_newResourceObject', method: 'tester_newResourceObject',
resourceObject: resourceObj }); resourceObject: resourceObj });
@ -282,7 +394,7 @@ Rectangle {
text: modelData text: modelData
width: root.width / 3 width: root.width / 3
height: 40 height: 40
onClicked: actions[text]() onClicked: rootActions.actions[text]()
} }
} }
} }

View file

@ -170,6 +170,7 @@
#include "ModelPackager.h" #include "ModelPackager.h"
#include "scripting/Audio.h" #include "scripting/Audio.h"
#include "networking/CloseEventSender.h" #include "networking/CloseEventSender.h"
#include "QUrlAncestry.h"
#include "scripting/TestScriptingInterface.h" #include "scripting/TestScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/AssetMappingsScriptingInterface.h"
#include "scripting/ClipboardScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h"
@ -226,6 +227,7 @@
#include "commerce/Ledger.h" #include "commerce/Ledger.h"
#include "commerce/Wallet.h" #include "commerce/Wallet.h"
#include "commerce/QmlCommerce.h" #include "commerce/QmlCommerce.h"
#include "ResourceRequestObserver.h"
#include "webbrowser/WebBrowserSuggestionsEngine.h" #include "webbrowser/WebBrowserSuggestionsEngine.h"
#include <DesktopPreviewProvider.h> #include <DesktopPreviewProvider.h>
@ -945,8 +947,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<Ledger>(); DependencyManager::set<Ledger>();
DependencyManager::set<Wallet>(); DependencyManager::set<Wallet>();
DependencyManager::set<WalletScriptingInterface>(); DependencyManager::set<WalletScriptingInterface>();
DependencyManager::set<FadeEffect>(); DependencyManager::set<FadeEffect>();
DependencyManager::set<ResourceRequestObserver>();
return previousSessionCrashed; return previousSessionCrashed;
} }
@ -3129,6 +3131,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
@ -5021,12 +5024,11 @@ void Application::saveSettings() const {
PluginManager::getInstance()->saveSettings(); PluginManager::getInstance()->saveSettings();
} }
bool Application::importEntities(const QString& urlOrFilename) { bool Application::importEntities(const QString& urlOrFilename, const bool isObservable, const qint64 callerId) {
bool success = false; bool success = false;
_entityClipboard->withWriteLock([&] { _entityClipboard->withWriteLock([&] {
_entityClipboard->eraseAllOctreeElements(); _entityClipboard->eraseAllOctreeElements();
success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, QUrlAncestry());
success = _entityClipboard->readFromURL(urlOrFilename);
if (success) { if (success) {
_entityClipboard->reaverageOctreeElements(); _entityClipboard->reaverageOctreeElements();
} }
@ -6810,6 +6812,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data()); scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data());
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
@ -7196,7 +7199,8 @@ void Application::addAssetToWorldFromURL(QString url) {
addAssetToWorldInfo(filename, "Downloading model file " + filename + "."); addAssetToWorldInfo(filename, "Downloading model file " + filename + ".");
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, QUrl(url)); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, QUrl(url), true, -1, "Application::addAssetToWorldFromURL");
connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished); connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished);
request->send(); request->send();
} }

View file

@ -340,7 +340,7 @@ public slots:
QVector<EntityItemID> pasteEntities(float x, float y, float z); QVector<EntityItemID> pasteEntities(float x, float y, float z);
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr); bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool exportEntities(const QString& filename, float x, float y, float z, float scale);
bool importEntities(const QString& url); bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1);
void updateThreadPoolCount() const; void updateThreadPoolCount() const;
void updateSystemTabletMode(); void updateSystemTabletMode();
void goToErrorDomainURL(QUrl errorDomainURL); void goToErrorDomainURL(QUrl errorDomainURL);

View file

@ -53,7 +53,8 @@ void ATPAssetMigrator::loadEntityServerFile() {
auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) { auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) {
auto request = auto request =
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL); DependencyManager::get<ResourceManager>()->createResourceRequest(
this, migrationURL, true, -1, "ATPAssetMigrator::loadEntityServerFile");
if (request) { if (request) {
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration"; qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";

View file

@ -325,7 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) {
QUrl appHref(itemHref); QUrl appHref(itemHref);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, appHref); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, appHref, true, -1, "QmlCommerce::installApp");
if (!request) { if (!request) {
qCDebug(commerce) << "Couldn't create resource request for app."; qCDebug(commerce) << "Couldn't create resource request for app.";

View file

@ -46,11 +46,17 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float
return retVal; return retVal;
} }
bool ClipboardScriptingInterface::importEntities(const QString& filename) { bool ClipboardScriptingInterface::importEntities(
const QString& filename,
const bool isObservable,
const qint64 callerId
) {
bool retVal; bool retVal;
BLOCKING_INVOKE_METHOD(qApp, "importEntities", BLOCKING_INVOKE_METHOD(qApp, "importEntities",
Q_RETURN_ARG(bool, retVal), Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, filename)); Q_ARG(const QString&, filename),
Q_ARG(const bool, isObservable),
Q_ARG(const qint64, callerId));
return retVal; return retVal;
} }

View file

@ -50,9 +50,11 @@ public:
* You can generate a JSON file using {@link Clipboard.exportEntities}. * You can generate a JSON file using {@link Clipboard.exportEntities}.
* @function Clipboard.importEntities * @function Clipboard.importEntities
* @param {string} filename Path and name of file to import. * @param {string} filename Path and name of file to import.
* @param {boolean} does the ResourceRequestObserver observe this request?
* @param {number} optional internal id of object causing this import.
* @returns {boolean} <code>true</code> if the import was successful, otherwise <code>false</code>. * @returns {boolean} <code>true</code> if the import was successful, otherwise <code>false</code>.
*/ */
Q_INVOKABLE bool importEntities(const QString& filename); Q_INVOKABLE bool importEntities(const QString& filename, const bool isObservable = true, const qint64 callerId = -1);
/**jsdoc /**jsdoc
* Export the entities specified to a JSON file. * Export the entities specified to a JSON file.

View file

@ -59,6 +59,8 @@
#include "raypick/PointerScriptingInterface.h" #include "raypick/PointerScriptingInterface.h"
#include <display-plugins/CompositorHelper.h> #include <display-plugins/CompositorHelper.h>
#include "AboutUtil.h" #include "AboutUtil.h"
#include "ResourceRequestObserver.h"
static int MAX_WINDOW_SIZE = 4096; static int MAX_WINDOW_SIZE = 4096;
static const float METERS_TO_INCHES = 39.3701f; static const float METERS_TO_INCHES = 39.3701f;
@ -269,6 +271,7 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data()); _webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface()); _webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
// Override min fps for tablet UI, for silky smooth scrolling // Override min fps for tablet UI, for silky smooth scrolling
setMaxFPS(90); setMaxFPS(90);

View file

@ -44,6 +44,7 @@
#include "AvatarLogging.h" #include "AvatarLogging.h"
#include "AvatarTraits.h" #include "AvatarTraits.h"
#include "ClientTraitsHandler.h" #include "ClientTraitsHandler.h"
#include "ResourceRequestObserver.h"
//#define WANT_DEBUG //#define WANT_DEBUG
@ -2161,11 +2162,21 @@ void AvatarData::updateJointMappings() {
} }
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
////
// TODO: Should we rely upon HTTPResourceRequest instead?
// HTTPResourceRequest::doSend() covers all of the following and
// then some. It doesn't cover the connect() call, so we may
// want to add a HTTPResourceRequest::doSend() method that does
// connects.
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL); QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL);
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
DependencyManager::get<ResourceRequestObserver>()->update(
_skeletonModelURL, -1, "AvatarData::updateJointMappings");
QNetworkReply* networkReply = networkAccessManager.get(networkRequest); QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
//
////
connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply); connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply);
} }
} }

View file

@ -200,7 +200,8 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) {
_filterDataMap.insert(entityID, filterData); _filterDataMap.insert(entityID, filterData);
_lock.unlock(); _lock.unlock();
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL); auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, scriptURL, true, -1, "EntityEditFilters::addFilter");
if (!scriptRequest) { if (!scriptRequest) {
qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString(); qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString();
scriptRequestFinished(entityID); scriptRequestFinished(entityID);

View file

@ -38,6 +38,8 @@
#include "LogHandler.h" #include "LogHandler.h"
#include "EntityEditFilters.h" #include "EntityEditFilters.h"
#include "EntityDynamicFactoryInterface.h" #include "EntityDynamicFactoryInterface.h"
#include "QUrlAncestry.h"
static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50;
const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour
@ -2493,7 +2495,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer
return true; return true;
} }
bool EntityTree::readFromMap(QVariantMap& map) { bool EntityTree::readFromMap(QVariantMap& map, const QUrlAncestry& ancestry) {
// These are needed to deal with older content (before adding inheritance modes) // These are needed to deal with older content (before adding inheritance modes)
int contentVersion = map["Version"].toInt(); int contentVersion = map["Version"].toInt();
bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes);

View file

@ -22,6 +22,8 @@
#include "EntityTreeElement.h" #include "EntityTreeElement.h"
#include "DeleteEntityOperator.h" #include "DeleteEntityOperator.h"
#include "MovingEntitiesOperator.h" #include "MovingEntitiesOperator.h"
#include "QUrlAncestry.h"
class EntityTree; class EntityTree;
using EntityTreePointer = std::shared_ptr<EntityTree>; using EntityTreePointer = std::shared_ptr<EntityTree>;
@ -223,7 +225,7 @@ public:
virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues,
bool skipThoseWithBadParents) override; bool skipThoseWithBadParents) override;
virtual bool readFromMap(QVariantMap& entityDescription) override; virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& ancestry = {}) override;
glm::vec3 getContentsDimensions(); glm::vec3 getContentsDimensions();
float getContentsLargestDimension(); float getContentsLargestDimension();

View file

@ -953,7 +953,8 @@ bool GLTFReader::doesResourceExist(const QString& url) {
} }
std::tuple<bool, QByteArray> GLTFReader::requestData(QUrl& url) { std::tuple<bool, QByteArray> GLTFReader::requestData(QUrl& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "GLTFReader::requestData");
if (!request) { if (!request) {
return std::make_tuple(false, QByteArray()); return std::make_tuple(false, QByteArray());

View file

@ -443,7 +443,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file
} }
std::tuple<bool, QByteArray> requestData(QUrl& url) { std::tuple<bool, QByteArray> requestData(QUrl& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "(OBJReader) requestData");
if (!request) { if (!request) {
return std::make_tuple(false, QByteArray()); return std::make_tuple(false, QByteArray());

View file

@ -456,7 +456,8 @@ void NetworkTexture::makeRequest() {
// Add a fragment to the base url so we can identify the section of the ktx being requested when debugging // Add a fragment to the base url so we can identify the section of the ktx being requested when debugging
// The actual requested url is _activeUrl and will not contain the fragment // The actual requested url is _activeUrl and will not contain the fragment
_url.setFragment("head"); _url.setFragment("head");
_ktxHeaderRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl); _ktxHeaderRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, _activeUrl, true, -1, "NetworkTexture::makeRequest");
if (!_ktxHeaderRequest) { if (!_ktxHeaderRequest) {
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
@ -617,7 +618,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL; bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL;
_ktxMipRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl); _ktxMipRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, _activeUrl, true, -1, "NetworkTexture::startMipRangeRequest");
if (!_ktxMipRequest) { if (!_ktxMipRequest) {
qCWarning(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); qCWarning(networking).noquote() << "Failed to get request for" << _url.toDisplayString();

View file

@ -24,8 +24,12 @@
static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5; static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5;
AssetResourceRequest::AssetResourceRequest(const QUrl& url) : AssetResourceRequest::AssetResourceRequest(
ResourceRequest(url) const QUrl& url,
const bool isObservable,
const qint64 callerId,
const QString& extra) :
ResourceRequest(url, isObservable, callerId, extra)
{ {
_lastProgressDebug = p_high_resolution_clock::now() - std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS); _lastProgressDebug = p_high_resolution_clock::now() - std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS);
} }

View file

@ -22,7 +22,11 @@
class AssetResourceRequest : public ResourceRequest { class AssetResourceRequest : public ResourceRequest {
Q_OBJECT Q_OBJECT
public: public:
AssetResourceRequest(const QUrl& url); AssetResourceRequest(
const QUrl& url,
const bool isObservable = true,
const qint64 callerId = -1,
const QString& extra = "");
virtual ~AssetResourceRequest() override; virtual ~AssetResourceRequest() override;
protected: protected:

View file

@ -14,7 +14,8 @@
#include "ResourceManager.h" #include "ResourceManager.h"
AtpReply::AtpReply(const QUrl& url, QObject* parent) : AtpReply::AtpReply(const QUrl& url, QObject* parent) :
_resourceRequest(DependencyManager::get<ResourceManager>()->createResourceRequest(parent, url)) { _resourceRequest(DependencyManager::get<ResourceManager>()->createResourceRequest(
parent, url, true, -1, "AtpReply::AtpReply")) {
setOperation(QNetworkAccessManager::GetOperation); setOperation(QNetworkAccessManager::GetOperation);
connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress); connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress);

View file

@ -12,14 +12,19 @@
#ifndef hifi_FileResourceRequest_h #ifndef hifi_FileResourceRequest_h
#define hifi_FileResourceRequest_h #define hifi_FileResourceRequest_h
#include <QUrl>
#include "ResourceRequest.h" #include "ResourceRequest.h"
#include "QUrlAncestry.h"
class FileResourceRequest : public ResourceRequest { class FileResourceRequest : public ResourceRequest {
Q_OBJECT Q_OBJECT
public: public:
FileResourceRequest(const QUrl& url) : ResourceRequest(url) { } FileResourceRequest(
const QUrlAncestry& urlAncestry,
const bool isObservable = true,
const qint64 callerId = -1,
const QString& extra = ""
) : ResourceRequest(urlAncestry, isObservable, callerId, extra) { }
protected: protected:
virtual void doSend() override; virtual void doSend() override;

View file

@ -13,15 +13,21 @@
#define hifi_HTTPResourceRequest_h #define hifi_HTTPResourceRequest_h
#include <QNetworkReply> #include <QNetworkReply>
#include <QUrl>
#include <QTimer> #include <QTimer>
#include "ResourceRequest.h" #include "ResourceRequest.h"
#include "QUrlAncestry.h"
class HTTPResourceRequest : public ResourceRequest { class HTTPResourceRequest : public ResourceRequest {
Q_OBJECT Q_OBJECT
public: public:
HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { } HTTPResourceRequest(
const QUrlAncestry& urlAncestry,
const bool isObservable = true,
const qint64 callerId = -1,
const QString& = ""
) : ResourceRequest(urlAncestry, isObservable, callerId) { }
~HTTPResourceRequest(); ~HTTPResourceRequest();
protected: protected:

View file

@ -10,6 +10,7 @@
// //
#include "ResourceCache.h" #include "ResourceCache.h"
#include "ResourceRequestObserver.h"
#include <cfloat> #include <cfloat>
#include <cmath> #include <cmath>
@ -336,20 +337,20 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
QReadLocker locker(&_resourcesLock); QReadLocker locker(&_resourcesLock);
resource = _resources.value(url).lock(); resource = _resources.value(url).lock();
} }
if (resource) { if (resource) {
removeUnusedResource(resource); removeUnusedResource(resource);
return resource;
} }
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { if (!resource && !url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl()); resource = getResource(fallback, QUrl());
} }
if (!resource) {
resource = createResource( resource = createResource(
url, url,
fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer<Resource>(), fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer<Resource>(),
extra); extra); resource->setSelf(resource);
resource->setSelf(resource);
resource->setCache(this); resource->setCache(this);
resource->moveToThread(qApp->thread()); resource->moveToThread(qApp->thread());
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
@ -359,7 +360,10 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
} }
removeUnusedResource(resource); removeUnusedResource(resource);
resource->ensureLoading(); resource->ensureLoading();
}
DependencyManager::get<ResourceRequestObserver>()->update(
resource->getURL(), -1, "ResourceCache::getResource");
return resource; return resource;
} }
@ -494,7 +498,15 @@ bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
resource->makeRequest(); resource->makeRequest();
return true; return true;
} }
<<<<<<< HEAD
return false; return false;
=======
++_requestsActive;
sharedItems->appendActiveRequest(resource);
resource->makeRequest();
return true;
>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester
} }
void ResourceCache::requestCompleted(QWeakPointer<Resource> resource) { void ResourceCache::requestCompleted(QWeakPointer<Resource> resource) {
@ -602,8 +614,13 @@ void Resource::allReferencesCleared() {
} }
if (_cache && isCacheable()) { if (_cache && isCacheable()) {
<<<<<<< HEAD
// create and reinsert new shared pointer // create and reinsert new shared pointer
QSharedPointer<Resource> self(this, &Resource::deleter); QSharedPointer<Resource> self(this, &Resource::deleter);
=======
// create and reinsert new shared pointer
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester
setSelf(self); setSelf(self);
reinsert(); reinsert();
@ -682,7 +699,8 @@ void Resource::makeRequest() {
PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } }); PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } });
_request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl); _request = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, _activeUrl, true, -1, "Resource::makeRequest");
if (!_request) { if (!_request) {
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();

View file

@ -26,6 +26,7 @@
#include "NetworkAccessManager.h" #include "NetworkAccessManager.h"
#include "NetworkLogging.h" #include "NetworkLogging.h"
ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) { ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) {
_thread.setObjectName("Resource Manager Thread"); _thread.setObjectName("Resource Manager Thread");
@ -112,22 +113,29 @@ void ResourceManager::cleanup() {
_thread.wait(); _thread.wait();
} }
ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { ResourceRequest* ResourceManager::createResourceRequest(
QObject* parent,
const QUrl& url,
const bool isObservable,
const qint64 callerId,
const QString& extra
) {
auto normalizedURL = normalizeURL(url); auto normalizedURL = normalizeURL(url);
auto scheme = normalizedURL.scheme(); auto scheme = normalizedURL.scheme();
ResourceRequest* request = nullptr; ResourceRequest* request = nullptr;
qDebug() << "!!!! in createResourceRequest " << callerId;
if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) { if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) {
request = new FileResourceRequest(normalizedURL); request = new FileResourceRequest(normalizedURL, isObservable, callerId, extra);
} else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) {
request = new HTTPResourceRequest(normalizedURL); request = new HTTPResourceRequest(normalizedURL, isObservable, callerId, extra);
} else if (scheme == URL_SCHEME_ATP) { } else if (scheme == URL_SCHEME_ATP) {
if (!_atpSupportEnabled) { if (!_atpSupportEnabled) {
qCDebug(networking) << "ATP support not enabled, unable to create request for URL: " << url.url(); qCDebug(networking) << "ATP support not enabled, unable to create request for URL: " << url.url();
return nullptr; return nullptr;
} }
request = new AssetResourceRequest(normalizedURL); request = new AssetResourceRequest(normalizedURL, isObservable, callerId, extra);
} else { } else {
qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url(); qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url();
return nullptr; return nullptr;
@ -138,6 +146,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q
QObject::connect(parent, &QObject::destroyed, request, &QObject::deleteLater); QObject::connect(parent, &QObject::destroyed, request, &QObject::deleteLater);
} }
request->moveToThread(&_thread); request->moveToThread(&_thread);
return request; return request;
} }
@ -163,7 +172,7 @@ bool ResourceManager::resourceExists(const QUrl& url) {
return reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200; return reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200;
} else if (scheme == URL_SCHEME_ATP && _atpSupportEnabled) { } else if (scheme == URL_SCHEME_ATP && _atpSupportEnabled) {
auto request = new AssetResourceRequest(url); auto request = new AssetResourceRequest(url, ResourceRequest::IS_NOT_OBSERVABLE);
ByteRange range; ByteRange range;
range.fromInclusive = 1; range.fromInclusive = 1;
range.toExclusive = 1; range.toExclusive = 1;

View file

@ -34,7 +34,12 @@ public:
QString normalizeURL(const QString& urlString); QString normalizeURL(const QString& urlString);
QUrl normalizeURL(const QUrl& url); QUrl normalizeURL(const QUrl& url);
ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); ResourceRequest* createResourceRequest(
QObject* parent,
const QUrl& url,
const bool isObservable = true,
const qint64 callerId = -1,
const QString& extra = "");
void init(); void init();
void cleanup(); void cleanup();

View file

@ -10,15 +10,20 @@
// //
#include "ResourceRequest.h" #include "ResourceRequest.h"
#include "ResourceRequestObserver.h"
#include <DependencyManager.h> #include <DependencyManager.h>
#include <StatTracker.h> #include <StatTracker.h>
#include <QtCore/QThread> #include <QtCore/QThread>
ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { }
void ResourceRequest::send() { void ResourceRequest::send() {
if (_isObservable) {
DependencyManager::get<ResourceRequestObserver>()->update(
_urlAncestry, _callerId, _extra + " => ResourceRequest::send" );
}
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection);
return; return;

View file

@ -18,6 +18,8 @@
#include <cstdint> #include <cstdint>
#include "ByteRange.h" #include "ByteRange.h"
#include "QUrlAncestry.h"
const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest"; const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest";
const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest"; const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest";
@ -40,7 +42,21 @@ const QString STAT_FILE_RESOURCE_TOTAL_BYTES = "FILEBytesDownloaded";
class ResourceRequest : public QObject { class ResourceRequest : public QObject {
Q_OBJECT Q_OBJECT
public: public:
ResourceRequest(const QUrl& url); static const bool IS_OBSERVABLE = true;
static const bool IS_NOT_OBSERVABLE = false;
ResourceRequest(
const QUrlAncestry& urlAncestry,
const bool isObservable = IS_OBSERVABLE,
const qint64 callerId = -1,
const QString& extra = ""
) : _urlAncestry(urlAncestry),
_isObservable(isObservable),
_callerId(callerId),
_extra(extra),
_url(urlAncestry.last())
{ }
virtual ~ResourceRequest() = default; virtual ~ResourceRequest() = default;
enum State { enum State {
@ -87,6 +103,7 @@ protected:
virtual void doSend() = 0; virtual void doSend() = 0;
void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived); void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived);
QUrl _url; QUrl _url;
QUrl _relativePathURL; QUrl _relativePathURL;
State _state { NotStarted }; State _state { NotStarted };
@ -99,6 +116,10 @@ protected:
bool _rangeRequestSuccessful { false }; bool _rangeRequestSuccessful { false };
uint64_t _totalSizeOfResource { 0 }; uint64_t _totalSizeOfResource { 0 };
int64_t _lastRecordedBytesDownloaded { 0 }; int64_t _lastRecordedBytesDownloaded { 0 };
bool _isObservable;
qint64 _callerId;
QString _extra;
QUrlAncestry _urlAncestry;
}; };
#endif #endif

View file

@ -669,7 +669,7 @@ OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Oc
return args.element; return args.element;
} }
bool Octree::readFromFile(const char* fileName) { bool Octree::readFromFile(const char* fileName, const QUrlAncestry& urlAncestry) {
QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS); QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS);
if (qFileName.endsWith(".json.gz")) { if (qFileName.endsWith(".json.gz")) {
@ -689,7 +689,7 @@ bool Octree::readFromFile(const char* fileName) {
qCDebug(octree) << "Loading file" << qFileName << "..."; qCDebug(octree) << "Loading file" << qFileName << "...";
bool success = readFromStream(fileLength, fileInputStream); bool success = readFromStream(fileLength, fileInputStream, "", urlAncestry);
file.close(); file.close();
@ -734,11 +734,18 @@ QString getMarketplaceID(const QString& urlString) {
return QString(); return QString();
} }
bool Octree::readFromURL(const QString& urlString) { bool Octree::readFromURL(
const QString& urlString,
const bool isObservable,
const qint64 callerId,
const QUrlAncestry& urlAncestry
) {
QString trimmedUrl = urlString.trimmed(); QString trimmedUrl = urlString.trimmed();
QString marketplaceID = getMarketplaceID(trimmedUrl); QString marketplaceID = getMarketplaceID(trimmedUrl);
auto request = qDebug() << "!!!!! going to createResourceRequest " << callerId;
std::unique_ptr<ResourceRequest>(DependencyManager::get<ResourceManager>()->createResourceRequest(this, trimmedUrl)); auto request = std::unique_ptr<ResourceRequest>(
DependencyManager::get<ResourceManager>()->createResourceRequest(
this, trimmedUrl, isObservable, callerId, "Octree::readFromURL"));
if (!request) { if (!request) {
return false; return false;
@ -760,15 +767,20 @@ bool Octree::readFromURL(const QString& urlString) {
if (wasCompressed) { if (wasCompressed) {
QDataStream inputStream(uncompressedJsonData); QDataStream inputStream(uncompressedJsonData);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, urlAncestry);
} }
QDataStream inputStream(data); QDataStream inputStream(data);
return readFromStream(data.size(), inputStream, marketplaceID); return readFromStream(data.size(), inputStream, marketplaceID, urlAncestry);
} }
bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID) { bool Octree::readFromStream(
uint64_t streamLength,
QDataStream& inputStream,
const QString& marketplaceID,
const QUrlAncestry& urlAncestry
) {
// decide if this is binary SVO or JSON-formatted SVO // decide if this is binary SVO or JSON-formatted SVO
QIODevice *device = inputStream.device(); QIODevice *device = inputStream.device();
char firstChar; char firstChar;
@ -780,7 +792,7 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con
return false; return false;
} else { } else {
qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength;
return readJSONFromStream(streamLength, inputStream, marketplaceID); return readJSONFromStream(streamLength, inputStream, marketplaceID, urlAncestry);
} }
} }
@ -809,7 +821,12 @@ QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QStri
const int READ_JSON_BUFFER_SIZE = 2048; const int READ_JSON_BUFFER_SIZE = 2048;
bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID /*=""*/) { bool Octree::readJSONFromStream(
uint64_t streamLength,
QDataStream& inputStream,
const QString& marketplaceID, /*=""*/
const QUrlAncestry& urlAncestry
) {
// if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until
// we get an eof. Leave streamLength parameter for consistency. // we get an eof. Leave streamLength parameter for consistency.
@ -834,7 +851,7 @@ bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream,
} }
QVariant asVariant = asDocument.toVariant(); QVariant asVariant = asDocument.toVariant();
QVariantMap asMap = asVariant.toMap(); QVariantMap asMap = asVariant.toMap();
bool success = readFromMap(asMap); bool success = readFromMap(asMap, urlAncestry);
delete[] rawData; delete[] rawData;
return success; return success;
} }

View file

@ -29,6 +29,7 @@
#include "OctreePacketData.h" #include "OctreePacketData.h"
#include "OctreeSceneStats.h" #include "OctreeSceneStats.h"
#include "OctreeUtils.h" #include "OctreeUtils.h"
#include "QUrlAncestry.h"
class ReadBitstreamToTreeParams; class ReadBitstreamToTreeParams;
class Octree; class Octree;
@ -209,13 +210,13 @@ public:
bool skipThoseWithBadParents) = 0; bool skipThoseWithBadParents) = 0;
// Octree importers // Octree importers
bool readFromFile(const char* filename); bool readFromFile(const char* filename, const QUrlAncestry& urlAncestry = {});
bool readFromURL(const QString& url); // will support file urls as well... bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const QUrlAncestry& urlAncestry = {}); // will support file urls as well...
bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {});
bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream); bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream);
bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {});
bool readJSONFromGzippedFile(QString qFileName); bool readJSONFromGzippedFile(QString qFileName);
virtual bool readFromMap(QVariantMap& entityDescription) = 0; virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& urlAncestry = {}) = 0;
uint64_t getOctreeElementsCount(); uint64_t getOctreeElementsCount();

View file

@ -258,24 +258,29 @@ void OffscreenSurface::setMaxFps(uint8_t maxFps) {
} }
void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) { void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
qDebug() << "Here 1";
loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) { loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) {
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem)); QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
}); });
} }
void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback) { void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback) {
qDebug() << "Here 2";
loadInternal(qmlSource, createNewContext, nullptr, callback); loadInternal(qmlSource, createNewContext, nullptr, callback);
} }
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) { void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) {
qDebug() << "Here 3";
loadInternal(qmlSource, true, nullptr, callback, contextCallback); loadInternal(qmlSource, true, nullptr, callback, contextCallback);
} }
void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) { void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
qDebug() << "Here 4";
load(qmlSource, false, callback); load(qmlSource, false, callback);
} }
void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback) { void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback) {
qDebug() << "Here 5";
return load(QUrl(qmlSourceFile), callback); return load(QUrl(qmlSourceFile), callback);
} }

View file

@ -138,7 +138,8 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) {
// this function is not in use // this function is not in use
void FileScriptingInterface::downloadZip(QString path, const QString link) { void FileScriptingInterface::downloadZip(QString path, const QString link) {
QUrl url = QUrl(link); QUrl url = QUrl(link);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "FileScriptingInterface::downloadZip");
connect(request, &ResourceRequest::finished, this, [this, path]{ connect(request, &ResourceRequest::finished, this, [this, path]{
unzipFile(path, ""); // so intellisense isn't mad unzipFile(path, ""); // so intellisense isn't mad
}); });

View file

@ -109,7 +109,8 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
#ifdef THREAD_DEBUGGING #ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif #endif
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "ScriptCache::getScriptContents");
Q_ASSERT(request); Q_ASSERT(request);
request->setCacheEnabled(!forceDownload); request->setCacheEnabled(!forceDownload);
connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); }); connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); });
@ -166,7 +167,8 @@ void ScriptCache::scriptContentAvailable(int maxRetries) {
qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3") qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3")
.arg(attempt).arg(maxRetries).arg(url.toString()); .arg(attempt).arg(maxRetries).arg(url.toString());
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url); auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "ScriptCache::scriptContentAvailable");
Q_ASSERT(request); Q_ASSERT(request);
// We've already made a request, so the cache must be disabled or it wasn't there, so enabling // We've already made a request, so the cache must be disabled or it wasn't there, so enabling

View file

@ -21,6 +21,7 @@
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
#include <NetworkingConstants.h> #include <NetworkingConstants.h>
#include "ResourceRequestObserver.h"
#include "ScriptEngine.h" #include "ScriptEngine.h"
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/"; const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/";
@ -189,7 +190,7 @@ void XMLHttpRequestClass::send(const QScriptValue& data) {
} }
void XMLHttpRequestClass::doSend() { void XMLHttpRequestClass::doSend() {
DependencyManager::get<ResourceRequestObserver>()->update(_url, -1, "XMLHttpRequestClass::doSend");
_reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
connectToReply(_reply); connectToReply(_reply);

View file

@ -0,0 +1,31 @@
//
// EntityItemWeakPointerWithUrlAncestry.h
// libraries/shared/src/
//
// Created by Kerry Ivan Kurian 10/15/18
// Copyright 2018 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_EntityItemWeakPointerWithUrlAncestry_h
#define hifi_EntityItemWeakPointerWithUrlAncestry_h
#include "EntityTypes.h"
#include "QUrlAncestry.h"
struct EntityItemWeakPointerWithUrlAncestry {
EntityItemWeakPointerWithUrlAncestry(
const EntityItemWeakPointer& a,
const QUrlAncestry& b
) : entityItemWeakPointer(a), urlAncestry(b) {}
EntityItemWeakPointer entityItemWeakPointer;
QUrlAncestry urlAncestry;
};
#endif // hifi_EntityItemWeakPointerWithUrlAncestry_h

View file

@ -0,0 +1,35 @@
//
// QUrlAncestry.cpp
// libraries/shared/src/
//
// Created by Kerry Ivan Kurian on 10/12/18.
// Copyright (c) 2018 High Fidelity, Inc. All rights reserved.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "QUrlAncestry.h"
QUrlAncestry::QUrlAncestry(const QUrl& resource, const QUrl& referrer) {
this->append(referrer);
this->append(resource);
}
QUrlAncestry::QUrlAncestry(
const QUrl& resource,
const QUrlAncestry& ancestors) : QVector<QUrl>(ancestors)
{
this->append(resource);
}
void QUrlAncestry::toJson(QJsonArray& array) const {
for (auto const& qurl : *this) {
array.append(qurl.toDisplayString());
}
}
const QUrl QUrlAncestry::url() const {
return this->last();
}

View file

@ -0,0 +1,32 @@
//
// QUrlAncestry.h
// libraries/shared/src/
//
// Created by Kerry Ivan Kurian on 10/12/18.
// Copyright (c) 2018 High Fidelity, Inc. All rights reserved.
//
// 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_QUrlAncestry_H
#define hifi_QUrlAncestry_H
#include <QJsonArray>
#include <QUrl>
#include <QVector>
class QUrlAncestry : public QVector<QUrl> {
public:
QUrlAncestry() {}
QUrlAncestry(const QUrl& resource, const QUrl& referrer = QUrl("__NONE__"));
QUrlAncestry(const QUrl& resource, const QUrlAncestry& ancestors);
void toJson(QJsonArray& array) const;
const QUrl url() const;
};
#endif // hifi_QUrlVector_H

View file

@ -0,0 +1,38 @@
//
// ResourceAccessMonitor.h
// libraries/networking/src
//
// Created by Kerry Ivan Kurian on 9/27/18.
// Copyright 2018 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 <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QUrl>
#include "ResourceRequestObserver.h"
#include "QUrlAncestry.h"
// void ResourceRequestObserver::update(const QNetworkRequest& request, const qint64 callerId, const QString& extra) {
// update(QUrlAncestry(request.url()), callerId, extra);
// }
void ResourceRequestObserver::update(
const QUrlAncestry& urlAncestry,
const qint64 callerId,
const QString& extra
) {
QJsonArray array;
urlAncestry.toJson(array);
QJsonObject data {
{ "url", array },
{ "callerId", callerId },
{ "extra", extra }
};
emit resourceRequestEvent(data.toVariantMap());
}

View file

@ -0,0 +1,31 @@
//
// ResourceRequestObserver.h
// libraries/commerce/src
//
// Created by Kerry Ivan Kurian on 9/27/18.
// Copyright 2018 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 <QJsonObject>
#include <QString>
#include <QNetworkRequest>
#include "DependencyManager.h"
#include "QUrlAncestry.h"
class ResourceRequestObserver : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
// void update(const QNetworkRequest& request, const qint64 callerId = -1, const QString& extra = "");
void update(const QUrlAncestry& urlAncestry, const qint64 callerId = -1, const QString& extra = "");
signals:
void resourceRequestEvent(QVariantMap result);
};

View file

@ -49,6 +49,33 @@ var NO_BUTTON = 0; // QMessageBox::NoButton
var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server."; var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server.";
var resourceRequestEvents = [];
function signalResourceRequestEvent(data) {
ui.tablet.sendToQml({
method: "resourceRequestEvent",
data: data });
}
function onResourceRequestEvent(data) {
var resourceRequestEvent = {
"date": JSON.stringify(new Date()),
"url": data.url,
"callerId": data.callerId,
"extra": data.extra };
resourceRequestEvents.push(resourceRequestEvent);
signalResourceRequestEvent(resourceRequestEvent);
}
function pushResourceRequestEvents() {
var length = resourceRequestEvents.length
for (var i = 0; i < length; i++) {
if (i in resourceRequestEvents) {
signalResourceRequestEvent(resourceRequestEvents[i]);
}
}
}
function onMessageBoxClosed(id, button) { function onMessageBoxClosed(id, button) {
if (id === messageBox && button === CANCEL_BUTTON) { if (id === messageBox && button === CANCEL_BUTTON) {
isDownloadBeingCancelled = true; isDownloadBeingCancelled = true;
@ -522,13 +549,19 @@ function getPositionToCreateEntity(extra) {
return position; return position;
} }
function rezEntity(itemHref, itemType) { function defaultFor(arg, val) {
return typeof arg !== 'undefined' ? arg : val;
}
function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
var isWearable = itemType === "wearable"; var isWearable = itemType === "wearable";
var success = Clipboard.importEntities(itemHref); print("!!!!! Clipboard.importEntities " + marketplaceItemTesterId);
var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId);
var wearableLocalPosition = null; var wearableLocalPosition = null;
var wearableLocalRotation = null; var wearableLocalRotation = null;
var wearableLocalDimensions = null; var wearableLocalDimensions = null;
var wearableDimensions = null; var wearableDimensions = null;
marketplaceItemTesterId = defaultFor(marketplaceItemTesterId, -1);
if (itemType === "contentSet") { if (itemType === "contentSet") {
console.log("Item is a content set; codepath shouldn't go here."); console.log("Item is a content set; codepath shouldn't go here.");
@ -877,11 +910,12 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
case 'checkout_rezClicked': case 'checkout_rezClicked':
case 'purchases_rezClicked': case 'purchases_rezClicked':
case 'tester_rezClicked': case 'tester_rezClicked':
rezEntity(message.itemHref, message.itemType); print("!!!!! marketplaces tester_rezClicked");
rezEntity(message.itemHref, message.itemType, message.itemId);
break; break;
case 'tester_newResourceObject': case 'tester_newResourceObject':
var resourceObject = message.resourceObject; var resourceObject = message.resourceObject;
resourceObjectsInTest[resourceObject.id] = resourceObject; resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject;
signalNewResourceObjectInTest(resourceObject); signalNewResourceObjectInTest(resourceObject);
break; break;
case 'tester_updateResourceObjectAssetType': case 'tester_updateResourceObjectAssetType':
@ -1029,16 +1063,20 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
}; };
function pushResourceObjectsInTest() { function pushResourceObjectsInTest() {
var maxObjectId = -1; var maxResourceObjectId = -1;
for (var objectId in resourceObjectsInTest) { var length = resourceObjectsInTest.length;
signalNewResourceObjectInTest(resourceObjectsInTest[objectId]); for (var i = 0; i < length; i++) {
maxObjectId = (maxObjectId < objectId) ? parseInt(objectId) : maxObjectId; if (i in resourceObjectsInTest) {
signalNewResourceObjectInTest(resourceObjectsInTest[i]);
var resourceObjectId = resourceObjectsInTest[i].resourceObjectId;
maxResourceObjectId = (maxResourceObjectId < resourceObjectId) ? parseInt(resourceObjectId) : maxResourceObjectId;
}
} }
// N.B. Thinking about removing the following sendToQml? Be sure // N.B. Thinking about removing the following sendToQml? Be sure
// that the marketplace item tester QML has heard from us, at least // that the marketplace item tester QML has heard from us, at least
// so that it can indicate to the user that all of the resoruce // so that it can indicate to the user that all of the resoruce
// objects in test have been transmitted to it. // objects in test have been transmitted to it.
ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxObjectId + 1 }); ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 });
} }
// Function Name: onTabletScreenChanged() // Function Name: onTabletScreenChanged()
@ -1127,6 +1165,7 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) {
// variable amount of time to come up, in practice less than // variable amount of time to come up, in practice less than
// 750ms. // 750ms.
Script.setTimeout(pushResourceObjectsInTest, 750); Script.setTimeout(pushResourceObjectsInTest, 750);
Script.setTimeout(pushResourceRequestEvents, 750);
} }
console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type +
@ -1193,6 +1232,7 @@ function startup() {
ui.tablet.webEventReceived.connect(onWebEventReceived); ui.tablet.webEventReceived.connect(onWebEventReceived);
Wallet.walletStatusChanged.connect(sendCommerceSettings); Wallet.walletStatusChanged.connect(sendCommerceSettings);
Window.messageBoxClosed.connect(onMessageBoxClosed); Window.messageBoxClosed.connect(onMessageBoxClosed);
ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent);
Wallet.refreshWalletStatus(); Wallet.refreshWalletStatus();
} }
@ -1226,6 +1266,7 @@ function shutdown() {
GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); GlobalServices.myUsernameChanged.disconnect(onUsernameChanged);
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
ContextOverlay.contextOverlayClicked.disconnect(openInspectionCertificateQML); ContextOverlay.contextOverlayClicked.disconnect(openInspectionCertificateQML);
ResourceRequestObserver.resourceRequestEvent.disconnect(onResourceRequestEvent);
off(); off();
} }