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 "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 // create a process for each of the repositories that are configured on 110 // the local system. Later, only those that have a web-app repository 111 // server code will be actually processed, but this means that the 112 // creation of the 'processes' does not need to be dynamic as the 113 // process coordinator runs. 114 115 BPackageRoster roster; 116 BStringList repoNames; 117 status_t repoNamesResult = roster.GetRepositoryNames(repoNames); 118 119 if (repoNamesResult == B_OK) { 120 AutoLocker<BLocker> locker(model->Lock()); 121 122 for (int32 i = 0; i < repoNames.CountStrings(); i++) { 123 AbstractProcessNode* processNode = new ThreadedProcessNode( 124 new ServerPkgDataUpdateProcess( 125 model->Language()->PreferredLanguage()->Code(), 126 repoNames.StringAt(i), model, serverProcessOptions)); 127 processNode->AddPredecessor(serverRepositoryDataUpdate); 128 processNode->AddPredecessor(serverReferenceDataUpdate); 129 processCoordinator->AddNode(processNode); 130 } 131 } else 132 HDERROR("a problem has arisen getting the repository names."); 133 } 134 135 return processCoordinator; 136 } 137 138 139 /*static*/ ProcessCoordinator* 140 ProcessCoordinatorFactory::CreatePackageActionCoordinator( 141 Model* model, BMessage* message) 142 { 143 switch (message->what) { 144 case MSG_PKG_INSTALL: 145 return _CreateInstallPackageActionCoordinator(model, message); 146 case MSG_PKG_UNINSTALL: 147 return _CreateUninstallPackageActionCoordinator(model, message); 148 case MSG_PKG_OPEN: 149 return _CreateOpenPackageActionCoordinator(model, message); 150 default: 151 HDFATAL("unexpected package action message what"); 152 } 153 } 154 155 156 /*static*/ PackageInfoRef 157 ProcessCoordinatorFactory::_ExtractPackageFromMessage( 158 Model* model, BMessage* message) 159 { 160 BString pkgName; 161 if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK) 162 HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME); 163 return model->PackageForName(pkgName); 164 } 165 166 167 /*static*/ ProcessCoordinator* 168 ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator( 169 Model* model, BMessage* message) 170 { 171 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 172 "InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 173 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 174 if (package.IsSet()) { 175 AbstractProcessNode *processNode = 176 new ThreadedProcessNode( 177 new InstallPackageProcess(package, model), 10); 178 processCoordinator->AddNode(processNode); 179 } else { 180 HDERROR("unable to find the package"); 181 } 182 return processCoordinator; 183 } 184 185 186 /*static*/ ProcessCoordinator* 187 ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator( 188 Model* model, BMessage* message) 189 { 190 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 191 "UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 192 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 193 if (package.IsSet()) { 194 AbstractProcessNode *processNode = 195 new ThreadedProcessNode( 196 new UninstallPackageProcess(package, model), 10); 197 processCoordinator->AddNode(processNode); 198 } else { 199 HDERROR("unable to find the package"); 200 } 201 return processCoordinator; 202 } 203 204 205 /*static*/ ProcessCoordinator* 206 ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator( 207 Model* model, BMessage* message) 208 { 209 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 210 "OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 211 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 212 if (package.IsSet()) { 213 BMessage deskbarLinkMessage; 214 if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK) 215 HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK); 216 DeskbarLink deskbarLink(&deskbarLinkMessage); 217 AbstractProcessNode *processNode = 218 new ThreadedProcessNode(new OpenPackageProcess( 219 package, model, deskbarLink)); 220 processCoordinator->AddNode(processNode); 221 } else { 222 HDERROR("unable to find the package"); 223 } 224 return processCoordinator; 225 } 226 227 228 /* static */ uint32 229 ProcessCoordinatorFactory::_CalculateServerProcessOptions() 230 { 231 uint32 processOptions = 0; 232 233 if (ServerSettings::IsClientTooOld()) { 234 HDINFO("bulk load proceeding without network communications " 235 "because the client is too old"); 236 processOptions |= SERVER_PROCESS_NO_NETWORKING; 237 } 238 239 if (!ServerHelper::IsNetworkAvailable()) 240 processOptions |= SERVER_PROCESS_NO_NETWORKING; 241 242 if (ServerSettings::PreferCache()) 243 processOptions |= SERVER_PROCESS_PREFER_CACHE; 244 245 if (ServerSettings::DropCache()) 246 processOptions |= SERVER_PROCESS_DROP_CACHE; 247 248 return processOptions; 249 } 250