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 36class DepotMatchingRepositoryListener : 37 public DumpExportRepositoryListener { 38public: 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 53private: 54 void _SetupRepositoryData( 55 DepotInfoRef& depot, 56 DumpExportRepository* repository, 57 DumpExportRepositorySource* 58 repositorySource); 59 60private: 61 Model* fModel; 62 Stoppable* fStoppable; 63}; 64 65 66DepotMatchingRepositoryListener::DepotMatchingRepositoryListener( 67 Model* model, Stoppable* stoppable) 68 : 69 fModel(model), 70 fStoppable(stoppable) 71{ 72} 73 74 75DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener() 76{ 77} 78 79 80void 81DepotMatchingRepositoryListener::_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 107void 108DepotMatchingRepositoryListener::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 123void 124DepotMatchingRepositoryListener::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 143bool 144DepotMatchingRepositoryListener::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 153void 154DepotMatchingRepositoryListener::Complete() 155{ 156} 157 158 159ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess( 160 Model* model, 161 uint32 serverProcessOptions) 162 : 163 AbstractSingleFileServerProcess(serverProcessOptions), 164 fModel(model) 165{ 166} 167 168 169ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess() 170{ 171} 172 173 174const char* 175ServerRepositoryDataUpdateProcess::Name() const 176{ 177 return "ServerRepositoryDataUpdateProcess"; 178} 179 180 181const char* 182ServerRepositoryDataUpdateProcess::Description() const 183{ 184 return B_TRANSLATE("Synchronizing meta-data about repositories"); 185} 186 187 188BString 189ServerRepositoryDataUpdateProcess::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 199status_t 200ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const 201{ 202 AutoLocker<BLocker> locker(fModel->Lock()); 203 return fModel->DumpExportRepositoryDataPath(path); 204} 205 206 207status_t 208ServerRepositoryDataUpdateProcess::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 235status_t 236ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 237{ 238 return GetLocalPath(path); 239} 240 241 242void 243ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 244 BString& jsonPath) const 245{ 246 jsonPath.SetTo("$.info"); 247} 248