1 /* 2 * Copyright 2018-2021, 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 PackageInfoListener *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(new InstallPackageProcess(package, model)); 177 processCoordinator->AddNode(processNode); 178 } else { 179 HDERROR("unable to find the package"); 180 } 181 return processCoordinator; 182 } 183 184 185 /*static*/ ProcessCoordinator* 186 ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator( 187 Model* model, BMessage* message) 188 { 189 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 190 "UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 191 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 192 if (package.IsSet()) { 193 AbstractProcessNode *processNode = 194 new ThreadedProcessNode(new UninstallPackageProcess( 195 package, model)); 196 processCoordinator->AddNode(processNode); 197 } else { 198 HDERROR("unable to find the package"); 199 } 200 return processCoordinator; 201 } 202 203 204 /*static*/ ProcessCoordinator* 205 ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator( 206 Model* model, BMessage* message) 207 { 208 ProcessCoordinator* processCoordinator = new ProcessCoordinator( 209 "OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); 210 PackageInfoRef package = _ExtractPackageFromMessage(model, message); 211 if (package.IsSet()) { 212 BMessage deskbarLinkMessage; 213 if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK) 214 HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK); 215 DeskbarLink deskbarLink(&deskbarLinkMessage); 216 AbstractProcessNode *processNode = 217 new ThreadedProcessNode(new OpenPackageProcess( 218 package, model, deskbarLink)); 219 processCoordinator->AddNode(processNode); 220 } else { 221 HDERROR("unable to find the package"); 222 } 223 return processCoordinator; 224 } 225 226 227 /* static */ uint32 228 ProcessCoordinatorFactory::_CalculateServerProcessOptions() 229 { 230 uint32 processOptions = 0; 231 232 if (ServerSettings::IsClientTooOld()) { 233 HDINFO("bulk load proceeding without network communications " 234 "because the client is too old"); 235 processOptions |= SERVER_PROCESS_NO_NETWORKING; 236 } 237 238 if (!ServerHelper::IsNetworkAvailable()) 239 processOptions |= SERVER_PROCESS_NO_NETWORKING; 240 241 if (ServerSettings::PreferCache()) 242 processOptions |= SERVER_PROCESS_PREFER_CACHE; 243 244 if (ServerSettings::DropCache()) 245 processOptions |= SERVER_PROCESS_DROP_CACHE; 246 247 return processOptions; 248 } 249