1 /* 2 * Copyright 2017-2020, 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->URL().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 BString depotUrl = depot->URL(); 117 if (identifier == depotUrl) 118 _SetupRepositoryData(depot, repository, repositorySource); 119 } 120 } 121 } 122 123 124 void 125 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository, 126 DumpExportRepositorySource* repositorySource) 127 { 128 if (!repositorySource->IdentifierIsNull()) 129 Handle(*(repositorySource->Identifier()), repository, repositorySource); 130 131 // there may be additional identifiers for the remote repository and 132 // these should also be taken into consideration. 133 134 for(int32 i = 0; 135 i < repositorySource->CountExtraIdentifiers(); 136 i++) 137 { 138 Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository, 139 repositorySource); 140 } 141 } 142 143 144 bool 145 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository) 146 { 147 int32 i; 148 for (i = 0; i < repository->CountRepositorySources(); i++) 149 Handle(repository, repository->RepositorySourcesItemAt(i)); 150 return !fStoppable->WasStopped(); 151 } 152 153 154 void 155 DepotMatchingRepositoryListener::Complete() 156 { 157 } 158 159 160 ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess( 161 Model* model, 162 uint32 serverProcessOptions) 163 : 164 AbstractSingleFileServerProcess(serverProcessOptions), 165 fModel(model) 166 { 167 } 168 169 170 ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess() 171 { 172 } 173 174 175 const char* 176 ServerRepositoryDataUpdateProcess::Name() const 177 { 178 return "ServerRepositoryDataUpdateProcess"; 179 } 180 181 182 const char* 183 ServerRepositoryDataUpdateProcess::Description() const 184 { 185 return B_TRANSLATE("Synchronizing meta-data about repositories"); 186 } 187 188 189 BString 190 ServerRepositoryDataUpdateProcess::UrlPathComponent() 191 { 192 BString result; 193 AutoLocker<BLocker> locker(fModel->Lock()); 194 result.SetToFormat("/__repository/all-%s.json.gz", 195 fModel->Language()->PreferredLanguage()->Code()); 196 return result; 197 } 198 199 200 status_t 201 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const 202 { 203 AutoLocker<BLocker> locker(fModel->Lock()); 204 return fModel->DumpExportRepositoryDataPath(path); 205 } 206 207 208 status_t 209 ServerRepositoryDataUpdateProcess::ProcessLocalData() 210 { 211 DepotMatchingRepositoryListener* itemListener = 212 new DepotMatchingRepositoryListener(fModel, this); 213 ObjectDeleter<DepotMatchingRepositoryListener> 214 itemListenerDeleter(itemListener); 215 216 BulkContainerDumpExportRepositoryJsonListener* listener = 217 new BulkContainerDumpExportRepositoryJsonListener(itemListener); 218 ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> 219 listenerDeleter(listener); 220 221 BPath localPath; 222 status_t result = GetLocalPath(localPath); 223 224 if (result != B_OK) 225 return result; 226 227 result = ParseJsonFromFileWithListener(listener, localPath); 228 229 if (result != B_OK) 230 return result; 231 232 return listener->ErrorStatus(); 233 } 234 235 236 status_t 237 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 238 { 239 return GetLocalPath(path); 240 } 241 242 243 void 244 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 245 BString& jsonPath) const 246 { 247 jsonPath.SetTo("$.info"); 248 } 249