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