xref: /haiku/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp (revision 4c07199d8201fcf267e90be0d24b76799d03cea6)
1 /*
2  * Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ProcessCoordinatorFactory.h"
8 
9 #include <Autolock.h>
10 #include <AutoLocker.h>
11 
12 #include <package/Context.h>
13 #include <package/PackageRoster.h>
14 
15 #include "AbstractServerProcess.h"
16 #include "DeskbarLink.h"
17 #include "HaikuDepotConstants.h"
18 #include "IncrementViewCounterProcess.h"
19 #include "InstallPackageProcess.h"
20 #include "LocalPkgDataLoadProcess.h"
21 #include "LocalRepositoryUpdateProcess.h"
22 #include "Logger.h"
23 #include "Model.h"
24 #include "OpenPackageProcess.h"
25 #include "PackageInfoListener.h"
26 #include "PopulatePkgSizesProcess.h"
27 #include "ProcessCoordinator.h"
28 #include "ServerHelper.h"
29 #include "ServerIconExportUpdateProcess.h"
30 #include "ServerPkgDataUpdateProcess.h"
31 #include "ServerReferenceDataUpdateProcess.h"
32 #include "ServerRepositoryDataUpdateProcess.h"
33 #include "ServerSettings.h"
34 #include "StorageUtils.h"
35 #include "ThreadedProcessNode.h"
36 #include "UninstallPackageProcess.h"
37 #include "UserDetailVerifierProcess.h"
38 
39 
40 using namespace BPackageKit;
41 
42 
43 /*static*/ ProcessCoordinator*
44 ProcessCoordinatorFactory::CreateIncrementViewCounter(
45 	Model* model, const PackageInfoRef package)
46 {
47 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
48 		"IncrementViewCounter");
49 	AbstractProcessNode* node = new ThreadedProcessNode(
50 		new IncrementViewCounterProcess(model, package));
51 	processCoordinator->AddNode(node);
52 	return processCoordinator;
53 }
54 
55 
56 /*static*/ ProcessCoordinator*
57 ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
58 	UserDetailVerifierListener* userDetailVerifierListener,
59 	Model* model)
60 {
61 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
62 		"UserDetailVerifier");
63 	AbstractProcessNode* userDetailVerifier = new ThreadedProcessNode(
64 		new UserDetailVerifierProcess(model, userDetailVerifierListener));
65 	processCoordinator->AddNode(userDetailVerifier);
66 	return processCoordinator;
67 }
68 
69 
70 /* static */ ProcessCoordinator*
71 ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
72 	PackageInfoListenerRef packageInfoListener,
73 	Model* model, bool forceLocalUpdate)
74 {
75 	bool areWorkingFilesAvailable = StorageUtils::AreWorkingFilesAvailable();
76 	uint32 serverProcessOptions = _CalculateServerProcessOptions();
77 	BAutolock locker(model->Lock());
78 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
79 		"BulkLoad", new BMessage(MSG_BULK_LOAD_DONE));
80 
81 	AbstractProcessNode *localRepositoryUpdate =
82 		new ThreadedProcessNode(new LocalRepositoryUpdateProcess(model,
83 			forceLocalUpdate));
84 	processCoordinator->AddNode(localRepositoryUpdate);
85 
86 	AbstractProcessNode *localPkgDataLoad =
87 		new ThreadedProcessNode(new LocalPkgDataLoadProcess(
88 			packageInfoListener, model, forceLocalUpdate));
89 	localPkgDataLoad->AddPredecessor(localRepositoryUpdate);
90 	processCoordinator->AddNode(localPkgDataLoad);
91 
92 	if (areWorkingFilesAvailable) {
93 		AbstractProcessNode *serverIconExportUpdate =
94 			new ThreadedProcessNode(new ServerIconExportUpdateProcess(model,
95 				serverProcessOptions));
96 		serverIconExportUpdate->AddPredecessor(localPkgDataLoad);
97 		processCoordinator->AddNode(serverIconExportUpdate);
98 
99 		AbstractProcessNode *serverRepositoryDataUpdate =
100 			new ThreadedProcessNode(new ServerRepositoryDataUpdateProcess(model,
101 				serverProcessOptions));
102 		serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
103 		processCoordinator->AddNode(serverRepositoryDataUpdate);
104 
105 		AbstractProcessNode *serverReferenceDataUpdate =
106 			new ThreadedProcessNode(new ServerReferenceDataUpdateProcess(model,
107 				serverProcessOptions));
108 		processCoordinator->AddNode(serverReferenceDataUpdate);
109 
110 		// This one has to run after the server data is taken up because it
111 		// will fill in the gaps based on local data that was not able to be
112 		// sourced from the server. It has all of the
113 		// `ServerPkgDataUpdateProcess` nodes configured as its predecessors.
114 
115 		AbstractProcessNode* populatePkgSizes =
116 			new ThreadedProcessNode(new PopulatePkgSizesProcess(model));
117 
118 		// create a process for each of the repositories that are configured on
119 		// the local system.  Later, only those that have a web-app repository
120 		// server code will be actually processed, but this means that the
121 		// creation of the 'processes' does not need to be dynamic as the
122 		// process coordinator runs.
123 
124 		BPackageRoster roster;
125 		BStringList repoNames;
126 		status_t repoNamesResult = roster.GetRepositoryNames(repoNames);
127 
128 		if (repoNamesResult == B_OK) {
129 			AutoLocker<BLocker> locker(model->Lock());
130 
131 			for (int32 i = 0; i < repoNames.CountStrings(); i++) {
132 				AbstractProcessNode* processNode = new ThreadedProcessNode(
133 					new ServerPkgDataUpdateProcess(
134 						model->Language()->PreferredLanguage()->Code(),
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*
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*/ PackageInfoRef
170 ProcessCoordinatorFactory::_ExtractPackageFromMessage(
171 	Model* model, BMessage* message)
172 {
173 	BString pkgName;
174 	if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK)
175 		HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME);
176 	return model->PackageForName(pkgName);
177 }
178 
179 
180 /*static*/ ProcessCoordinator*
181 ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(
182 	Model* model, BMessage* message)
183 {
184 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
185 		"InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
186 	PackageInfoRef package = _ExtractPackageFromMessage(model, message);
187 	if (package.IsSet()) {
188 		AbstractProcessNode *processNode =
189 			new ThreadedProcessNode(
190 				new InstallPackageProcess(package, model), 10);
191 		processCoordinator->AddNode(processNode);
192 	} else {
193 		HDERROR("unable to find the package");
194 	}
195 	return processCoordinator;
196 }
197 
198 
199 /*static*/ ProcessCoordinator*
200 ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(
201 	Model* model, BMessage* message)
202 {
203 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
204 		"UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
205 	PackageInfoRef package = _ExtractPackageFromMessage(model, message);
206 	if (package.IsSet()) {
207 		AbstractProcessNode *processNode =
208 			new ThreadedProcessNode(
209 				new UninstallPackageProcess(package, model), 10);
210 		processCoordinator->AddNode(processNode);
211 	} else {
212 		HDERROR("unable to find the package");
213 	}
214 	return processCoordinator;
215 }
216 
217 
218 /*static*/ ProcessCoordinator*
219 ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator(
220 	Model* model, BMessage* message)
221 {
222 	ProcessCoordinator* processCoordinator = new ProcessCoordinator(
223 		"OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
224 	PackageInfoRef package = _ExtractPackageFromMessage(model, message);
225 	if (package.IsSet()) {
226 		BMessage deskbarLinkMessage;
227 		if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK)
228 			HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK);
229 		DeskbarLink deskbarLink(&deskbarLinkMessage);
230 		AbstractProcessNode *processNode =
231 			new ThreadedProcessNode(new OpenPackageProcess(
232 				package, model, deskbarLink));
233 		processCoordinator->AddNode(processNode);
234 	} else {
235 		HDERROR("unable to find the package");
236 	}
237 	return processCoordinator;
238 }
239 
240 
241 /* static */ uint32
242 ProcessCoordinatorFactory::_CalculateServerProcessOptions()
243 {
244 	uint32 processOptions = 0;
245 
246 	if (ServerSettings::IsClientTooOld()) {
247 		HDINFO("bulk load proceeding without network communications "
248 			"because the client is too old");
249 		processOptions |= SERVER_PROCESS_NO_NETWORKING;
250 	}
251 
252 	if (!ServerHelper::IsNetworkAvailable())
253 		processOptions |= SERVER_PROCESS_NO_NETWORKING;
254 
255 	if (ServerSettings::PreferCache())
256 		processOptions |= SERVER_PROCESS_PREFER_CACHE;
257 
258 	if (ServerSettings::DropCache())
259 		processOptions |= SERVER_PROCESS_DROP_CACHE;
260 
261 	return processOptions;
262 }
263