From e5b5778caf2ba2e9b80edd17e25ed4a414211359 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Mar 2014 15:04:22 -0700 Subject: [PATCH] Upload FST --- libraries/shared/src/AccountManager.cpp | 31 ++++-- libraries/shared/src/AccountManager.h | 7 +- libraries/shared/src/FstReader.cpp | 141 +++++++++++++++++------- libraries/shared/src/FstReader.h | 26 ++--- 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 7915a60690..6517d080ed 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "NodeList.h" #include "PacketHeaders.h" @@ -30,6 +31,7 @@ Q_DECLARE_METATYPE(OAuthAccessToken) Q_DECLARE_METATYPE(DataServerAccountInfo) Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) Q_DECLARE_METATYPE(JSONCallbackParameters) +Q_DECLARE_METATYPE(QHttpMultiPart) const QString ACCOUNTS_GROUP = "accounts"; @@ -99,21 +101,25 @@ void AccountManager::setAuthURL(const QUrl& authURL) { } void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart) { QMetaObject::invokeMethod(this, "invokedRequest", Q_ARG(const QString&, path), Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(const JSONCallbackParameters&, callbackParams), - Q_ARG(const QByteArray&, dataByteArray)); + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart)); } void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { - + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { + if (!_networkAccessManager) { _networkAccessManager = new QNetworkAccessManager(this); } - + if (hasValidAccessToken()) { QNetworkRequest authenticatedRequest; @@ -140,11 +146,18 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::PutOperation: authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + if (dataMultiPart) { + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); + } } else { - networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + } } break; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index ee821fa43c..bfe84f392e 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -39,7 +39,8 @@ public: void authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), - const QByteArray& dataByteArray = QByteArray()); + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -77,7 +78,9 @@ private: void operator=(AccountManager const& other); // not implemented Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray); + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart); QUrl _authURL; QNetworkAccessManager* _networkAccessManager; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index d94f036af0..0e99a7b2f4 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -10,15 +10,38 @@ #include #include #include -#include #include #include +#include +#include + +#include "AccountManager.h" #include "FstReader.h" -FstReader::FstReader() { + +static const QString NAME_FIELD = "name"; +static const QString FILENAME_FIELD = "filename"; +static const QString TEXDIR_FIELD = "texdir"; +static const QString LOD_FIELD = "lod"; + +static const QString MODEL_URL = "/api/v1/models"; + +static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB + +FstReader::FstReader() : + _lodCount(-1), + _texturesCount(-1), + _readyToSend(false), + _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) +{ } +FstReader::~FstReader() { + if (_dataMultiPart) { + delete _dataMultiPart; + } +} bool FstReader::zip() { // File Dialog @@ -33,11 +56,18 @@ bool FstReader::zip() { qDebug() << "[ERROR] Could not open FST file : " << fst.fileName(); return false; } + + // Compress and copy the fst + if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { + return false; + } + _totalSize += QFileInfo(fst).size(); + if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), + QString("fst"))) { + return false; + } qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); - - QDir rootDir(_zipDir.path()); - // Let's read through the FST file QTextStream stream(&fst); QList line; @@ -47,20 +77,34 @@ bool FstReader::zip() { continue; } + if (_totalSize > MAX_SIZE) { + qDebug() << "[ERROR] Model too big, over " << MAX_SIZE << " Bytes."; + return false; + } + // according to what is read, we modify the command - if (line.first() == nameField) { - _modelName = line[1]; - } else if (line.first() == filenameField) { + if (line.first() == NAME_FIELD) { + QHttpPart textPart; + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"model_name\""); + //textPart.setRawHeader("name", "\"model_name\""); + textPart.setBody(line[1].toUtf8()); + _dataMultiPart->append(textPart); + } else if (line.first() == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " doesn't exist."; return false; - } else { // Compress and copy - _fbxFile = rootDir.path() + "/" + line[1]; - _totalSize += fbx.size(); - compressFile(fbx.filePath(), _fbxFile); } - } else if (line.first() == texdirField) { // Check existence + // Compress and copy + if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += fbx.size(); + if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { + return false; + } + } else if (line.first() == TEXDIR_FIELD) { // Check existence QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { qDebug() << "[ERROR] Texture directory " << texdir.absolutePath() << " doesn't exist."; @@ -69,47 +113,41 @@ bool FstReader::zip() { if (!addTextures(texdir)) { // Recursive compress and copy return false; } - } else if (line.first() == lodField) { + } else if (line.first() == LOD_FIELD) { QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " doesn't exist."; - //return false; - } else { // Compress and copy - _lodFiles.push_back(rootDir.path() + "/" + line[1]); - _totalSize += lod.size(); - compressFile(lod.filePath(), _lodFiles.back()); + return false; + } + // Compress and copy + if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += lod.size(); + if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { + return false; } } } - // Compress and copy the fst - _fstFile = rootDir.path() + "/" + QFileInfo(fst).fileName(); - _totalSize += QFileInfo(fst).size(); - compressFile(fst.fileName(), _fstFile); - + _readyToSend = true; return true; } bool FstReader::send() { - QString command = QString("curl -F \"model_name=%1\"").arg(_modelName); - - command += QString(" -F \"fst=@%1\" -F \"fbx=@%2\"").arg(_fstFile, _fbxFile); - for (int i = 0; i < _lodFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_lodFiles[i]); + if (!_readyToSend) { + return false; } - for (int i = 0; i < _textureFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_textureFiles[i]); - } - command += " http://localhost:3000/api/v1/models/?access_token\\=017894b7312316a2b5025613fcc58c13bc701da9b797cca34b60aae9d1c53acb --trace-ascii /dev/stdout"; - qDebug() << "[DEBUG] " << command; + AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + _dataMultiPart = NULL; return true; } -bool FstReader::addTextures(QFileInfo& texdir) { +bool FstReader::addTextures(const QFileInfo& texdir) { QStringList filter; - filter << "*.png" << "*.tiff" << "*.jpg" << "*.jpeg"; + filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; QFileInfoList list = QDir(texdir.filePath()).entryInfoList(filter, QDir::Files | @@ -118,9 +156,15 @@ bool FstReader::addTextures(QFileInfo& texdir) { QDir::NoSymLinks); foreach (QFileInfo info, list) { if (info.isFile()) { - _textureFiles.push_back(_zipDir.path() + "/" + info.fileName()); + // Compress and copy + if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { + return false; + } _totalSize += info.size(); - compressFile(info.canonicalFilePath(), _textureFiles.back()); + if (!addPart(_zipDir.path() + "/" + info.fileName(), + QString("texture%1").arg(++_texturesCount))) { + return false; + } } else if (info.isDir()) { if (!addTextures(info)) { return false; @@ -153,7 +197,26 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa } - +bool FstReader::addPart(const QString &path, const QString& name) { + QFile* file = new QFile(path); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << "[ERROR] Couldn't open " << file->fileName(); + return false; + } + + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"" + name.toUtf8() + "\";" + " filename=\"" + QFileInfo(*file).fileName().toUtf8() + "\""); + part.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); + part.setBodyDevice(file); + _dataMultiPart->append(part); + file->setParent(_dataMultiPart); + + qDebug() << QFileInfo(*file).fileName().toUtf8(); + + return true; +} diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index c5816ea415..aab42bd967 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -10,39 +10,31 @@ #ifndef __hifi__FstReader__ #define __hifi__FstReader__ -#include -#include #include - -static const QString nameField = "name"; -static const QString filenameField = "filename"; -static const QString texdirField = "texdir"; -static const QString lodField = "lod"; - -static const int MAX_SIZE = 1024 * 1024; // 1 MB +class QHttpMultiPart; class FstReader { public: FstReader(); + ~FstReader(); bool zip(); bool send(); private: QTemporaryDir _zipDir; - - QString _modelName; - QString _fstFile; - QString _fbxFile; - QStringList _lodFiles; - QStringList _textureFiles; - + int _lodCount; + int _texturesCount; int _totalSize; + bool _readyToSend; + + QHttpMultiPart* _dataMultiPart; - bool addTextures(QFileInfo& texdir); + bool addTextures(const QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); + bool addPart(const QString& path, const QString& name); }; #endif /* defined(__hifi__FstReader__) */