Skip to content

Commit fc1c9af

Browse files
Use async NetworkManager in LanguagesService
1 parent 3df1000 commit fc1c9af

File tree

3 files changed

+119
-98
lines changed

3 files changed

+119
-98
lines changed

src/framework/languages/ilanguagesservice.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* MuseScore
66
* Music Composition & Notation
77
*
8-
* Copyright (C) 2021 MuseScore Limited and others
8+
* Copyright (C) 2025 MuseScore Limited and others
99
*
1010
* This program is free software: you can redistribute it and/or modify
1111
* it under the terms of the GNU General Public License version 3 as
@@ -19,8 +19,8 @@
1919
* You should have received a copy of the GNU General Public License
2020
* along with this program. If not, see <https://www.gnu.org/licenses/>.
2121
*/
22-
#ifndef MUSE_LANGUAGES_ILANGUAGESSERVICE_H
23-
#define MUSE_LANGUAGES_ILANGUAGESSERVICE_H
22+
23+
#pragma once
2424

2525
#include "modularity/imoduleinterface.h"
2626
#include "async/notification.h"
@@ -50,5 +50,3 @@ class ILanguagesService : MODULE_EXPORT_INTERFACE
5050
virtual async::Channel<bool> restartRequiredToApplyLanguageChanged() const = 0;
5151
};
5252
}
53-
54-
#endif // MUSE_LANGUAGES_ILANGUAGESSERVICE_H

src/framework/languages/internal/languagesservice.cpp

Lines changed: 100 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* MuseScore
66
* Music Composition & Notation
77
*
8-
* Copyright (C) 2021 MuseScore Limited and others
8+
* Copyright (C) 2025 MuseScore Limited and others
99
*
1010
* This program is free software: you can redistribute it and/or modify
1111
* it under the terms of the GNU General Public License version 3 as
@@ -32,15 +32,12 @@
3232

3333
#include "languageserrors.h"
3434

35-
#include "global/io/buffer.h"
36-
#include "global/serialization/zipreader.h"
37-
#include "global/concurrency/concurrent.h"
38-
3935
#include "multiinstances/resourcelockguard.h"
4036

41-
#include "translation.h"
42-
43-
#include "log.h"
37+
#include "global/io/buffer.h"
38+
#include "global/serialization/zipreader.h"
39+
#include "global/translation.h"
40+
#include "global/log.h"
4441

4542
using namespace Qt::Literals::StringLiterals;
4643

@@ -186,13 +183,14 @@ void LanguagesService::setCurrentLanguage(const QString& languageCode)
186183
delete t;
187184
}
188185
m_translators.clear();
186+
m_translators.reserve(lang.files.size());
189187

190188
for (const io::path_t& file : lang.files) {
191189
QTranslator* translator = new QTranslator();
192190
bool ok = translator->load(file.toQString());
193191
if (ok) {
194192
qApp->installTranslator(translator);
195-
m_translators << translator;
193+
m_translators.push_back(translator);
196194
} else {
197195
LOGE() << "Error loading translator " << file.toQString();
198196
delete translator;
@@ -314,29 +312,53 @@ Progress LanguagesService::update(const QString& languageCode)
314312
return {};
315313
}
316314

317-
if (m_updateOperationsHash.contains(effectiveLanguageCode)) {
318-
return m_updateOperationsHash[effectiveLanguageCode];
315+
auto progressIt = m_updateOperationsHash.find(effectiveLanguageCode);
316+
if (progressIt != m_updateOperationsHash.end()) {
317+
return progressIt.value();
319318
}
320319

321320
Language& lang = m_languagesHash[effectiveLanguageCode];
322-
323321
if (!lang.isLoaded()) {
324322
loadLanguage(lang);
325323
}
326324

327-
Progress progress;
325+
auto finishProgress = [this, effectiveLanguageCode](const Ret& ret) {
326+
m_updateOperationsHash[effectiveLanguageCode].finish(ret);
327+
m_updateOperationsHash.remove(effectiveLanguageCode);
328+
};
329+
330+
auto updateFinished = [this, effectiveLanguageCode, finishProgress](const muse::Ret& ret) {
331+
if (ret) {
332+
m_restartRequiredToApplyLanguage = true;
333+
m_restartRequiredToApplyLanguageChanged.send(m_restartRequiredToApplyLanguage);
334+
}
328335

329-
m_updateOperationsHash.insert(effectiveLanguageCode, progress);
336+
finishProgress(ret);
337+
};
330338

331-
progress.finished().onReceive(this, [this, effectiveLanguageCode](const ProgressResult& res) {
332-
if (!res.ret && res.ret.code() != static_cast<int>(Err::AlreadyUpToDate)) {
333-
LOGE() << res.ret.toString();
339+
auto updateCheckFinished = [this, effectiveLanguageCode, updateFinished, finishProgress](const muse::RetVal<bool>& res) {
340+
if (!res.ret) {
341+
finishProgress(res.ret);
342+
return;
334343
}
335344

336-
m_updateOperationsHash.remove(effectiveLanguageCode);
337-
});
345+
if (!res.val) {
346+
finishProgress(make_ret(Err::AlreadyUpToDate));
347+
return;
348+
}
349+
350+
updateLanguage(effectiveLanguageCode, updateFinished);
351+
};
338352

339-
Concurrent::run(this, &LanguagesService::th_update, effectiveLanguageCode, progress);
353+
if (!m_networkManager) {
354+
m_networkManager = networkManagerCreator()->makeNetworkManager();
355+
}
356+
357+
Progress& progress = m_updateOperationsHash[effectiveLanguageCode];
358+
progress.start();
359+
progress.progress(0, 0, muse::trc("global", "Checking for updates…"));
360+
361+
checkUpdateAvailable(effectiveLanguageCode, updateCheckFinished);
340362

341363
return progress;
342364
}
@@ -351,84 +373,81 @@ async::Channel<bool> LanguagesService::restartRequiredToApplyLanguageChanged() c
351373
return m_restartRequiredToApplyLanguageChanged;
352374
}
353375

354-
void LanguagesService::th_update(const QString& languageCode, Progress progress)
376+
void LanguagesService::checkUpdateAvailable(const QString& languageCode, std::function<void(const RetVal<bool>&)> finished)
355377
{
356-
progress.start();
357-
358-
progress.progress(0, 0, muse::trc("languages", "Checking for updates…"));
359-
360-
if (!canUpdate(languageCode)) {
361-
progress.finish(make_ret(Err::AlreadyUpToDate));
362-
return;
363-
}
364-
365-
Ret ret = downloadLanguage(languageCode, progress);
366-
if (!ret) {
367-
progress.finish(ret);
378+
auto buff = std::make_shared<QBuffer>();
379+
RetVal<Progress> progress = m_networkManager->get(configuration()->languagesUpdateUrl().toString(), buff);
380+
if (!progress.ret) {
381+
finished(RetVal<bool>::make_ret(progress.ret));
368382
return;
369383
}
370384

371-
m_restartRequiredToApplyLanguage = true;
372-
m_restartRequiredToApplyLanguageChanged.send(m_restartRequiredToApplyLanguage);
373-
374-
progress.finish(make_ret(Err::NoError));
375-
}
376-
377-
bool LanguagesService::canUpdate(const QString& languageCode)
378-
{
379-
QBuffer buff;
380-
deprecated::INetworkManagerPtr networkManagerPtr = networkManagerCreator()->makeDeprecatedNetworkManager();
381-
382-
Ret ret = networkManagerPtr->get(configuration()->languagesUpdateUrl().toString(), &buff);
383-
if (!ret) {
384-
LOGE() << ret.toString();
385-
return false;
386-
}
385+
progress.val.finished().onReceive(this, [this, languageCode, buff, finished](const ProgressResult& res) {
386+
if (!res.ret) {
387+
finished(RetVal<bool>::make_ret(res.ret));
388+
return;
389+
}
387390

388-
QJsonParseError err;
389-
QJsonDocument jsonDoc = QJsonDocument::fromJson(buff.data(), &err);
390-
if (err.error != QJsonParseError::NoError || !jsonDoc.isObject()) {
391-
return false;
392-
}
391+
QJsonParseError err;
392+
QJsonDocument jsonDoc = QJsonDocument::fromJson(buff->data(), &err);
393+
if (err.error != QJsonParseError::NoError || !jsonDoc.isObject()) {
394+
finished(RetVal<bool>::make_ret(make_ret(Err::ErrorParseConfig)));
395+
return;
396+
}
393397

394-
QJsonObject languageObject = jsonDoc.object().value(languageCode).toObject();
398+
QJsonObject languageObject = jsonDoc.object().value(languageCode).toObject();
399+
const Language& language = m_languagesHash[languageCode];
395400

396-
Language& language = m_languagesHash[languageCode];
401+
bool shouldUpdate = false;
397402

398-
for (const QString& resource : LANGUAGE_RESOURCE_NAMES) {
399-
RetVal<QString> hash = fileHash(language.files[resource]);
400-
QString latestHash = languageObject.value(resource).toObject().value("hash").toString();
403+
for (const QString& resource : LANGUAGE_RESOURCE_NAMES) {
404+
RetVal<QString> hash = fileHash(language.files[resource]);
405+
QString latestHash = languageObject.value(resource).toObject().value("hash").toString();
401406

402-
if (!hash.ret || hash.val != latestHash) {
403-
return true;
407+
if (!hash.ret || hash.val != latestHash) {
408+
shouldUpdate = true;
409+
break;
410+
}
404411
}
405-
}
406412

407-
return false;
413+
finished(RetVal<bool>::make_ok(shouldUpdate));
414+
});
408415
}
409416

410-
Ret LanguagesService::downloadLanguage(const QString& languageCode, Progress progress) const
417+
void LanguagesService::updateLanguage(const QString& languageCode, std::function<void(const Ret&)> finished)
411418
{
412-
std::string downloadingStatusTitle = muse::trc("languages", "Downloading…");
413-
progress.progress(0, 0, downloadingStatusTitle);
419+
auto qbuff = std::make_shared<QBuffer>();
420+
QUrl url = configuration()->languageFileServerUrl(languageCode);
421+
RetVal<Progress> downloadProgress = m_networkManager->get(url, qbuff);
422+
if (!downloadProgress.ret) {
423+
finished(make_ret(Err::ErrorDownloadLanguage));
424+
return;
425+
}
414426

415-
QBuffer qbuff;
416-
deprecated::INetworkManagerPtr networkManagerPtr = networkManagerCreator()->makeDeprecatedNetworkManager();
427+
m_updateOperationsHash[languageCode].progress(0, 0, muse::trc("global", "Downloading…"));
417428

418-
networkManagerPtr->progress().progressChanged().onReceive(
419-
this, [&progress, &downloadingStatusTitle](int64_t current, int64_t total, const std::string&) {
420-
progress.progress(current, total, downloadingStatusTitle);
429+
downloadProgress.val.progressChanged().onReceive(this, [this, languageCode](int64_t current, int64_t total, const std::string&) {
430+
m_updateOperationsHash[languageCode].progress(current, total, muse::trc("global", "Downloading…"));
421431
});
422432

423-
Ret ret = networkManagerPtr->get(configuration()->languageFileServerUrl(languageCode), &qbuff);
424-
if (!ret) {
425-
LOGE() << "Error while downloading: " << ret.toString();
426-
return make_ret(Err::ErrorDownloadLanguage);
427-
}
433+
downloadProgress.val.finished().onReceive(this, [this, languageCode, qbuff, finished](const ProgressResult& res) {
434+
if (!res.ret) {
435+
finished(make_ret(Err::ErrorDownloadLanguage));
436+
return;
437+
}
428438

429-
progress.progress(0, 0, muse::trc("languages", "Unpacking…"));
439+
m_updateOperationsHash[languageCode].progress(0, 0, muse::trc("global", "Unpacking…"));
430440

431-
ByteArray ba = ByteArray::fromQByteArrayNoCopy(qbuff.data());
441+
Ret ret = unpackAndWriteLanguage(qbuff->data());
442+
finished(ret);
443+
});
444+
}
445+
446+
Ret LanguagesService::unpackAndWriteLanguage(const QByteArray& zipData)
447+
{
448+
TRACEFUNC;
449+
450+
ByteArray ba = ByteArray::fromQByteArrayNoCopy(zipData);
432451
io::Buffer buff(&ba);
433452
ZipReader zipReader(&buff);
434453

@@ -437,18 +456,17 @@ Ret LanguagesService::downloadLanguage(const QString& languageCode, Progress pro
437456

438457
for (const auto& info : zipReader.fileInfoList()) {
439458
io::path_t userFilePath = configuration()->languagesUserAppDataPath().appendingComponent(info.filePath);
440-
ret = fileSystem()->writeFile(userFilePath, zipReader.fileData(info.filePath.toStdString()));
459+
Ret ret = fileSystem()->writeFile(userFilePath, zipReader.fileData(info.filePath.toStdString()));
441460
if (!ret) {
442-
LOGE() << "Error while writing to disk: " << ret.toString();
443461
return make_ret(Err::ErrorWriteLanguage);
444462
}
445463
}
446464
}
447465

448-
return muse::make_ok();
466+
return make_ok();
449467
}
450468

451-
RetVal<QString> LanguagesService::fileHash(const io::path_t& path)
469+
RetVal<QString> LanguagesService::fileHash(const io::path_t& path) const
452470
{
453471
RetVal<ByteArray> fileBytes;
454472
{

src/framework/languages/internal/languagesservice.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* MuseScore
66
* Music Composition & Notation
77
*
8-
* Copyright (C) 2021 MuseScore Limited and others
8+
* Copyright (C) 2025 MuseScore Limited and others
99
*
1010
* This program is free software: you can redistribute it and/or modify
1111
* it under the terms of the GNU General Public License version 3 as
@@ -36,10 +36,10 @@ class QTranslator;
3636
namespace muse::languages {
3737
class LanguagesService : public ILanguagesService, public Injectable, public async::Asyncable
3838
{
39-
ThreadSafeInject<ILanguagesConfiguration> configuration = { this };
40-
ThreadSafeInject<network::INetworkManagerCreator> networkManagerCreator = { this };
41-
ThreadSafeInject<io::IFileSystem> fileSystem = { this };
42-
ThreadSafeInject<mi::IMultiInstancesProvider> multiInstancesProvider = { this };
39+
Inject<ILanguagesConfiguration> configuration = { this };
40+
Inject<network::INetworkManagerCreator> networkManagerCreator = { this };
41+
Inject<io::IFileSystem> fileSystem = { this };
42+
Inject<mi::IMultiInstancesProvider> multiInstancesProvider = { this };
4343

4444
public:
4545
LanguagesService(const modularity::ContextPtr& iocCtx)
@@ -65,24 +65,29 @@ class LanguagesService : public ILanguagesService, public Injectable, public asy
6565

6666
void setCurrentLanguage(const QString& languageCode);
6767
QString effectiveLanguageCode(QString languageCode) const;
68+
6869
Ret loadLanguage(Language& lang);
6970

70-
void th_update(const QString& languageCode, Progress progress);
71-
bool canUpdate(const QString& languageCode);
72-
Ret downloadLanguage(const QString& languageCode, Progress progress) const;
73-
RetVal<QString> fileHash(const io::path_t& path);
71+
void checkUpdateAvailable(const QString& languageCode, std::function<void(const RetVal<bool>&)> finished);
72+
void updateLanguage(const QString& languageCode, std::function<void(const Ret&)> finished);
73+
74+
Ret unpackAndWriteLanguage(const QByteArray& zipData);
75+
76+
RetVal<QString> fileHash(const io::path_t& path) const;
7477

7578
private:
7679
LanguagesHash m_languagesHash;
7780
Language m_currentLanguage;
7881
async::Notification m_currentLanguageChanged;
7982
Language m_placeholderLanguage;
8083

81-
QSet<QTranslator*> m_translators;
82-
mutable QHash<QString, Progress> m_updateOperationsHash;
84+
std::vector<QTranslator*> m_translators;
85+
QHash<QString, Progress> m_updateOperationsHash;
8386

8487
bool m_inited = false;
8588
bool m_restartRequiredToApplyLanguage = false;
8689
async::Channel<bool> m_restartRequiredToApplyLanguageChanged;
90+
91+
network::INetworkManagerPtr m_networkManager;
8792
};
8893
}

0 commit comments

Comments
 (0)