24
24
#include " qgsvectorlayer.h"
25
25
#include " nlohmann/json.hpp"
26
26
27
+ #include < mutex>
27
28
#include < QCryptographicHash>
29
+ #include < QFileSystemWatcher>
28
30
29
31
const QRegularExpression QgsLandingPageUtils::PROJECT_HASH_RE { QStringLiteral ( " /(?<projectHash>[a-f0-9]{32})" ) };
30
32
QMap<QString, QString> QgsLandingPageUtils::AVAILABLE_PROJECTS;
31
33
34
+ std::once_flag initDirWatcher;
35
+
32
36
QMap<QString, QString> QgsLandingPageUtils::projects ( )
33
37
{
34
- // TODO: use a dir-watcher to invalidate
38
+
39
+ static QString QGIS_SERVER_PROJECTS_DIRECTORIES;
40
+ static QString QGIS_SERVER_PROJECTS_PG_CONNECTIONS;
41
+
42
+ // Init directory watcher
43
+ static QFileSystemWatcher dirWatcher;
44
+ std::call_once ( initDirWatcher, [ = ]
45
+ {
46
+ QObject::connect ( &dirWatcher, &QFileSystemWatcher::directoryChanged, qApp, [ = ]( const QString & path )
47
+ {
48
+ QgsMessageLog::logMessage ( QStringLiteral ( " Directory '%1' has changed: project information cache cleared." ).arg ( path ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Info );
49
+ AVAILABLE_PROJECTS.clear ();
50
+ } );
51
+ } );
52
+
53
+
54
+ const QString projectDir { QString ( qgetenv ( " QGIS_SERVER_PROJECTS_DIRECTORIES" ) ) };
55
+
56
+ // Clear cache if QGIS_SERVER_PROJECTS_DIRECTORIES has changed
57
+ if ( projectDir != QGIS_SERVER_PROJECTS_DIRECTORIES )
58
+ {
59
+ QGIS_SERVER_PROJECTS_DIRECTORIES = projectDir;
60
+ AVAILABLE_PROJECTS.clear ();
61
+ const QStringList cWatchedDirs { dirWatcher.directories () };
62
+ dirWatcher.removePaths ( cWatchedDirs );
63
+ }
64
+
65
+ const QString pgConnections { QString ( qgetenv ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS" ) ) };
66
+
67
+ // Clear cache if QGIS_SERVER_PROJECTS_PG_CONNECTIONS has changed
68
+ if ( pgConnections != QGIS_SERVER_PROJECTS_PG_CONNECTIONS )
69
+ {
70
+ QGIS_SERVER_PROJECTS_PG_CONNECTIONS = pgConnections;
71
+ AVAILABLE_PROJECTS.clear ();
72
+ }
73
+
74
+ // Scan QGIS_SERVER_PROJECTS_DIRECTORIES
35
75
if ( AVAILABLE_PROJECTS.isEmpty () )
36
76
{
37
- for ( const auto &path : QString ( qgetenv ( " QGIS_SERVER_PROJECTS_DIRECTORIES" ) ).split ( QStringLiteral ( " ||" ) ) )
77
+ const auto cProjectDirs { projectDir.split ( QStringLiteral ( " ||" ) ) };
78
+ for ( const auto &path : cProjectDirs )
38
79
{
39
80
if ( ! path.isEmpty () )
40
81
{
41
82
const QDir dir { path };
42
83
if ( dir.exists () )
43
84
{
85
+ dirWatcher.addPath ( dir.path () );
44
86
const auto constFiles { dir.entryList ( ) };
45
87
for ( const auto &f : constFiles )
46
88
{
@@ -64,35 +106,36 @@ QMap<QString, QString> QgsLandingPageUtils::projects( )
64
106
QgsMessageLog::logMessage ( QStringLiteral ( " QGIS_SERVER_PROJECTS_DIRECTORIES empty path: skipping." ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
65
107
}
66
108
}
109
+ }
67
110
68
- // PG projects
69
- const auto storage { QgsApplication::instance ()->projectStorageRegistry ()->projectStorageFromType ( QStringLiteral ( " postgresql" ) ) };
70
- Q_ASSERT ( storage );
71
- for ( const auto &connectionString : QString ( qgetenv ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS" ) ).split ( QStringLiteral ( " ||" ) ) )
111
+ // PG projects (there is no watcher for PG: scan every time)
112
+ const auto storage { QgsApplication::instance ()->projectStorageRegistry ()->projectStorageFromType ( QStringLiteral ( " postgresql" ) ) };
113
+ Q_ASSERT ( storage );
114
+ const auto cPgConnections { pgConnections.split ( QStringLiteral ( " ||" ) ) };
115
+ for ( const auto &connectionString : cPgConnections )
116
+ {
117
+ if ( ! connectionString.isEmpty () )
72
118
{
73
- if ( ! connectionString.isEmpty () )
119
+ const auto constProjects { storage->listProjects ( connectionString ) };
120
+ if ( ! constProjects.isEmpty () )
74
121
{
75
- const auto constProjects { storage->listProjects ( connectionString ) };
76
- if ( ! constProjects.isEmpty () )
77
- {
78
- for ( const auto &projectName : constProjects )
79
- {
80
- const QString projectFullPath { connectionString + QStringLiteral ( " &project=%1" ).arg ( projectName ) };
81
- const auto projectHash { QCryptographicHash::hash ( projectFullPath.toUtf8 (), QCryptographicHash::Md5 ).toHex () };
82
- AVAILABLE_PROJECTS[ projectHash ] = projectFullPath;
83
- QgsMessageLog::logMessage ( QStringLiteral ( " Adding postgres project '%1' with id '%2'" ).arg ( projectName, QString::fromUtf8 ( projectHash ) ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
84
- }
85
- }
86
- else
122
+ for ( const auto &projectName : constProjects )
87
123
{
88
- QgsMessageLog::logMessage ( QStringLiteral ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS entry '%1' was not found or has not projects: skipping." ).arg ( connectionString ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
124
+ const QString projectFullPath { connectionString + QStringLiteral ( " &project=%1" ).arg ( projectName ) };
125
+ const auto projectHash { QCryptographicHash::hash ( projectFullPath.toUtf8 (), QCryptographicHash::Md5 ).toHex () };
126
+ AVAILABLE_PROJECTS[ projectHash ] = projectFullPath;
127
+ QgsMessageLog::logMessage ( QStringLiteral ( " Adding postgres project '%1' with id '%2'" ).arg ( projectName, QString::fromUtf8 ( projectHash ) ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
89
128
}
90
129
}
91
130
else
92
131
{
93
- QgsMessageLog::logMessage ( QStringLiteral ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS empty connection : skipping." ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
132
+ QgsMessageLog::logMessage ( QStringLiteral ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS entry '%1' was not found or has not projects : skipping." ). arg ( connectionString ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
94
133
}
95
134
}
135
+ else
136
+ {
137
+ QgsMessageLog::logMessage ( QStringLiteral ( " QGIS_SERVER_PROJECTS_PG_CONNECTIONS empty connection: skipping." ), QStringLiteral ( " Landing Page" ), Qgis::MessageLevel::Warning );
138
+ }
96
139
}
97
140
98
141
return AVAILABLE_PROJECTS;
@@ -176,8 +219,8 @@ json QgsLandingPageUtils::projectInfo( const QString &projectUri )
176
219
return jLinks;
177
220
};
178
221
179
- json info;
180
- info[ " id" ] = QCryptographicHash::hash ( projectUri.toUtf8 (), QCryptographicHash::Md5 ).toHex ();
222
+ json info = json::object () ;
223
+ info[ " id" ] = QCryptographicHash::hash ( projectUri.toUtf8 (), QCryptographicHash::Md5 ).toHex ();
181
224
QgsProject p;
182
225
if ( p.read ( projectUri ) )
183
226
{
0 commit comments