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