1 /* 2 * Copyright 2017-2023, Andrew Lindesay <apl@lindesay.co.nz>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 #include "ServerRepositoryDataUpdateProcess.h" 6 7 #include <stdio.h> 8 #include <sys/stat.h> 9 #include <time.h> 10 11 #include <AutoDeleter.h> 12 #include <Autolock.h> 13 #include <Catalog.h> 14 #include <FileIO.h> 15 #include <Url.h> 16 17 #include "DumpExportRepository.h" 18 #include "DumpExportRepositoryJsonListener.h" 19 #include "DumpExportRepositorySource.h" 20 #include "PackageInfo.h" 21 #include "ServerSettings.h" 22 #include "StorageUtils.h" 23 #include "Logger.h" 24 25 26 #undef B_TRANSLATION_CONTEXT 27 #define B_TRANSLATION_CONTEXT "ServerRepositoryDataUpdateProcess" 28 29 30 /*! This repository listener (not at the JSON level) is feeding in the 31 repositories as they are parsed and processing them. Processing 32 includes finding the matching depot record and coupling the data 33 from the server with the data about the depot. 34 */ 35 36 class DepotMatchingRepositoryListener : 37 public DumpExportRepositoryListener { 38 public: 39 DepotMatchingRepositoryListener(Model* model, 40 Stoppable* stoppable); 41 virtual ~DepotMatchingRepositoryListener(); 42 43 virtual bool Handle(DumpExportRepository* item); 44 void Handle(DumpExportRepository* repository, 45 DumpExportRepositorySource* 46 repositorySource); 47 void Handle(const BString& identifier, 48 DumpExportRepository* repository, 49 DumpExportRepositorySource* 50 repositorySource); 51 virtual void Complete(); 52 53 private: 54 void _SetupRepositoryData( 55 DepotInfoRef& depot, 56 DumpExportRepository* repository, 57 DumpExportRepositorySource* 58 repositorySource); 59 60 private: 61 Model* fModel; 62 Stoppable* fStoppable; 63 }; 64 65 66 DepotMatchingRepositoryListener::DepotMatchingRepositoryListener( 67 Model* model, Stoppable* stoppable) 68 : 69 fModel(model), 70 fStoppable(stoppable) 71 { 72 } 73 74 75 DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener() 76 { 77 } 78 79 80 void 81 DepotMatchingRepositoryListener::_SetupRepositoryData(DepotInfoRef& depot, 82 DumpExportRepository* repository, 83 DumpExportRepositorySource* repositorySource) 84 { 85 BString* repositoryCode = repository->Code(); 86 BString* repositorySourceCode = repositorySource->Code(); 87 88 depot->SetWebAppRepositoryCode(*repositoryCode); 89 depot->SetWebAppRepositorySourceCode(*repositorySourceCode); 90 91 if (Logger::IsDebugEnabled()) { 92 HDDEBUG("[DepotMatchingRepositoryListener] associated depot [%s] (%s) " 93 "with server repository source [%s] (%s)", 94 depot->Name().String(), 95 depot->Identifier().String(), 96 repositorySourceCode->String(), 97 repositorySource->Identifier()->String()); 98 } else { 99 HDINFO("[DepotMatchingRepositoryListener] associated depot [%s] with " 100 "server repository source [%s]", 101 depot->Name().String(), 102 repositorySourceCode->String()); 103 } 104 } 105 106 107 void 108 DepotMatchingRepositoryListener::Handle(const BString& identifier, 109 DumpExportRepository* repository, 110 DumpExportRepositorySource* repositorySource) 111 { 112 if (!identifier.IsEmpty()) { 113 AutoLocker<BLocker> locker(fModel->Lock()); 114 for (int32 i = 0; i < fModel->CountDepots(); i++) { 115 DepotInfoRef depot = fModel->DepotAtIndex(i); 116 if (identifier == depot->Identifier()) 117 _SetupRepositoryData(depot, repository, repositorySource); 118 } 119 } 120 } 121 122 123 void 124 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository, 125 DumpExportRepositorySource* repositorySource) 126 { 127 if (!repositorySource->IdentifierIsNull()) 128 Handle(*(repositorySource->Identifier()), repository, repositorySource); 129 130 // there may be additional identifiers for the remote repository and 131 // these should also be taken into consideration. 132 133 for(int32 i = 0; 134 i < repositorySource->CountExtraIdentifiers(); 135 i++) 136 { 137 Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository, 138 repositorySource); 139 } 140 } 141 142 143 bool 144 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository) 145 { 146 int32 i; 147 for (i = 0; i < repository->CountRepositorySources(); i++) 148 Handle(repository, repository->RepositorySourcesItemAt(i)); 149 return !fStoppable->WasStopped(); 150 } 151 152 153 void 154 DepotMatchingRepositoryListener::Complete() 155 { 156 } 157 158 159 ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess( 160 Model* model, 161 uint32 serverProcessOptions) 162 : 163 AbstractSingleFileServerProcess(serverProcessOptions), 164 fModel(model) 165 { 166 } 167 168 169 ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess() 170 { 171 } 172 173 174 const char* 175 ServerRepositoryDataUpdateProcess::Name() const 176 { 177 return "ServerRepositoryDataUpdateProcess"; 178 } 179 180 181 const char* 182 ServerRepositoryDataUpdateProcess::Description() const 183 { 184 return B_TRANSLATE("Synchronizing meta-data about repositories"); 185 } 186 187 188 BString 189 ServerRepositoryDataUpdateProcess::UrlPathComponent() 190 { 191 BString result; 192 AutoLocker<BLocker> locker(fModel->Lock()); 193 result.SetToFormat("/__repository/all-%s.json.gz", fModel->PreferredLanguage()->ID()); 194 return result; 195 } 196 197 198 status_t 199 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const 200 { 201 AutoLocker<BLocker> locker(fModel->Lock()); 202 return StorageUtils::DumpExportRepositoryDataPath(path, fModel->PreferredLanguage()); 203 } 204 205 206 status_t 207 ServerRepositoryDataUpdateProcess::ProcessLocalData() 208 { 209 DepotMatchingRepositoryListener* itemListener = 210 new DepotMatchingRepositoryListener(fModel, this); 211 ObjectDeleter<DepotMatchingRepositoryListener> 212 itemListenerDeleter(itemListener); 213 214 BulkContainerDumpExportRepositoryJsonListener* listener = 215 new BulkContainerDumpExportRepositoryJsonListener(itemListener); 216 ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> 217 listenerDeleter(listener); 218 219 BPath localPath; 220 status_t result = GetLocalPath(localPath); 221 222 if (result != B_OK) 223 return result; 224 225 result = ParseJsonFromFileWithListener(listener, localPath); 226 227 if (result != B_OK) 228 return result; 229 230 return listener->ErrorStatus(); 231 } 232 233 234 status_t 235 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 236 { 237 return GetLocalPath(path); 238 } 239 240 241 void 242 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 243 BString& jsonPath) const 244 { 245 jsonPath.SetTo("$.info"); 246 } 247