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