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 model->Language()->PreferredLanguage()->Code(), 134 repoNames.StringAt(i), model, serverProcessOptions)); 135 processNode->AddPredecessor(serverRepositoryDataUpdate); 136 processNode->AddPredecessor(serverReferenceDataUpdate); 137 processCoordinator->AddNode(processNode); 138 139 populatePkgSizes->AddPredecessor(processNode); 140 } 141 } else 142 HDERROR("a problem has arisen getting the repository names."); 143 144 processCoordinator->AddNode(populatePkgSizes); 145 } 146 147 return processCoordinator; 148 } 149 150 151 /*static*/ ProcessCoordinator* 152 ProcessCoordinatorFactory::CreatePackageActionCoordinator( 153 Model* model, BMessage* message) 154 { 155 switch (message->what) { 156 case MSG_PKG_INSTALL: 157 return _CreateInstallPackageActionCoordinator(model, message); 158 case MSG_PKG_UNINSTALL: 159 return _CreateUninstallPackageActionCoordinator(model, message); 160 case MSG_PKG_OPEN: 161 return _CreateOpenPackageActionCoordinator(model, message); 162 default: 163 HDFATAL("unexpected package action message what"); 164 } 165 } 166 167 168 /*static*/ ProcessCoordinator* 169 ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model, 170 ScreenshotCoordinate& screenshotCoordinate) 171 { 172 ProcessCoordinator* processCoordinator = new ProcessCoordinator("CacheScreenshot"); 173 AbstractProcessNode* cacheScreenshotNode = new ThreadedProcessNode( 174 new CacheScreenshotProcess(model, screenshotCoordinate)); 175 processCoordinator->AddNode(cacheScreenshotNode); 176 return processCoordinator; 177 } 178 179 180 /*static*/ PackageInfoRef 181 ProcessCoordinatorFactory::_ExtractPackageFromMessage( 182 Model* model, BMessage* message) 183 { 184 BString pkgName; 185 if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK) 186 HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME); 187 return model->PackageForName(pkgName); 188 } 189 190 191 /*static*/ ProcessCoordinator* 192 ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator( 193 Model* model, BMessage* message) 194 { 195 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 196 "InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 197 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 198 if (package.IsSet()) { 199 AbstractProcessNode *processNode = 200 new ThreadedProcessNode( 201 new InstallPackageProcess(package, model), 10); 202 processCoordinator->AddNode(processNode); 203 } else { 204 HDERROR("unable to find the package"); 205 } 206 return processCoordinator; 207 } 208 209 210 /*static*/ ProcessCoordinator* 211 ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator( 212 Model* model, BMessage* message) 213 { 214 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 215 "UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 216 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 217 if (package.IsSet()) { 218 AbstractProcessNode *processNode = 219 new ThreadedProcessNode( 220 new UninstallPackageProcess(package, model), 10); 221 processCoordinator->AddNode(processNode); 222 } else { 223 HDERROR("unable to find the package"); 224 } 225 return processCoordinator; 226 } 227 228 229 /*static*/ ProcessCoordinator* 230 ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator( 231 Model* model, BMessage* message) 232 { 233 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 234 "OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 235 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 236 if (package.IsSet()) { 237 BMessage deskbarLinkMessage; 238 if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK) 239 HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK); 240 DeskbarLink deskbarLink(&deskbarLinkMessage); 241 AbstractProcessNode *processNode = 242 new ThreadedProcessNode(new OpenPackageProcess( 243 package, model, deskbarLink)); 244 processCoordinator->AddNode(processNode); 245 } else { 246 HDERROR("unable to find the package"); 247 } 248 return processCoordinator; 249 } 250 251 252 /* static */ uint32 253 ProcessCoordinatorFactory::_CalculateServerProcessOptions() 254 { 255 uint32 processOptions = 0; 256 257 if (ServerSettings::IsClientTooOld()) { 258 HDINFO("bulk load proceeding without network communications " 259 "because the client is too old"); 260 processOptions |= SERVER_PROCESS_NO_NETWORKING; 261 } 262 263 if (!ServerHelper::IsNetworkAvailable()) 264 processOptions |= SERVER_PROCESS_NO_NETWORKING; 265 266 if (ServerSettings::PreferCache()) 267 processOptions |= SERVER_PROCESS_PREFER_CACHE; 268 269 if (ServerSettings::DropCache()) 270 processOptions |= SERVER_PROCESS_DROP_CACHE; 271 272 return processOptions; 273 } 274