1 /* 2 * Copyright 2017-2019, 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 return fModel->DumpExportRepositoryDataPath(path); 193 } 194 195 196 status_t 197 ServerRepositoryDataUpdateProcess::ProcessLocalData() 198 { 199 DepotMatchingRepositoryListener* itemListener = 200 new DepotMatchingRepositoryListener(fModel, this); 201 ObjectDeleter<DepotMatchingRepositoryListener> 202 itemListenerDeleter(itemListener); 203 204 BulkContainerDumpExportRepositoryJsonListener* listener = 205 new BulkContainerDumpExportRepositoryJsonListener(itemListener); 206 ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> 207 listenerDeleter(listener); 208 209 BPath localPath; 210 status_t result = GetLocalPath(localPath); 211 212 if (result != B_OK) 213 return result; 214 215 result = ParseJsonFromFileWithListener(listener, localPath); 216 217 if (result != B_OK) 218 return result; 219 220 return listener->ErrorStatus(); 221 } 222 223 224 status_t 225 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 226 { 227 return GetLocalPath(path); 228 } 229 230 231 void 232 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 233 BString& jsonPath) const 234 { 235 jsonPath.SetTo("$.info"); 236 } 237