##// END OF EJS Templates
Merge branch 'feature/NetworkController2' into develop
perrinel -
r390:1d8a5cf19c4c merge
parent child
Show More
@@ -1,153 +1,153
1 1
2 2 ## core - CMakeLists.txt
3 3 STRING(TOLOWER ${CMAKE_PROJECT_NAME} LIBRARY_PREFFIX)
4 4 SET(SQPCORE_LIBRARY_NAME "${LIBRARY_PREFFIX}_core${DEBUG_SUFFIX}")
5 5 SET(SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/")
6 6 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/")
7 7
8 8 # Include core directory
9 9 include_directories("${INCLUDES_DIR}")
10 10
11 11 # Set a variable to display a warning in the version files.
12 12 SET(SCIQLOP_CMAKE_GENERATION_WARNING "DON'T CHANGE THIS FILE. AUTOGENERATED BY CMAKE.")
13 13 # Generate the version file from the cmake version variables. The version
14 14 # variables are defined in the cmake/sciqlop_version.cmake file.
15 15 CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/resources/Version.h.in"
16 16 "${INCLUDES_DIR}/Version.h")
17 17 CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/resources/Version.cpp.in"
18 18 "${SOURCES_DIR}/Version.cpp")
19 19
20 20 # Find dependent modules
21 21 find_package(sciqlop-plugin)
22 22 INCLUDE_DIRECTORIES(${SCIQLOP-PLUGIN_INCLUDE_DIR})
23 23
24 24 #
25 25 # Find Qt modules
26 26 #
27 SCIQLOP_FIND_QT(Core)
27 SCIQLOP_FIND_QT(Core Network)
28 28
29 29 #
30 30 # Compile the library library
31 31 #
32 32 FILE (GLOB_RECURSE MODULE_SOURCES
33 33 ${INCLUDES_DIR}/*.h
34 34 ${SOURCES_DIR}/*.c
35 35 ${SOURCES_DIR}/*.cpp
36 36 ${SOURCES_DIR}/*.h)
37 37
38 38 ADD_LIBRARY(${SQPCORE_LIBRARY_NAME} ${MODULE_SOURCES})
39 39 set_property(TARGET ${SQPCORE_LIBRARY_NAME} PROPERTY CXX_STANDARD 14)
40 40 set_property(TARGET ${SQPCORE_LIBRARY_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
41 41 TARGET_LINK_LIBRARIES(${SQPCORE_LIBRARY_NAME})
42 qt5_use_modules(${SQPCORE_LIBRARY_NAME} Core)
42 qt5_use_modules(${SQPCORE_LIBRARY_NAME} Core Network)
43 43
44 44 INSTALL(TARGETS ${SQPCORE_LIBRARY_NAME}
45 45 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
46 46 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
47 47 ARCHIVE DESTINATION ${INSTALL_LIBRARY_DIR}
48 48 )
49 49
50 50 # From cmake documentation: http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
51 51 # Entries in the COMPILE_DEFINITIONS are prefixed with -D or /D and added to the compile line in an unspecified order.
52 52 # The DEFINE_SYMBOL target property is also added as a compile definition as a special convenience case for SHARED and MODULE library targets
53 53 IF(BUILD_SHARED_LIBS)
54 54 SET_TARGET_PROPERTIES(${SQPCORE_LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS "SCIQLOP_EXPORT")
55 55 ELSE()
56 56 TARGET_COMPILE_DEFINITIONS(${SQPCORE_LIBRARY_NAME} PUBLIC "SCIQLOP_STATIC_LIBRARIES")
57 57 ENDIF()
58 58
59 59 # Set the variable to parent scope so that the other projects can copy the
60 60 # dependent shared libraries
61 61 SCIQLOP_SET_TO_PARENT_SCOPE(SQPCORE_LIBRARY_NAME)
62 62
63 63 # Copy extern shared libraries to the lib folder
64 64 SCIQLOP_COPY_TO_TARGET(LIBRARY ${SQPCORE_LIBRARY_NAME} ${EXTERN_SHARED_LIBRARIES})
65 65
66 66 # Add the files to the list of files to be analyzed
67 67 LIST(APPEND CHECKSTYLE_INPUT_FILES ${MODULE_SOURCES})
68 68 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
69 69 # Vera++ exclusion files
70 70 LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
71 71 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
72 72
73 73 #
74 74 # Compile the tests
75 75 #
76 76 IF(BUILD_TESTS)
77 77 INCLUDE_DIRECTORIES(${SOURCES_DIR})
78 78 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
79 79 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
80 80 SET( TEST_LIBRARIES ${SQPCORE_LIBRARY_NAME})
81 81
82 82 SET(TARGETS_COV)
83 83 FOREACH( testFile ${TESTS_SOURCES} )
84 84 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
85 85 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
86 86
87 87 # Add to the list of sources files all the sources in the same
88 88 # directory that aren't another test
89 89 FILE (GLOB currentTestSources
90 90 ${testDirectory}/*.c
91 91 ${testDirectory}/*.cpp
92 92 ${testDirectory}/*.h)
93 93 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
94 94 # LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
95 95
96 96 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
97 97 set_property(TARGET ${testName} PROPERTY CXX_STANDARD 14)
98 98 set_property(TARGET ${testName} PROPERTY CXX_STANDARD_REQUIRED ON)
99 99 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES} )
100 100 qt5_use_modules(${testName} Test)
101 101
102 102 ADD_TEST( NAME ${testName} COMMAND ${testName} )
103 103
104 104 SCIQLOP_COPY_TO_TARGET(RUNTIME ${testName} ${EXTERN_SHARED_LIBRARIES})
105 105 set(Coverage_NAME ${testName})
106 106 if(UNIX)
107 107 SETUP_TARGET_FOR_COVERAGE(TARGET ${testName}_coverage OUTPUT ${testFile}-path NAME ${testFile} EXECUTABLE ${testName})
108 108 LIST( APPEND TARGETS_COV ${testName}_coverage)
109 109 endif(UNIX)
110 110
111 111 ENDFOREACH( testFile )
112 112
113 113 add_custom_target(coverage)
114 114
115 115 FOREACH( target_cov ${TARGETS_COV} )
116 116 add_custom_command(TARGET coverage PRE_BUILD COMMAND make ${target_cov})
117 117 ENDFOREACH( target_cov )
118 118
119 119 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
120 120 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
121 121 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
122 122 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
123 123 ENDIF(BUILD_TESTS)
124 124
125 125 #
126 126 # Set the files that must be formatted by clang-format.
127 127 #
128 128 LIST (APPEND FORMATTING_INPUT_FILES ${MODULE_SOURCES})
129 129 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
130 130
131 131 #
132 132 # Set the directories that doxygen must browse to generate the
133 133 # documentation.
134 134 #
135 135 # Source directories:
136 136 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
137 137 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
138 138 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
139 139 # Source directories to exclude from the documentation generation
140 140 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
141 141 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
142 142
143 143 #
144 144 # Set the directories with the sources to analyze and propagate the
145 145 # modification to the parent scope
146 146 #
147 147 # Source directories to analyze:
148 148 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
149 149 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
150 150 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
151 151 # Source directories to exclude from the analysis
152 152 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
153 153 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -1,40 +1,60
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include <memory>
5 5
6 6 #include <QObject>
7 7 #include <QUuid>
8 8
9 9 #include <Common/MetaTypes.h>
10 10
11 11 #include <Data/SqpDateTime.h>
12 12
13 13 class DataProviderParameters;
14 14 class IDataSeries;
15 class QNetworkReply;
16 class QNetworkRequest;
15 17
16 18 /**
17 19 * @brief The IDataProvider interface aims to declare a data provider.
18 20 *
19 21 * A data provider is an entity that generates data and returns it according to various parameters
20 22 * (time interval, product to retrieve the data, etc.)
21 23 *
22 24 * @sa IDataSeries
23 25 */
24 26 class IDataProvider : public QObject {
25 27
26 28 Q_OBJECT
27 29 public:
28 30 virtual ~IDataProvider() noexcept = default;
29 31
30 virtual void requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList) = 0;
32 /**
33 * @brief requestDataLoading provide datas for the data identified by identifier for all
34 * SqpDateTime of dateTimeList
35 */
36 virtual void requestDataLoading(QUuid identifier, const QVector<SqpDateTime> &dateTimeList) = 0;
31 37
32 38 signals:
33 void dataProvided(QUuid token, std::shared_ptr<IDataSeries> dateSerie,
39 /**
40 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
41 * identified by identifier
42 */
43 void dataProvided(QUuid identifier, std::shared_ptr<IDataSeries> dateSerie,
34 44 const SqpDateTime &dateTime);
45
46
47 /**
48 * @brief requestConstructed send a request for the data identified by identifier
49 * @callback is the methode call by the reply of the request when it is finished.
50 */
51 void requestConstructed(const QNetworkRequest &request, QUuid identifier,
52 std::function<void(QNetworkReply *, QUuid)> callback);
35 53 };
36 54
37 55 // Required for using shared_ptr in signals/slots
38 56 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
57 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
58 std::function<void(QNetworkReply *, QUuid)>)
39 59
40 60 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,30 +1,43
1 1 #ifndef SCIQLOP_NETWORKCONTROLLER_H
2 2 #define SCIQLOP_NETWORKCONTROLLER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QObject>
6 #include <QUuid>
6 7
7 8 #include <Common/spimpl.h>
9 #include <functional>
8 10
9 11 Q_DECLARE_LOGGING_CATEGORY(LOG_NetworkController)
10 12
13 class QNetworkReply;
14 class QNetworkRequest;
15
11 16 /**
12 17 * @brief The NetworkController class aims to handle all network connection of SciQlop.
13 18 */
14 19 class NetworkController : public QObject {
15 20 Q_OBJECT
16 21 public:
17 22 explicit NetworkController(QObject *parent = 0);
18 23
19
20 24 void initialize();
21 25 void finalize();
22 26
27 public slots:
28 void onProcessRequested(const QNetworkRequest &request, QUuid identifier,
29 std::function<void(QNetworkReply *, QUuid)> callback);
30 void onReplyCanceled(QUuid identifier);
31
32 signals:
33 void replyFinished(QNetworkReply *reply, QUuid identifier);
34 void replyDownloadProgress(QUuid identifier);
35
23 36 private:
24 37 void waitForFinish();
25 38
26 39 class NetworkControllerPrivate;
27 40 spimpl::unique_impl_ptr<NetworkControllerPrivate> impl;
28 41 };
29 42
30 43 #endif // SCIQLOP_NETWORKCONTROLLER_H
@@ -1,33 +1,88
1 1 #include "Network/NetworkController.h"
2 2
3 3 #include <QMutex>
4 #include <QNetworkAccessManager>
5 #include <QNetworkReply>
6 #include <QNetworkRequest>
4 7 #include <QThread>
5 8
9 #include <unordered_map>
10
6 11 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
7 12
8 13 struct NetworkController::NetworkControllerPrivate {
9 14 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
10 15 QMutex m_WorkingMutex;
16
17 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
18 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
11 19 };
12 20
13 21 NetworkController::NetworkController(QObject *parent)
14 22 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
15 23 {
16 24 }
17 25
26 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
27 std::function<void(QNetworkReply *, QUuid)> callback)
28 {
29 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
30 << QThread::currentThread();
31 auto reply = impl->m_AccessManager->get(request);
32
33 // Store the couple reply id
34 impl->m_NetworkReplyToVariableId[reply] = identifier;
35
36 auto onReplyFinished = [reply, this, identifier, callback]() {
37
38 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
39 << QThread::currentThread();
40 auto it = impl->m_NetworkReplyToVariableId.find(reply);
41 if (it != impl->m_NetworkReplyToVariableId.cend()) {
42 callback(reply, identifier);
43 }
44 };
45
46 auto onReplyDownloadProgress = [reply, this]() {
47
48 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyDownloadProgress")
49 << QThread::currentThread();
50 auto it = impl->m_NetworkReplyToVariableId.find(reply);
51 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 emit this->replyDownloadProgress(it->second);
53 }
54 };
55
56
57 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
58 connect(reply, &QNetworkReply::downloadProgress, this, onReplyDownloadProgress);
59 }
60
18 61 void NetworkController::initialize()
19 62 {
20 63 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
21 64 impl->m_WorkingMutex.lock();
65 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
22 66 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
23 67 }
24 68
25 69 void NetworkController::finalize()
26 70 {
27 71 impl->m_WorkingMutex.unlock();
28 72 }
29 73
74 void NetworkController::onReplyCanceled(QUuid identifier)
75 {
76 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
77
78 auto end = impl->m_NetworkReplyToVariableId.cend();
79 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
80 if (it != end) {
81 it->first->abort();
82 }
83 }
84
30 85 void NetworkController::waitForFinish()
31 86 {
32 87 QMutexLocker locker{&impl->m_WorkingMutex};
33 88 }
@@ -1,205 +1,205
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QUuid>
15 15 #include <QtCore/QItemSelectionModel>
16 16
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20 20
21 21 struct VariableController::VariableControllerPrivate {
22 22 explicit VariableControllerPrivate(VariableController *parent)
23 23 : m_WorkingMutex{},
24 24 m_VariableModel{new VariableModel{parent}},
25 25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 27 {
28 28 }
29 29
30 30 QMutex m_WorkingMutex;
31 31 /// Variable model. The VariableController has the ownership
32 32 VariableModel *m_VariableModel;
33 33 QItemSelectionModel *m_VariableSelectionModel;
34 34
35 35
36 36 TimeController *m_TimeController{nullptr};
37 37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38 38
39 39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 40 m_VariableToProviderMap;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToToken;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifier;
42 42 };
43 43
44 44 VariableController::VariableController(QObject *parent)
45 45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 46 {
47 47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 48 << QThread::currentThread();
49 49 }
50 50
51 51 VariableController::~VariableController()
52 52 {
53 53 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
54 54 << QThread::currentThread();
55 55 this->waitForFinish();
56 56 }
57 57
58 58 VariableModel *VariableController::variableModel() noexcept
59 59 {
60 60 return impl->m_VariableModel;
61 61 }
62 62
63 63 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
64 64 {
65 65 return impl->m_VariableSelectionModel;
66 66 }
67 67
68 68 void VariableController::setTimeController(TimeController *timeController) noexcept
69 69 {
70 70 impl->m_TimeController = timeController;
71 71 }
72 72
73 73 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
74 74 {
75 75 if (!variable) {
76 76 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
77 77 return;
78 78 }
79 79
80 80 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
81 81 // make some treatments before the deletion
82 82 emit variableAboutToBeDeleted(variable);
83 83
84 84 // Deletes provider
85 85 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
86 86 qCDebug(LOG_VariableController())
87 87 << tr("Number of providers deleted for variable %1: %2")
88 88 .arg(variable->name(), QString::number(nbProvidersDeleted));
89 89
90 90 // Clears cache
91 91 impl->m_VariableCacheController->clear(variable);
92 92
93 93 // Deletes from model
94 94 impl->m_VariableModel->deleteVariable(variable);
95 95 }
96 96
97 97 void VariableController::deleteVariables(
98 98 const QVector<std::shared_ptr<Variable> > &variables) noexcept
99 99 {
100 100 for (auto variable : qAsConst(variables)) {
101 101 deleteVariable(variable);
102 102 }
103 103 }
104 104
105 105 void VariableController::createVariable(const QString &name,
106 106 std::shared_ptr<IDataProvider> provider) noexcept
107 107 {
108 108
109 109 if (!impl->m_TimeController) {
110 110 qCCritical(LOG_VariableController())
111 111 << tr("Impossible to create variable: The time controller is null");
112 112 return;
113 113 }
114 114
115 115
116 116 /// @todo : for the moment :
117 117 /// - the provider is only used to retrieve data from the variable for its initialization, but
118 118 /// it will be retained later
119 119 /// - default data are generated for the variable, without taking into account the timerange set
120 120 /// in sciqlop
121 121 auto dateTime = impl->m_TimeController->dateTime();
122 122 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime)) {
123 auto token = QUuid::createUuid();
123 auto identifier = QUuid::createUuid();
124 124
125 125 // store the provider
126 126 impl->m_VariableToProviderMap[newVariable] = provider;
127 impl->m_VariableToToken[newVariable] = token;
127 impl->m_VariableToIdentifier[newVariable] = identifier;
128 128
129 129 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
130 QUuid token, auto dataSeriesAcquired, auto dateTimeToPutInCache)
130 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
131 131 {
132 132 if (auto variable = varW.lock()) {
133 auto varToken = impl->m_VariableToToken.at(variable);
134 if (varToken == token) {
133 auto varIdentifier = impl->m_VariableToIdentifier.at(variable);
134 if (varIdentifier == identifier) {
135 135 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
136 136 variable->setDataSeries(dataSeriesAcquired);
137 137 }
138 138 }
139 139 };
140 140
141 141 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
142 142 this->onRequestDataLoading(newVariable, dateTime);
143 143 }
144 144 }
145 145
146 146 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
147 147 {
148 148 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
149 149 << QThread::currentThread()->objectName();
150 150 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
151 151
152 152 for (const auto &selectedRow : qAsConst(selectedRows)) {
153 153 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
154 154 selectedVariable->setDateTime(dateTime);
155 155 this->onRequestDataLoading(selectedVariable, dateTime);
156 156 }
157 157 }
158 158 }
159 159
160 160
161 161 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
162 162 const SqpDateTime &dateTime)
163 163 {
164 164 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
165 165 << QThread::currentThread()->objectName();
166 166 // we want to load data of the variable for the dateTime.
167 167 // First we check if the cache contains some of them.
168 168 // For the other, we ask the provider to give them.
169 169 if (variable) {
170 170
171 171 auto dateTimeListNotInCache
172 172 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
173 173
174 174 if (!dateTimeListNotInCache.empty()) {
175 175 // Ask the provider for each data on the dateTimeListNotInCache
176 auto token = impl->m_VariableToToken.at(variable);
176 auto identifier = impl->m_VariableToIdentifier.at(variable);
177 177 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
178 token, std::move(dateTimeListNotInCache));
178 identifier, std::move(dateTimeListNotInCache));
179 179 }
180 180 else {
181 181 emit variable->updated();
182 182 }
183 183 }
184 184 else {
185 185 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
186 186 }
187 187 }
188 188
189 189
190 190 void VariableController::initialize()
191 191 {
192 192 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
193 193 impl->m_WorkingMutex.lock();
194 194 qCDebug(LOG_VariableController()) << tr("VariableController init END");
195 195 }
196 196
197 197 void VariableController::finalize()
198 198 {
199 199 impl->m_WorkingMutex.unlock();
200 200 }
201 201
202 202 void VariableController::waitForFinish()
203 203 {
204 204 QMutexLocker locker{&impl->m_WorkingMutex};
205 205 }
@@ -1,140 +1,140
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <Network/NetworkController.h>
6 6 #include <QThread>
7 7 #include <Time/TimeController.h>
8 8 #include <Variable/Variable.h>
9 9 #include <Variable/VariableController.h>
10 10 #include <Visualization/VisualizationController.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
13 13
14 14 class SqpApplication::SqpApplicationPrivate {
15 15 public:
16 16 SqpApplicationPrivate()
17 17 : m_DataSourceController{std::make_unique<DataSourceController>()},
18 18 m_NetworkController{std::make_unique<NetworkController>()},
19 19 m_TimeController{std::make_unique<TimeController>()},
20 20 m_VariableController{std::make_unique<VariableController>()},
21 21 m_VisualizationController{std::make_unique<VisualizationController>()}
22 22 {
23 23 // /////////////////////////////// //
24 24 // Connections between controllers //
25 25 // /////////////////////////////// //
26 26
27 27 // VariableController <-> DataSourceController
28 28 connect(m_DataSourceController.get(),
29 29 SIGNAL(variableCreationRequested(const QString &, std::shared_ptr<IDataProvider>)),
30 30 m_VariableController.get(),
31 31 SLOT(createVariable(const QString &, std::shared_ptr<IDataProvider>)));
32 32
33 33 // VariableController <-> VisualizationController
34 34 connect(m_VariableController.get(),
35 35 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
36 36 m_VisualizationController.get(),
37 37 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
38 38
39 39
40 40 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
41 41 m_NetworkController->moveToThread(&m_NetworkControllerThread);
42 42 m_VariableController->moveToThread(&m_VariableControllerThread);
43 43 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
44 44
45 45
46 46 // Additionnal init
47 47 m_VariableController->setTimeController(m_TimeController.get());
48 48 }
49 49
50 50 virtual ~SqpApplicationPrivate()
51 51 {
52 52 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
53 53 m_DataSourceControllerThread.quit();
54 54 m_DataSourceControllerThread.wait();
55 55
56 56 m_NetworkControllerThread.quit();
57 57 m_NetworkControllerThread.wait();
58 58
59 59 m_VariableControllerThread.quit();
60 60 m_VariableControllerThread.wait();
61 61
62 62 m_VisualizationControllerThread.quit();
63 63 m_VisualizationControllerThread.wait();
64 64 }
65 65
66 66 std::unique_ptr<DataSourceController> m_DataSourceController;
67 67 std::unique_ptr<VariableController> m_VariableController;
68 68 std::unique_ptr<TimeController> m_TimeController;
69 69 std::unique_ptr<NetworkController> m_NetworkController;
70 70 std::unique_ptr<VisualizationController> m_VisualizationController;
71 71 QThread m_DataSourceControllerThread;
72 72 QThread m_NetworkControllerThread;
73 73 QThread m_VariableControllerThread;
74 74 QThread m_VisualizationControllerThread;
75 75 };
76 76
77 77
78 78 SqpApplication::SqpApplication(int &argc, char **argv)
79 79 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
80 80 {
81 qCInfo(LOG_SqpApplication()) << tr("SqpApplication construction");
81 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
82 82
83 83 connect(&impl->m_DataSourceControllerThread, &QThread::started,
84 84 impl->m_DataSourceController.get(), &DataSourceController::initialize);
85 85 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
86 86 impl->m_DataSourceController.get(), &DataSourceController::finalize);
87 87
88 88 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
89 89 &NetworkController::initialize);
90 90 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
91 91 &NetworkController::finalize);
92 92
93 93 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
94 94 &VariableController::initialize);
95 95 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
96 96 &VariableController::finalize);
97 97
98 98 connect(&impl->m_VisualizationControllerThread, &QThread::started,
99 99 impl->m_VisualizationController.get(), &VisualizationController::initialize);
100 100 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
101 101 impl->m_VisualizationController.get(), &VisualizationController::finalize);
102 102
103 103 impl->m_DataSourceControllerThread.start();
104 104 impl->m_NetworkControllerThread.start();
105 105 impl->m_VariableControllerThread.start();
106 106 impl->m_VisualizationControllerThread.start();
107 107 }
108 108
109 109 SqpApplication::~SqpApplication()
110 110 {
111 111 }
112 112
113 113 void SqpApplication::initialize()
114 114 {
115 115 }
116 116
117 117 DataSourceController &SqpApplication::dataSourceController() noexcept
118 118 {
119 119 return *impl->m_DataSourceController;
120 120 }
121 121
122 122 NetworkController &SqpApplication::networkController() noexcept
123 123 {
124 124 return *impl->m_NetworkController;
125 125 }
126 126
127 127 TimeController &SqpApplication::timeController() noexcept
128 128 {
129 129 return *impl->m_TimeController;
130 130 }
131 131
132 132 VariableController &SqpApplication::variableController() noexcept
133 133 {
134 134 return *impl->m_VariableController;
135 135 }
136 136
137 137 VisualizationController &SqpApplication::visualizationController() noexcept
138 138 {
139 139 return *impl->m_VisualizationController;
140 140 }
@@ -1,36 +1,38
1 1 #ifndef SCIQLOP_AMDAPROVIDER_H
2 2 #define SCIQLOP_AMDAPROVIDER_H
3 3
4 4 #include "AmdaGlobal.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <Data/IDataProvider.h>
9 9
10 10 #include <QLoggingCategory>
11 11
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaProvider)
14 14
15 class QNetworkReply;
16
15 17 /**
16 18 * @brief The AmdaProvider class is an example of how a data provider can generate data
17 19 */
18 20 class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider {
19 21 public:
20 22 explicit AmdaProvider();
21 23
22 24 void requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList) override;
23 25
24 26 private:
25 void retrieveData(QUuid token, const DataProviderParameters &parameters) const;
27 void retrieveData(QUuid token, const DataProviderParameters &parameters);
26 28
27 29 class AmdaProviderPrivate;
28 30 spimpl::unique_impl_ptr<AmdaProviderPrivate> impl;
29 31
30 private slots:
31 void httpFinished() noexcept;
32 void httpDownloadFinished() noexcept;
33 void httpDownloadReadyRead() noexcept;
32 // private slots:
33 // void httpFinished(QNetworkReply *reply, QUuid dataId) noexcept;
34 // void httpDownloadFinished(QNetworkReply *reply, QUuid dataId) noexcept;
35 // void httpDownloadReadyRead(QNetworkReply *reply, QUuid dataId) noexcept;
34 36 };
35 37
36 38 #endif // SCIQLOP_AMDAPROVIDER_H
@@ -1,134 +1,128
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaResultParser.h"
3 3
4 4 #include <Data/DataProviderParameters.h>
5 #include <Network/NetworkController.h>
6 #include <SqpApplication.h>
7 #include <Variable/Variable.h>
5 8
6 9 #include <QNetworkAccessManager>
7 10 #include <QNetworkReply>
8 11 #include <QTemporaryFile>
12 #include <QThread>
9 13
10 14 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
11 15
12 16 namespace {
13 17
14 18 /// URL format for a request on AMDA server. The parameters are as follows:
15 19 /// - %1: start date
16 20 /// - %2: end date
17 21 /// - %3: parameter id
18 22 const auto AMDA_URL_FORMAT = QStringLiteral(
19 23 "http://amda.irap.omp.eu/php/rest/"
20 24 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&sampling=60&outputFormat=ASCII&"
21 25 "timeFormat=ISO8601&gzip=0");
22 26
23 27 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
24 28 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:ss");
25 29
26 30 /// Formats a time to a date that can be passed in URL
27 31 QString dateFormat(double sqpDateTime) noexcept
28 32 {
29 33 auto dateTime = QDateTime::fromMSecsSinceEpoch(sqpDateTime * 1000.);
30 34 return dateTime.toString(AMDA_TIME_FORMAT);
31 35 }
32 36
37
33 38 } // namespace
34 39
35 40 struct AmdaProvider::AmdaProviderPrivate {
36 41 DataProviderParameters m_Params{};
37 42 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
38 43 QNetworkReply *m_Reply{nullptr};
39 std::unique_ptr<QTemporaryFile> m_File{nullptr};
44 // std::unique_ptr<QTemporaryFile> m_File{nullptr};
40 45 QUuid m_Token;
41 46 };
42 47
43 48 AmdaProvider::AmdaProvider() : impl{spimpl::make_unique_impl<AmdaProviderPrivate>()}
44 49 {
50 qCDebug(LOG_NetworkController()) << tr("AmdaProvider::AmdaProvider")
51 << QThread::currentThread();
52 if (auto app = sqpApp) {
53 auto &networkController = app->networkController();
54 connect(this, &AmdaProvider::requestConstructed, &networkController,
55 &NetworkController::onProcessRequested);
56 }
45 57 }
46 58
47 59 void AmdaProvider::requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList)
48 60 {
49 61 // NOTE: Try to use multithread if possible
50 62 for (const auto &dateTime : dateTimeList) {
51 63 retrieveData(token, DataProviderParameters{dateTime});
52 64 }
53 65 }
54 66
55 void AmdaProvider::retrieveData(QUuid token, const DataProviderParameters &parameters) const
67 void AmdaProvider::retrieveData(QUuid token, const DataProviderParameters &parameters)
56 68 {
57 69 // /////////// //
58 70 // Creates URL //
59 71 // /////////// //
60 72
61 73 auto startDate = dateFormat(parameters.m_Time.m_TStart);
62 74 auto endDate = dateFormat(parameters.m_Time.m_TEnd);
63 75 auto productId = QStringLiteral("imf(0)");
64 76
65 77 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
66 78
67 // //////////////// //
68 // Executes request //
69 // //////////////// //
79 auto tempFile = std::make_shared<QTemporaryFile>();
70 80
71 impl->m_Token = token;
72 impl->m_Params = parameters;
73 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
74 impl->m_Reply = impl->m_AccessManager->get(QNetworkRequest{url});
75 connect(impl->m_Reply, &QNetworkReply::finished, this, &AmdaProvider::httpFinished);
76 }
77 81
78 void AmdaProvider::httpFinished() noexcept
79 {
80 // ////////////////////// //
81 // Gets download file url //
82 // ////////////////////// //
83
84 auto downloadFileUrl = QUrl{QString{impl->m_Reply->readAll()}};
85
86 // ///////////////////////////////////// //
87 // Executes request for downloading file //
88 // ///////////////////////////////////// //
89
90 // Deletes old reply
91 impl->m_Reply->deleteLater();
92 impl->m_Reply = nullptr;
93
94 // Creates destination file
95 impl->m_File = std::make_unique<QTemporaryFile>();
96 if (impl->m_File->open()) {
97 qCDebug(LOG_AmdaProvider()) << "Temp file: " << impl->m_File->fileName();
98
99 // Executes request
100 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
101 impl->m_Reply = impl->m_AccessManager->get(QNetworkRequest{downloadFileUrl});
102 connect(impl->m_Reply, &QNetworkReply::finished, this,
103 &AmdaProvider::httpDownloadReadyRead);
104 connect(impl->m_Reply, &QNetworkReply::finished, this, &AmdaProvider::httpDownloadFinished);
105 }
106 }
82 // LAMBDA
83 auto httpDownloadFinished = [this, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
107 84
108 void AmdaProvider::httpDownloadFinished() noexcept
109 {
110 if (impl->m_File) {
111 impl->m_File->close();
85 if (tempFile) {
86 auto replyReadAll = reply->readAll();
87 if (!replyReadAll.isEmpty()) {
88 tempFile->write(replyReadAll);
89 }
90 tempFile->close();
112 91
113 // Parse results file
114 if (auto dataSeries = AmdaResultParser::readTxt(impl->m_File->fileName())) {
115 emit dataProvided(impl->m_Token, dataSeries, impl->m_Params.m_Time);
116 }
117 else {
118 /// @todo ALX : debug
92 // Parse results file
93 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
94 emit dataProvided(impl->m_Token, dataSeries, impl->m_Params.m_Time);
95 }
96 else {
97 /// @todo ALX : debug
98 }
119 99 }
120 100
121 impl->m_File = nullptr;
122 }
101 // Deletes reply
102 reply->deleteLater();
103 reply = nullptr;
104 };
105 auto httpFinishedLambda = [this, httpDownloadFinished, tempFile](QNetworkReply *reply,
106 QUuid dataId) noexcept {
123 107
124 // Deletes reply
125 impl->m_Reply->deleteLater();
126 impl->m_Reply = nullptr;
127 }
108 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
109 // Deletes old reply
110 reply->deleteLater();
128 111
129 void AmdaProvider::httpDownloadReadyRead() noexcept
130 {
131 if (impl->m_File) {
132 impl->m_File->write(impl->m_Reply->readAll());
133 }
112 // Executes request for downloading file //
113
114 // Creates destination file
115 if (tempFile->open()) {
116 // Executes request
117 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId, httpDownloadFinished);
118 }
119 };
120
121 // //////////////// //
122 // Executes request //
123 // //////////////// //
124
125 impl->m_Token = token;
126 impl->m_Params = parameters;
127 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
134 128 }
General Comments 0
You need to be logged in to leave comments. Login now