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* 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* 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* 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* 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* 170 ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model, 171 ScreenshotCoordinate& screenshotCoordinate) 172 { 173 return _CreateSingleProcessCoordinator("CacheScreenshot", 174 new CacheScreenshotProcess(model, screenshotCoordinate)); 175 } 176 177 178 /*static*/ ProcessCoordinator* 179 ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(Model* model, PackageInfoRef package) 180 { 181 return _CreateSingleProcessCoordinator("PopulatePkgChangelog", 182 new PopulatePkgChangelogFromServerProcess(package, model)); 183 } 184 185 186 /*static*/ ProcessCoordinator* 187 ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, PackageInfoRef package) 188 { 189 return _CreateSingleProcessCoordinator("PopulatePkgUserRatings", 190 new PopulatePkgUserRatingsFromServerProcess(package, model)); 191 } 192 193 194 /*static*/ PackageInfoRef 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* 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* 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* 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 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* 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