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", 194 fModel->Language()->PreferredLanguage()->ID()); 195 return result; 196 } 197 198 199 status_t 200 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const 201 { 202 AutoLocker<BLocker> locker(fModel->Lock()); 203 return fModel->DumpExportRepositoryDataPath(path); 204 } 205 206 207 status_t 208 ServerRepositoryDataUpdateProcess::ProcessLocalData() 209 { 210 DepotMatchingRepositoryListener* itemListener = 211 new DepotMatchingRepositoryListener(fModel, this); 212 ObjectDeleter<DepotMatchingRepositoryListener> 213 itemListenerDeleter(itemListener); 214 215 BulkContainerDumpExportRepositoryJsonListener* listener = 216 new BulkContainerDumpExportRepositoryJsonListener(itemListener); 217 ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> 218 listenerDeleter(listener); 219 220 BPath localPath; 221 status_t result = GetLocalPath(localPath); 222 223 if (result != B_OK) 224 return result; 225 226 result = ParseJsonFromFileWithListener(listener, localPath); 227 228 if (result != B_OK) 229 return result; 230 231 return listener->ErrorStatus(); 232 } 233 234 235 status_t 236 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 237 { 238 return GetLocalPath(path); 239 } 240 241 242 void 243 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 244 BString& jsonPath) const 245 { 246 jsonPath.SetTo("$.info"); 247 } 248