#include "PhoenixServicesClient.h" #include <QDebug> #include <QByteArray> #include <QJsonDocument> #include <QJsonObject> #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> #include <phoenix.h> #include <QtCore/qjsondocument.h> namespace phoenix { typedef QSharedPointer<QNetworkRequest> QNetworkRequestPtr; typedef QSharedPointer<QByteArray> QByteArrayPtr; // It's expected that the default server setup will point a hostname to our // web services application. // // This might be lame for some development environments, that typically // don't have much control over their local DNS settings, so this can be // configured, but I don't expect it to be used in production. QString DEFAULT_PHOENIX_PREFIX_PATH = "/p4_phoenix_services/v1"; class PhoenixServicesClient::Impl : public QObject { Q_OBJECT public: Impl(PhoenixServicesClient *parent) : mClient(parent), mManager(parent), mUrl("http://example.com"), mSession(nullptr), mPhoenixPrefixPath(DEFAULT_PHOENIX_PREFIX_PATH) { } QNetworkRequestPtr createRequest() { QNetworkRequestPtr request = QNetworkRequestPtr::create(); request->setRawHeader("User-Agent", (QString("p4_phoenix_services ") + phoenix::kMajorVersion + "." + phoenix::kMinorVersion + "." + phoenix::kPatchVersion).toUtf8()); request->setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request->setRawHeader("Accept", "application/json"); return request; } // Configures the url on the path with the indicated final path part. // The path should not be encoded. // // Note: will not set the query parameter. void setRequestUrlWithPath(QNetworkRequestPtr request, QString path) { QUrl url(mUrl); QString fullPath(mPhoenixPrefixPath); fullPath += path; url.setPath(fullPath); qDebug() << "setting request url " << url; request->setUrl(url); } QByteArray createSessionPostBody(const QString & user, const QString & password) { QJsonObject obj; obj["user"] = user; obj["password"] = password; QJsonDocument doc(obj); return doc.toJson(QJsonDocument::JsonFormat::Compact); } void logInFinished(QNetworkReply *reply, const QString & user); public slots: void handleLogInError(QNetworkReply::NetworkError code); void handleLogInSslErrors(const QList<QSslError> & errors); void fetchProjectsFinished(); void fetchProjectsError(QNetworkReply::NetworkError code); void fetchProjectsSslErrors(const QList<QSslError> & errors); void fetchProjectFinished(); void fetchProjectError(QNetworkReply::NetworkError code); void fetchProjectSslErrors(const QList<QSslError> & errors); void createProjectFinished(); void createProjectError(QNetworkReply::NetworkError code); void createProjectSslErrors(const QList<QSslError> & errors); // Member state public: PhoenixServicesClient *mClient; QNetworkAccessManager mManager; QUrl mUrl; SessionPtr mSession; QString mPhoenixPrefixPath; }; void PhoenixServicesClient::Impl::logInFinished(QNetworkReply *reply, const QString & user) { if (reply->isFinished() && reply->error() == QNetworkReply::NetworkError::NoError) { QByteArray data = reply->readAll(); RequestErrorPtr error = parseRequestError(data); SessionPtr session; if (!error) { QJsonDocument doc; QJsonParseError err; doc = doc.fromJson(data, &err); if (err.error == QJsonParseError::NoError) { auto object = doc.object(); if (object.contains("token") && object.contains("p4Ticket")) { QString token = object["token"].toString(); QString p4Ticket = object["p4Ticket"].toString(); session.reset(new Session); session->setUrl(mUrl); session->setUser(user); session->setToken(token); session->setP4Ticket(p4Ticket); mClient->setSession(*session); } } } if (!session) { QString msg = QString("Unable to create session from JSON data: %1").arg(QString(data)); error.reset(new RequestError(msg, msg, RequestError::JSON_ERROR, RequestError::ERROR)); } emit mClient->logInDone(error, session); } } void PhoenixServicesClient::Impl::handleLogInError( QNetworkReply::NetworkError code) { RequestErrorPtr error(new RequestError()); // TODO covert the network error to something nice QString msg = QString("Network Error %1").arg(code); error->setMessageText(msg); error->setBaseMessageText(msg); error->setCode(RequestError::NETWORK_ERROR); error->setSeverity(RequestError::ERROR); emit mClient->logInDone(error, SessionPtr()); }; void PhoenixServicesClient::Impl::handleLogInSslErrors( const QList<QSslError> & errors) { RequestErrorPtr error(new RequestError()); // TODO convert the errors array to messages error->setMessageText("SSL Error"); error->setBaseMessageText("SSL Error"); error->setCode(RequestError::SSL_ERROR); error->setSeverity(RequestError::ERROR); emit mClient->logInDone(error, SessionPtr()); } void PhoenixServicesClient::Impl::fetchProjectsFinished() { } void PhoenixServicesClient::Impl::fetchProjectsError( QNetworkReply::NetworkError code) { } void PhoenixServicesClient::Impl::fetchProjectsSslErrors( const QList<QSslError> & errors) { } void PhoenixServicesClient::Impl::fetchProjectFinished() { } void PhoenixServicesClient::Impl::fetchProjectError( QNetworkReply::NetworkError code) { } void PhoenixServicesClient::Impl::fetchProjectSslErrors( const QList<QSslError> & errors) { } void PhoenixServicesClient::Impl::createProjectFinished() { } void PhoenixServicesClient::Impl::createProjectError( QNetworkReply::NetworkError code) { } void PhoenixServicesClient::Impl::createProjectSslErrors( const QList<QSslError> & errors) { } PhoenixServicesClient::PhoenixServicesClient() : mImpl(new Impl(this)) { } PhoenixServicesClient::~PhoenixServicesClient() { delete mImpl; } void PhoenixServicesClient::setUrl(const QUrl & url) { mImpl->mUrl = url; } const QUrl & PhoenixServicesClient::url() const { return mImpl->mUrl; } bool PhoenixServicesClient::hasSession() const { return mImpl->mSession.isNull() == false; } const Session & PhoenixServicesClient::session() const { return *(mImpl->mSession); } void PhoenixServicesClient::setSession(const Session & session) { mImpl->mSession.reset(new Session(session)); } const QString & PhoenixServicesClient::phoenixPrefixPath() const { return mImpl->mPhoenixPrefixPath; } void PhoenixServicesClient::setPhoenixPrefixPath(const QString & path) { mImpl->mPhoenixPrefixPath = path; } void PhoenixServicesClient::logIn(const QString & user, const QString & password) { QNetworkRequestPtr request = mImpl->createRequest(); // set the right url... mImpl->setRequestUrlWithPath(request, "/sessions"); QByteArray data = mImpl->createSessionPostBody(user, password); QNetworkReply *reply = mImpl->mManager.post(*request, data); connect(reply, &QNetworkReply::finished, [=]() { mImpl->logInFinished(reply, user); }); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), mImpl, SLOT(handleLogInError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors( const QList<QSslError> &)), mImpl, SLOT(handleLogInSslErrors( const QList<QSslError> &))); } void PhoenixServicesClient::fetchProjects() { QNetworkRequestPtr request = mImpl->createRequest(); mImpl->setRequestUrlWithPath(request, "/projects"); QNetworkReply *reply = mImpl->mManager.get(*request); connect(reply, SIGNAL(finished()), mImpl, SLOT(fetchProjectsFinished())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), mImpl, SLOT(fetchProjectsError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors( const QList<QSslError> &)), mImpl, SLOT(fetchProjectsSslErrors( const QList<QSslError> &))); } void PhoenixServicesClient::fetchProject(const QString & id) { QNetworkRequestPtr request = mImpl->createRequest(); // setRequestUrlWithPath will pass this on to a URL, which will handle // appropriate path encoding. QString path = QString("/projects/%1").arg(id); mImpl->setRequestUrlWithPath(request, path); QNetworkReply *reply = mImpl->mManager.get(*request); connect(reply, SIGNAL(finished()), mImpl, SLOT(fetchProjectFinished())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), mImpl, SLOT(fetchProjectError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors( const QList<QSslError> &)), mImpl, SLOT(fetchProjectSslErrors( const QList<QSslError> &))); } void PhoenixServicesClient::createProject(const PhoenixProject & project) { QNetworkRequestPtr request = mImpl->createRequest(); mImpl->setRequestUrlWithPath(request, "/projects"); QByteArray data = project.project() .document() .toJson(QJsonDocument::JsonFormat::Compact); QNetworkReply *reply = mImpl->mManager.post(*request, data); connect(reply, SIGNAL(finished()), mImpl, SLOT(createProjectFinished())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), mImpl, SLOT(createProjectError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(sslErrors( const QList<QSslError> &)), mImpl, SLOT(createProjectSslErrors( const QList<QSslError> &))); } } #include "PhoenixServicesClient.moc"
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#18 | 14025 | tjuricek |
Revise Qt SDK to a single 'helix_web_services_client' project. Most references to "Phoenix" have now been removed. Additionally, this is more similar to the other platform client SDKs in Ruby and JavaScript. Documentation via Doxygen is now available, and will be how much of the SDK reference should occur. |
||
#17 | 13941 | tjuricek |
Re-implemented the sync project methods at the HTTP level. The Qt API is missing the "members" concept, but it's likely not quite usable just yet. It's existing logic does work, however. |
||
#16 | 13532 | tjuricek |
Qt SDK: Add constructor that uses an application's QSettings for caching Sessions for each URL Added a simple validateSession remote call to ping the services instance to see if the session is indeed usable. Also, removing puma configuraiton that is automatically generated in the (shared) development instance. |
||
#15 | 13530 | tjuricek |
Add p4_phoenix_services package and Salt configuration for deployment. This uncovered a couple of issues from the C++ API during it's conversion to C++03. So, in a nutshell, most operations, except for notifications, appear to be working (well, using Vagrant machines). |
||
#14 | 13510 | tjuricek |
Convert version information to macros to get around unused variable warnings that some people want to use to fail builds. Also, fixed an actual reorder issue, and enabled '-Wall' on the cmake config. |
||
#13 | 13508 | tjuricek | Replace use of C++11 'nullptr' with NULL | ||
#12 | 13506 | tjuricek |
Change to a C++03 build. Major changes: 1. QSharedPointer::create(...) is much more restricted than in C++11, so just use the .reset() method unless you're passing in a single const reference argument to the constructor. 2. Using Qt's foreach. 3. Replace lambdas with simpler helper methods. This seems to work, but we may have subtle memory issues I'm not 100% on top of yet. |
||
#11 | 13497 | tjuricek | Follow QObject memory management conventions for the PhoenixServicesClient. | ||
#10 | 13471 | tjuricek |
Define some JSON messages for Qt API's websocket interaction. Not tested... yet. |
||
#9 | 13470 | tjuricek |
Phoenix notification services, client API, including new phoenix_updater This is an interim commit containing a first pass implementation of the phoenix_updater. Notably missing parts: - The Qt API doesn't yet actually interact with the phoenix_updater - The phoenix_services web service doesn't filter out notifications I *may* end up creating another web application *just* to filter out notifications, since this may end up taking up a lot of background workers. |
||
#8 | 13460 | tjuricek |
Call out authentication problems with a specific application error code. This allows Qt clients to easily know when they should recreate a new session. |
||
#7 | 13459 | tjuricek |
Return the created project when creating a new project, since default values will often be filled out. Allow new projects to be created only with names set. We'll generate an ID at the moment, when I have better indexing, I'll double check for uniqueness. |
||
#6 | 13455 | tjuricek | Basic Phoenix project metadata (the project name) can now be created and read back. | ||
#5 | 13454 | tjuricek |
First cut at SDK implementation of the Create-Read lifecycle of Phoenix projects. (Bugs on the server side may be the issue, we'll see. TBD.) |
||
#4 | 13452 | tjuricek | Normalize header includes and preliminary implementation of the Project-related methods of the PhoenixServicesClient. | ||
#3 | 13451 | tjuricek | Setup common error handling callbacks for most of the first operations. | ||
#2 | 13449 | tjuricek | Adjusting the User-Agent string which gets rejected by Unicorn. | ||
#1 | 13443 | tjuricek |
Reorganized the Qt libraries into a separate part of the tree, to make it easier for CMake configuration. Added 'qt_build' and 'qt_test' tasks to at least execute tests and fail the build if they don't pass. Started the implementation of the project library interaction. Change: 1018651 Date: 3/4/15 11:43 AM Client: tjuricek_dhcp-141-n100_5959 User: tjuricek Status: pending Type: public Description: Reorganized the Qt libraries into a separate part of the tree, to make it easier for CMake configuration. Added 'qt_build' and 'qt_test' tasks to at least execute tests and fail the build if they don't pass. Started the implementation of the project library interaction. JobStatus: Jobs: Files: //web-services/p4ws-main/Rakefile //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/CMakeLists.txt //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/PhoenixIntegrationTests.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/README //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/PhoenixProject.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/PhoenixProject.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/PhoenixServicesClient.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/PhoenixServicesClient.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/RequestError.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/RequestError.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/Session.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/phoenix/Session.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/test/PhoenixServicesClientTests.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/test/PhoenixServicesClientTests.h //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/test/SessionTests.cpp //web-services/p4ws-main/p4_phoenix_services/clients/qt/p4_phoenix_services_client/test/SessionTests.h //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/CMakeLists.txt //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services.h //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/Branch.cpp //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/Branch.h //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/Project.cpp //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/Project.h //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/View.cpp //web-services/p4ws-main/p4_project_services/clients/qt/p4_project_services_client/p4_project_services/View.h //web-services/p4ws-main/qt/CMakeLists.txt //web-services/p4ws-main/qt/p4_phoenix_services_client/CMakeLists.txt //web-services/p4ws-main/qt/p4_phoenix_services_client/PhoenixIntegrationTests.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/README //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix.h //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/PhoenixProject.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/PhoenixProject.h //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/PhoenixServicesClient.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/PhoenixServicesClient.h //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/RequestError.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/RequestError.h //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/Session.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/phoenix/Session.h //web-services/p4ws-main/qt/p4_phoenix_services_client/test/PhoenixServicesClientTests.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/test/PhoenixServicesClientTests.h //web-services/p4ws-main/qt/p4_phoenix_services_client/test/SessionTests.cpp //web-services/p4ws-main/qt/p4_phoenix_services_client/test/SessionTests.h //web-services/p4ws-main/qt/p4_project_services_client/CMakeLists.txt //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeCache.txt //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CMakeCCompiler.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CMakeCXXCompiler.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CMakeDetermineCompilerABI_C.bin //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CMakeDetermineCompilerABI_CXX.bin //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CMakeSystem.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CompilerIdC/CMakeCCompilerId.c //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CompilerIdC/a.out //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CompilerIdCXX/CMakeCXXCompilerId.cpp //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/2.8.12/CompilerIdCXX/a.out //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/CMakeDirectoryInformation.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/CMakeOutput.log //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/Makefile.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/Makefile2 //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/TargetDirectories.txt //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/cmake.check_cache //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/DependInfo.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/build.make //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/cmake_clean.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/cmake_clean_target.cmake //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/depend.make //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/flags.make //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/link.txt //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/p4_project_services_client.dir/progress.make //web-services/p4ws-main/qt/p4_project_services_client/build/CMakeFiles/progress.marks //web-services/p4ws-main/qt/p4_project_services_client/build/Makefile //web-services/p4ws-main/qt/p4_project_services_client/build/cmake_install.cmake //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services.h //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/Branch.cpp //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/Branch.h //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/Project.cpp //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/Project.h //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/View.cpp //web-services/p4ws-main/qt/p4_project_services_client/p4_project_services/View.h |