1 /*
2 * Copyright 2018-2024, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5 #include "ProcessCoordinatorFactory.h"
6
7 #include <Autolock.h>
8 #include <AutoLocker.h>
9
10 #include <package/Context.h>
11 #include <package/PackageRoster.h>
12
13 #include "AbstractServerProcess.h"
14 #include "CacheScreenshotProcess.h"
15 #include "DeskbarLink.h"
16 #include "HaikuDepotConstants.h"
17 #include "IncrementViewCounterProcess.h"
18 #include "InstallPackageProcess.h"
19 #include "LocalPkgDataLoadProcess.h"
20 #include "LocalRepositoryUpdateProcess.h"
21 #include "Logger.h"
22 #include "Model.h"
23 #include "OpenPackageProcess.h"
24 #include "PackageInfoListener.h"
25 #include "PopulatePkgChangelogFromServerProcess.h"
26 #include "PopulatePkgSizesProcess.h"
27 #include "PopulatePkgUserRatingsFromServerProcess.h"
28 #include "ProcessCoordinator.h"
29 #include "ServerHelper.h"
30 #include "ServerIconExportUpdateProcess.h"
31 #include "ServerPkgDataUpdateProcess.h"
32 #include "ServerReferenceDataUpdateProcess.h"
33 #include "ServerRepositoryDataUpdateProcess.h"
34 #include "ServerSettings.h"
35 #include "StorageUtils.h"
36 #include "ThreadedProcessNode.h"
37 #include "UninstallPackageProcess.h"
38 #include "UserDetailVerifierProcess.h"
39
40
41 using namespace BPackageKit;
42
43
44 /*static*/ ProcessCoordinator*
CreateIncrementViewCounter(Model * model,const PackageInfoRef package)45 ProcessCoordinatorFactory::CreateIncrementViewCounter(
46 Model* model, const PackageInfoRef package)
47 {
48 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
49 "IncrementViewCounter");
50 AbstractProcessNode* node = new ThreadedProcessNode(
51 new IncrementViewCounterProcess(model, package));
52 processCoordinator->AddNode(node);
53 return processCoordinator;
54 }
55
56
57 /*static*/ ProcessCoordinator*
CreateUserDetailVerifierCoordinator(UserDetailVerifierListener * userDetailVerifierListener,Model * model)58 ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
59 UserDetailVerifierListener* userDetailVerifierListener,
60 Model* model)
61 {
62 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
63 "UserDetailVerifier");
64 AbstractProcessNode* userDetailVerifier = new ThreadedProcessNode(
65 new UserDetailVerifierProcess(model, userDetailVerifierListener));
66 processCoordinator->AddNode(userDetailVerifier);
67 return processCoordinator;
68 }
69
70
71 /* static */ ProcessCoordinator*
CreateBulkLoadCoordinator(PackageInfoListenerRef packageInfoListener,Model * model,bool forceLocalUpdate)72 ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
73 PackageInfoListenerRef packageInfoListener,
74 Model* model, bool forceLocalUpdate)
75 {
76 bool areWorkingFilesAvailable = StorageUtils::AreWorkingFilesAvailable();
77 uint32 serverProcessOptions = _CalculateServerProcessOptions();
78 BAutolock locker(model->Lock());
79 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
80 "BulkLoad", new BMessage(MSG_BULK_LOAD_DONE));
81
82 AbstractProcessNode *localRepositoryUpdate =
83 new ThreadedProcessNode(new LocalRepositoryUpdateProcess(model,
84 forceLocalUpdate));
85 processCoordinator->AddNode(localRepositoryUpdate);
86
87 AbstractProcessNode *localPkgDataLoad =
88 new ThreadedProcessNode(new LocalPkgDataLoadProcess(
89 packageInfoListener, model, forceLocalUpdate));
90 localPkgDataLoad->AddPredecessor(localRepositoryUpdate);
91 processCoordinator->AddNode(localPkgDataLoad);
92
93 if (areWorkingFilesAvailable) {
94 AbstractProcessNode *serverIconExportUpdate =
95 new ThreadedProcessNode(new ServerIconExportUpdateProcess(model,
96 serverProcessOptions));
97 serverIconExportUpdate->AddPredecessor(localPkgDataLoad);
98 processCoordinator->AddNode(serverIconExportUpdate);
99
100 AbstractProcessNode *serverRepositoryDataUpdate =
101 new ThreadedProcessNode(new ServerRepositoryDataUpdateProcess(model,
102 serverProcessOptions));
103 serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
104 processCoordinator->AddNode(serverRepositoryDataUpdate);
105
106 AbstractProcessNode *serverReferenceDataUpdate =
107 new ThreadedProcessNode(new ServerReferenceDataUpdateProcess(model,
108 serverProcessOptions));
109 processCoordinator->AddNode(serverReferenceDataUpdate);
110
111 // This one has to run after the server data is taken up because it
112 // will fill in the gaps based on local data that was not able to be
113 // sourced from the server. It has all of the
114 // `ServerPkgDataUpdateProcess` nodes configured as its predecessors.
115
116 AbstractProcessNode* populatePkgSizes =
117 new ThreadedProcessNode(new PopulatePkgSizesProcess(model));
118
119 // create a process for each of the repositories that are configured on
120 // the local system. Later, only those that have a web-app repository
121 // server code will be actually processed, but this means that the
122 // creation of the 'processes' does not need to be dynamic as the
123 // process coordinator runs.
124
125 BPackageRoster roster;
126 BStringList repoNames;
127 status_t repoNamesResult = roster.GetRepositoryNames(repoNames);
128
129 if (repoNamesResult == B_OK) {
130 AutoLocker<BLocker> locker(model->Lock());
131
132 for (int32 i = 0; i < repoNames.CountStrings(); i++) {
133 AbstractProcessNode* processNode = new ThreadedProcessNode(
134 new ServerPkgDataUpdateProcess(
135 repoNames.StringAt(i), model, serverProcessOptions));
136 processNode->AddPredecessor(serverRepositoryDataUpdate);
137 processNode->AddPredecessor(serverReferenceDataUpdate);
138 processCoordinator->AddNode(processNode);
139
140 populatePkgSizes->AddPredecessor(processNode);
141 }
142 } else
143 HDERROR("a problem has arisen getting the repository names.");
144
145 processCoordinator->AddNode(populatePkgSizes);
146 }
147
148 return processCoordinator;
149 }
150
151
152 /*static*/ ProcessCoordinator*
CreatePackageActionCoordinator(Model * model,BMessage * message)153 ProcessCoordinatorFactory::CreatePackageActionCoordinator(
154 Model* model, BMessage* message)
155 {
156 switch (message->what) {
157 case MSG_PKG_INSTALL:
158 return _CreateInstallPackageActionCoordinator(model, message);
159 case MSG_PKG_UNINSTALL:
160 return _CreateUninstallPackageActionCoordinator(model, message);
161 case MSG_PKG_OPEN:
162 return _CreateOpenPackageActionCoordinator(model, message);
163 default:
164 HDFATAL("unexpected package action message what");
165 }
166 }
167
168
169 /*static*/ ProcessCoordinator*
CacheScreenshotCoordinator(Model * model,ScreenshotCoordinate & screenshotCoordinate)170 ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model,
171 ScreenshotCoordinate& screenshotCoordinate)
172 {
173 return _CreateSingleProcessCoordinator("CacheScreenshot",
174 new CacheScreenshotProcess(model, screenshotCoordinate));
175 }
176
177
178 /*static*/ ProcessCoordinator*
PopulatePkgChangelogCoordinator(Model * model,PackageInfoRef package)179 ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(Model* model, PackageInfoRef package)
180 {
181 return _CreateSingleProcessCoordinator("PopulatePkgChangelog",
182 new PopulatePkgChangelogFromServerProcess(package, model));
183 }
184
185
186 /*static*/ ProcessCoordinator*
PopulatePkgUserRatingsCoordinator(Model * model,PackageInfoRef package)187 ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, PackageInfoRef package)
188 {
189 return _CreateSingleProcessCoordinator("PopulatePkgUserRatings",
190 new PopulatePkgUserRatingsFromServerProcess(package, model));
191 }
192
193
194 /*static*/ PackageInfoRef
_ExtractPackageFromMessage(Model * model,BMessage * message)195 ProcessCoordinatorFactory::_ExtractPackageFromMessage(
196 Model* model, BMessage* message)
197 {
198 BString pkgName;
199 if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK)
200 HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME);
201 return model->PackageForName(pkgName);
202 }
203
204
205 /*static*/ ProcessCoordinator*
_CreateInstallPackageActionCoordinator(Model * model,BMessage * message)206 ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(
207 Model* model, BMessage* message)
208 {
209 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
210 "InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
211 PackageInfoRef package = _ExtractPackageFromMessage(model, message);
212 if (package.IsSet()) {
213 AbstractProcessNode *processNode =
214 new ThreadedProcessNode(
215 new InstallPackageProcess(package, model), 10);
216 processCoordinator->AddNode(processNode);
217 } else {
218 HDERROR("unable to find the package");
219 }
220 return processCoordinator;
221 }
222
223
224 /*static*/ ProcessCoordinator*
_CreateUninstallPackageActionCoordinator(Model * model,BMessage * message)225 ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(
226 Model* model, BMessage* message)
227 {
228 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
229 "UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
230 PackageInfoRef package = _ExtractPackageFromMessage(model, message);
231 if (package.IsSet()) {
232 AbstractProcessNode *processNode =
233 new ThreadedProcessNode(
234 new UninstallPackageProcess(package, model), 10);
235 processCoordinator->AddNode(processNode);
236 } else {
237 HDERROR("unable to find the package");
238 }
239 return processCoordinator;
240 }
241
242
243 /*static*/ ProcessCoordinator*
_CreateOpenPackageActionCoordinator(Model * model,BMessage * message)244 ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator(
245 Model* model, BMessage* message)
246 {
247 ProcessCoordinator* processCoordinator = new ProcessCoordinator(
248 "OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
249 PackageInfoRef package = _ExtractPackageFromMessage(model, message);
250 if (package.IsSet()) {
251 BMessage deskbarLinkMessage;
252 if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK)
253 HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK);
254 DeskbarLink deskbarLink(&deskbarLinkMessage);
255 AbstractProcessNode *processNode =
256 new ThreadedProcessNode(new OpenPackageProcess(
257 package, model, deskbarLink));
258 processCoordinator->AddNode(processNode);
259 } else {
260 HDERROR("unable to find the package");
261 }
262 return processCoordinator;
263 }
264
265
266 /* static */ uint32
_CalculateServerProcessOptions()267 ProcessCoordinatorFactory::_CalculateServerProcessOptions()
268 {
269 uint32 processOptions = 0;
270
271 if (ServerSettings::IsClientTooOld()) {
272 HDINFO("bulk load proceeding without network communications "
273 "because the client is too old");
274 processOptions |= SERVER_PROCESS_NO_NETWORKING;
275 }
276
277 if (!ServerHelper::IsNetworkAvailable())
278 processOptions |= SERVER_PROCESS_NO_NETWORKING;
279
280 if (ServerSettings::PreferCache())
281 processOptions |= SERVER_PROCESS_PREFER_CACHE;
282
283 if (ServerSettings::DropCache())
284 processOptions |= SERVER_PROCESS_DROP_CACHE;
285
286 return processOptions;
287 }
288
289
290 /*static*/ ProcessCoordinator*
_CreateSingleProcessCoordinator(const char * name,AbstractProcess * process)291 ProcessCoordinatorFactory::_CreateSingleProcessCoordinator(const char* name,
292 AbstractProcess* process)
293 {
294 ProcessCoordinator* processCoordinator = new ProcessCoordinator(name);
295 AbstractProcessNode* cacheScreenshotNode = new ThreadedProcessNode(process);
296 processCoordinator->AddNode(cacheScreenshotNode);
297 return processCoordinator;
298 }
299