Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "globalmodule.h"
23 :
24 : #include "muse_framework_config.h"
25 :
26 : #include "modularity/ioc.h"
27 : #include "internal/globalconfiguration.h"
28 :
29 : #include "logger.h"
30 : #include "logremover.h"
31 : #include "profiler.h"
32 :
33 : #include "internal/baseapplication.h"
34 : #include "internal/cryptographichash.h"
35 : #include "internal/process.h"
36 : #include "internal/systeminfo.h"
37 : #include "internal/tickerprovider.h"
38 :
39 : #ifndef NO_QT_SUPPORT
40 : #include "internal/applicationeventcontroller.h"
41 : #endif
42 :
43 : #include "runtime.h"
44 : #include "async/processevents.h"
45 :
46 : #include "settings.h"
47 :
48 : #include "io/dir.h"
49 :
50 : #include "api/internal/apiregister.h"
51 : #include "api/internal/filesystemapirestriction.h"
52 : #include "api/iapiregister.h"
53 : #include "api/logapi.h"
54 : #include "api/filesystemapi.h"
55 : #include "api/processapi.h"
56 :
57 : #include "muse_framework_config.h"
58 :
59 : #ifdef MUSE_MODULE_DIAGNOSTICS
60 : #include "diagnostics/idiagnosticspathsregister.h"
61 : #endif
62 :
63 : #ifdef Q_OS_WASM
64 : #include "io/internal/memfilesystem.h"
65 : #else
66 : #include "io/internal/filesystem.h"
67 : #endif
68 :
69 : #ifdef Q_OS_WIN
70 : #include "platform/win/waitabletimer.h"
71 : #endif
72 :
73 : #include "log.h"
74 :
75 : using namespace muse;
76 : using namespace muse::modularity;
77 : using namespace muse::io;
78 :
79 46 : GlobalModule::GlobalModule()
80 : {
81 46 : }
82 :
83 460 : std::string GlobalModule::moduleName() const
84 : {
85 920 : return "global";
86 : }
87 :
88 46 : void GlobalModule::registerExports()
89 : {
90 46 : m_configuration = std::make_shared<GlobalConfiguration>();
91 46 : m_systemInfo = std::make_shared<SystemInfo>();
92 46 : m_tickerProvider = std::make_shared<TickerProvider>();
93 :
94 46 : globalIoc()->registerExport<IGlobalConfiguration>(moduleName(), m_configuration);
95 46 : globalIoc()->registerExport<ISystemInfo>(moduleName(), m_systemInfo);
96 46 : globalIoc()->registerExport<ICryptographicHash>(moduleName(), new CryptographicHash());
97 46 : globalIoc()->registerExport<IProcess>(moduleName(), new Process());
98 46 : globalIoc()->registerExport<ITickerProvider>(moduleName(), m_tickerProvider);
99 46 : globalIoc()->registerExport<api::IApiRegister>(moduleName(), new api::ApiRegister());
100 46 : globalIoc()->registerExport<api::IFileSystemApiRestriction>(moduleName(), new api::FileSystemApiRestriction());
101 :
102 : #ifndef NO_QT_SUPPORT
103 46 : m_eventController = std::make_shared<ApplicationEventController>();
104 46 : globalIoc()->registerExport<IApplicationEventController>(moduleName(), m_eventController);
105 : #endif
106 :
107 : #ifdef Q_OS_WASM
108 : globalIoc()->registerExport<IFileSystem>(moduleName(), new MemFileSystem());
109 : #else
110 46 : globalIoc()->registerExport<IFileSystem>(moduleName(), new FileSystem());
111 : #endif
112 46 : }
113 :
114 0 : void GlobalModule::registerApi()
115 : {
116 : using namespace muse::api;
117 :
118 0 : auto api = globalIoc()->resolve<IApiRegister>(moduleName());
119 0 : if (api) {
120 0 : api->regApiCreator(moduleName(), "MuseApi.Log", new ApiCreator<LogApi>());
121 0 : api->regApiCreator(moduleName(), "api.process", new ApiCreator<ProcessApi>());
122 0 : api->regApiCreator(moduleName(), "MuseApi.FS", new ApiCreator<FileSystemApi>());
123 : }
124 :
125 : // added fs restrictions
126 0 : auto fsRestriction = globalIoc()->resolve<api::IFileSystemApiRestriction>(moduleName());
127 0 : if (fsRestriction) {
128 0 : fsRestriction->addAllowedPathBase("temp", io::Dir::tempPath());
129 0 : fsRestriction->addAllowedPathBase("userData", m_configuration->userDataPath());
130 : }
131 0 : }
132 :
133 46 : void GlobalModule::onPreInit(const IApplication::RunMode& mode)
134 : {
135 46 : muse::runtime::mainThreadId(); //! NOTE Needs only call
136 46 : muse::runtime::setThreadName("main");
137 :
138 : //! NOTE: settings must be inited before initialization of any module
139 : //! because modules can use settings at the moment of their initialization
140 46 : settings()->load();
141 :
142 : //! --- Setup logger ---
143 : using namespace muse::logger;
144 46 : Logger* logger = Logger::instance();
145 46 : logger->clearDests();
146 :
147 : //! Console
148 46 : if (mode == IApplication::RunMode::GuiApp || muse::runtime::isDebug()) {
149 138 : logger->addDest(new ConsoleLogDest(LogLayout("${time} | ${type|5} | ${thread|15} | ${tag|15} | ${message}")));
150 : }
151 :
152 : //! Log file
153 46 : io::path_t logFilePath = "none";
154 : #ifndef MUSE_CONFIGURATION_IS_WEB
155 46 : io::path_t logPath = m_configuration->userAppDataPath() + "/logs";
156 46 : fileSystem()->makePath(logPath);
157 :
158 46 : logFilePath = logPath;
159 46 : String logFileNamePattern;
160 :
161 46 : if (mode == IApplication::RunMode::AudioPluginRegistration) {
162 0 : logFileNamePattern = u"audiopluginregistration_yyMMdd.log";
163 :
164 : //! This creates a file named "data/logs/audiopluginregistration_yyMMdd.log"
165 : logFilePath += "/audiopluginregistration_"
166 0 : + QDateTime::currentDateTime().toString("yyMMdd")
167 0 : + ".log";
168 : } else {
169 46 : logFileNamePattern = BaseApplication::appName() + u"_yyMMdd_HHmmss.log";
170 :
171 : //! This creates a file named "data/logs/AppName_yyMMdd_HHmmss.log"
172 92 : logFilePath += u"/" + BaseApplication::appName() + u"_"
173 184 : + String::fromQString(QDateTime::currentDateTime().toString("yyMMdd_HHmmss"))
174 92 : + u".log";
175 : }
176 :
177 : //! Remove old logs
178 46 : LogRemover::removeLogs(logPath, 7, logFileNamePattern);
179 :
180 : FileLogDest* logFile = new FileLogDest(logFilePath.toStdString(),
181 92 : LogLayout("${datetime} | ${type|5} | ${thread|15} | ${tag|15} | ${message}"));
182 :
183 46 : logger->addDest(logFile);
184 46 : LOGI() << "log path: " << logFilePath;
185 : #endif // end of not MUSE_CONFIGURATION_IS_WEB
186 :
187 46 : if (m_loggerLevel) {
188 0 : logger->setLevel(m_loggerLevel.value());
189 : } else {
190 : #ifdef MUSE_MODULE_GLOBAL_LOGGER_DEBUGLEVEL
191 46 : logger->setLevel(muse::logger::Level::Debug);
192 : #else
193 : logger->setLevel(muse::logger::Level::Normal);
194 : #endif
195 : }
196 :
197 46 : auto application = globalIoc()->resolve<IApplication>("global");
198 46 : if (application) {
199 92 : LOGI() << "=== Started " << application->title()
200 92 : << " " << application->fullVersion().toString()
201 46 : << ", build: " << application->build() << " ===";
202 : }
203 :
204 : //! --- Setup profiler ---
205 : using namespace muse::profiler;
206 : struct MyPrinter : public Profiler::Printer
207 : {
208 2 : void printDebug(const std::string& str) override { LOG_STREAM(Logger::DEBG, "Profiler", logger::Color::Magenta)() << str; }
209 46 : void printInfo(const std::string& str) override { LOG_STREAM(Logger::INFO, "Profiler", logger::Color::Magenta)() << str; }
210 : };
211 :
212 46 : Profiler::Options profOpt;
213 46 : profOpt.stepTimeEnabled = true;
214 46 : profOpt.timersEnabled = true;
215 46 : profOpt.funcsTimeEnabled = true;
216 46 : profOpt.funcsTraceEnabled = false;
217 46 : profOpt.funcsMaxThreadCount = 100;
218 46 : profOpt.statTopCount = 150;
219 :
220 46 : Profiler* profiler = Profiler::instance();
221 46 : profiler->setup(profOpt, new MyPrinter());
222 :
223 : //! --- Setup Ticker ---
224 46 : m_tickerProvider->start();
225 :
226 : //! --- Setup Async ---
227 46 : const std::thread::id thisThId = std::this_thread::get_id();
228 46 : m_asyncTicker.start(1, [thisThId]() {
229 185 : async::processMessages(thisThId);
230 185 : }, Ticker::Mode::Repeat);
231 :
232 : //! --- Diagnostics ---
233 : #ifdef MUSE_MODULE_DIAGNOSTICS
234 46 : auto pr = globalIoc()->resolve<muse::diagnostics::IDiagnosticsPathsRegister>(moduleName());
235 46 : if (pr) {
236 0 : pr->reg("appBinPath", m_configuration->appBinPath());
237 0 : pr->reg("appBinDirPath", m_configuration->appBinDirPath());
238 0 : pr->reg("appDataPath", m_configuration->appDataPath());
239 0 : pr->reg("appConfigPath", m_configuration->appConfigPath());
240 0 : pr->reg("userAppDataPath", m_configuration->userAppDataPath());
241 0 : pr->reg("userBackupPath", m_configuration->userBackupPath());
242 0 : pr->reg("userDataPath", m_configuration->userDataPath());
243 0 : pr->reg("log file", logFilePath);
244 0 : pr->reg("settings file", settings()->filePath());
245 : }
246 : #endif
247 46 : }
248 :
249 46 : void GlobalModule::onInit(const IApplication::RunMode&)
250 : {
251 46 : m_configuration->init();
252 46 : m_systemInfo->init();
253 :
254 46 : m_endTimePeriod = false;
255 :
256 : #ifdef Q_OS_WIN
257 : WaitableTimer timer;
258 : if (m_configuration->highResolutionTimers() || !timer.init()) {
259 : // Improves the accuracy of Sleep() on Windows
260 : // Without it, errors up to 15 ms are possible, which is critical for the audio thread
261 : // and can significantly degrade sound quality
262 : // However, this approach may result in higher CPU usage as a trade-off
263 : LOGI() << "Use timeBeginPeriod(1)";
264 : timeBeginPeriod(1);
265 : m_endTimePeriod = true;
266 : }
267 : #endif
268 46 : }
269 :
270 46 : void GlobalModule::onDeinit()
271 : {
272 46 : m_tickerProvider->stop();
273 46 : muse::async::terminate();
274 :
275 : #ifdef Q_OS_WIN
276 : if (m_endTimePeriod) {
277 : timeEndPeriod(1);
278 : }
279 : #endif
280 46 : }
281 :
282 0 : void GlobalModule::setLoggerLevel(const muse::logger::Level& level)
283 : {
284 0 : m_loggerLevel = level;
285 0 : }
286 :
287 0 : IContextSetup* GlobalModule::newContext(const kors::modularity::ContextPtr& ctx) const
288 : {
289 0 : return new GlobalContext(ctx);
290 : }
291 :
292 0 : void GlobalContext::registerExports()
293 : {
294 0 : }
|