Skip to content

Commit abfe443

Browse files
authored
partial Fixes #12057 (#12060)
essentially this commit drastically reduces image updates and associated ResourceJob creation by checking the etag of the image and only fetching the resource if the tag has changed. same principle is applied to the space itself. Space's drive is "updated" automatically every 30 seconds using a polling strategy, so it's common that nothing has actually changed. New behavior: if the space etag has not changed there should be nothing to update, so skip it.
1 parent e9d736b commit abfe443

File tree

1 file changed

+73
-42
lines changed

1 file changed

+73
-42
lines changed

src/libsync/graphapi/space.cpp

+73-42
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ Space::Space(SpacesManager *spacesManager, const OpenAPI::OAIDrive &drive, const
3838
, _image(new SpaceImage(this))
3939
, _hasManyPersonalSpaces(hasManyPersonalSpaces)
4040
{
41+
// todo future refactoring: get this setDrive out of the ctr since it potentially kicks off a job for the SpaceImage before the Space is fully constructed
42+
// propose removing the drive arg from the ctr completely, and moving the call to setDrive to the spacesmanager such that any call to
43+
// "new" space is immediately followed by setDrive.
4144
setDrive(drive);
4245
connect(_image, &SpaceImage::imageChanged, this, &Space::imageChanged);
4346
}
@@ -49,51 +52,21 @@ OpenAPI::OAIDrive Space::drive() const
4952

5053
void Space::setDrive(const OpenAPI::OAIDrive &drive)
5154
{
52-
_drive = drive;
53-
_image->update();
54-
}
5555

56-
SpaceImage::SpaceImage(Space *space)
57-
: QObject(space)
58-
, _space(space)
59-
{
60-
update();
61-
}
56+
// first config naturally has an empty drive - reality check that updated drives are always valid
57+
Q_ASSERT(drive.isValid());
6258

63-
QIcon SpaceImage::image() const
64-
{
65-
if (_image.isNull()) {
66-
return Resources::getCoreIcon(QStringLiteral("space"));
67-
}
68-
return _image;
69-
}
59+
QString curTag = _drive.getRoot().getETag();
60+
QString newTag = drive.getRoot().getETag();
61+
Q_ASSERT(!newTag.isEmpty());
62+
// the tag should change when the space is edited on the server. I verified that it changes on space rename as well
63+
// as on changing the space image so we may have further wrinkles if there is an error in logic server side, but for now
64+
// we want to reduce updates to "only when something changed" else everything is auto-refreshed periodically (eg every 30s)
65+
if (curTag == newTag)
66+
return;
7067

71-
QUrl SpaceImage::qmlImageUrl() const
72-
{
73-
if (!_image.isNull()) {
74-
return QUrl(QStringLiteral("image://space/%1/%2").arg(etag(), _space->id()));
75-
} else {
76-
// invalid space id to display the placeholder
77-
return QUrl(QStringLiteral("image://space/placeholder"));
78-
}
79-
}
80-
81-
void SpaceImage::update()
82-
{
83-
const auto &special = _space->drive().getSpecial();
84-
const auto img = std::find_if(special.cbegin(), special.cend(), [](const auto &it) { return it.getSpecialFolder().getName() == QLatin1String("image"); });
85-
if (img != special.cend()) {
86-
_url = QUrl(img->getWebDavUrl());
87-
_etag = Utility::normalizeEtag(img->getETag());
88-
auto job = _space->_spaceManager->account()->resourcesCache()->makeGetJob(_url, {}, _space);
89-
QObject::connect(job, &SimpleNetworkJob::finishedSignal, _space, [job, this] {
90-
if (job->httpStatusCode() == 200) {
91-
_image = job->asIcon();
92-
Q_EMIT imageChanged();
93-
}
94-
});
95-
job->start();
96-
}
68+
_drive = drive;
69+
_image->update();
9770
}
9871

9972
QString Space::displayName() const
@@ -143,3 +116,61 @@ QUrl Space::webdavUrl() const
143116
{
144117
return QUrl(_drive.getRoot().getWebDavUrl());
145118
}
119+
120+
SpaceImage::SpaceImage(Space *space)
121+
: QObject(space)
122+
, _space(space)
123+
{
124+
}
125+
126+
QIcon SpaceImage::image() const
127+
{
128+
if (_image.isNull()) {
129+
return Resources::getCoreIcon(QStringLiteral("space"));
130+
}
131+
return _image;
132+
}
133+
134+
QUrl SpaceImage::qmlImageUrl() const
135+
{
136+
if (!_image.isNull()) {
137+
return QUrl(QStringLiteral("image://space/%1/%2").arg(etag(), _space->id()));
138+
} else {
139+
// invalid space id to display the placeholder
140+
return QUrl(QStringLiteral("image://space/placeholder"));
141+
}
142+
}
143+
144+
void SpaceImage::update()
145+
{
146+
const auto &special = _space->drive().getSpecial();
147+
const auto img = std::find_if(special.cbegin(), special.cend(), [](const auto &it) { return it.getSpecialFolder().getName() == QLatin1String("image"); });
148+
if (img != special.cend())
149+
{
150+
// ssue 12057: verified the image etag does change when the space's icon has been updated via the web interface
151+
// check the etag before updating the members and creating the job. This should eliminate *many* pointless resource jobs which
152+
// will exacerbate whatever is making the app crash when the space tries to clean up it's child jobs and one is already gone
153+
QString newEtag = Utility::normalizeEtag(img->getETag());
154+
if (_etag == newEtag)
155+
return;
156+
157+
_etag = newEtag;
158+
_url = QUrl(img->getWebDavUrl());
159+
// issue 12057: I am leaving the space as the parent of the job just to avoid having confusion about "new" destructor crashes. At least
160+
// we'll get any future crashes on the space still. I don't think that changing the parent is going to eliminate the associate crash - save
161+
// this for a future refactoring
162+
auto job = _space->_spaceManager->account()->resourcesCache()->makeGetJob(_url, {}, _space);
163+
164+
// TODO: next problem = this routine is correctly run when the icon has changed on the server, but the icon in the gui does not get refreshed!
165+
// The icon IS in the app cache, so it seems to have been brought back from the server correctly, but it is not shown until restart
166+
// I did have a quick look at Resources::getCoreIcon - that is used in the SpaceImage::image function. Also sus is that I can't find any slot
167+
// for the imageChanged signal but I think this may be connected in qml via the associated space image property.
168+
QObject::connect(job, &SimpleNetworkJob::finishedSignal, _space, [job, this] {
169+
if (job->httpStatusCode() == 200) {
170+
_image = job->asIcon();
171+
Q_EMIT imageChanged();
172+
}
173+
});
174+
job->start();
175+
}
176+
}

0 commit comments

Comments
 (0)