1 /* 2 * Copyright 2017-2018, Andrew Lindesay <apl@lindesay.co.nz>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 #include "ServerIconExportUpdateProcess.h" 7 8 #include <stdio.h> 9 #include <sys/stat.h> 10 #include <time.h> 11 12 #include <Autolock.h> 13 #include <FileIO.h> 14 #include <support/StopWatch.h> 15 #include <support/ZlibCompressionAlgorithm.h> 16 17 #include "HaikuDepotConstants.h" 18 #include "Logger.h" 19 #include "ServerSettings.h" 20 #include "StorageUtils.h" 21 #include "TarArchiveService.h" 22 23 24 /*! This constructor will locate the cached data in a standardized location */ 25 26 ServerIconExportUpdateProcess::ServerIconExportUpdateProcess( 27 AbstractServerProcessListener* listener, 28 const BPath& localStorageDirectoryPath, 29 Model* model, 30 uint32 options) 31 : 32 AbstractServerProcess(listener, options), 33 fLocalStorageDirectoryPath(localStorageDirectoryPath), 34 fModel(model), 35 fLocalIconStore(LocalIconStore(localStorageDirectoryPath)), 36 fCountIconsSet(0) 37 { 38 } 39 40 41 ServerIconExportUpdateProcess::~ServerIconExportUpdateProcess() 42 { 43 } 44 45 46 const char* 47 ServerIconExportUpdateProcess::Name() 48 { 49 return "ServerIconExportUpdateProcess"; 50 } 51 52 53 status_t 54 ServerIconExportUpdateProcess::RunInternal() 55 { 56 status_t result = B_OK; 57 58 if (IsSuccess(result) && HasOption(SERVER_PROCESS_DROP_CACHE)) { 59 result = StorageUtils::RemoveDirectoryContents( 60 fLocalStorageDirectoryPath); 61 } 62 63 if (IsSuccess(result)) { 64 bool hasData; 65 66 result = HasLocalData(&hasData); 67 68 if (IsSuccess(result) && ShouldAttemptNetworkDownload(hasData)) 69 result = DownloadAndUnpack(); 70 71 if (IsSuccess(result)) { 72 status_t hasDataResult = HasLocalData(&hasData); 73 74 if (IsSuccess(hasDataResult) && !hasData) 75 result = HD_ERR_NO_DATA; 76 } 77 } 78 79 if (IsSuccess(result) && !WasStopped()) 80 result = Populate(); 81 82 return result; 83 } 84 85 86 status_t 87 ServerIconExportUpdateProcess::PopulateForPkg(const PackageInfoRef& package) 88 { 89 BPath bestIconPath; 90 91 if ( fLocalIconStore.TryFindIconPath( 92 package->Name(), bestIconPath) == B_OK) { 93 94 BFile bestIconFile(bestIconPath.Path(), O_RDONLY); 95 BitmapRef bitmapRef(new(std::nothrow)SharedBitmap(bestIconFile), true); 96 // TODO; somehow handle the locking! 97 //BAutolock locker(&fLock); 98 package->SetIcon(bitmapRef); 99 100 if (Logger::IsDebugEnabled()) { 101 fprintf(stdout, "have set the package icon for [%s] from [%s]\n", 102 package->Name().String(), bestIconPath.Path()); 103 } 104 105 fCountIconsSet++; 106 107 return B_OK; 108 } 109 110 if (Logger::IsDebugEnabled()) { 111 fprintf(stdout, "did not set the package icon for [%s]; no data\n", 112 package->Name().String()); 113 } 114 115 return B_FILE_NOT_FOUND; 116 } 117 118 119 bool 120 ServerIconExportUpdateProcess::ConsumePackage( 121 const PackageInfoRef& packageInfoRef, void* context) 122 { 123 PopulateForPkg(packageInfoRef); 124 return !WasStopped(); 125 } 126 127 128 status_t 129 ServerIconExportUpdateProcess::Populate() 130 { 131 BStopWatch watch("ServerIconExportUpdateProcess::Populate", true); 132 fModel->ForAllPackages(this, NULL); 133 134 if (Logger::IsInfoEnabled()) { 135 double secs = watch.ElapsedTime() / 1000000.0; 136 fprintf(stdout, "did populate %" B_PRId32 " packages' icons" 137 " (%6.3g secs)\n", fCountIconsSet, secs); 138 } 139 140 return B_OK; 141 } 142 143 144 status_t 145 ServerIconExportUpdateProcess::DownloadAndUnpack() 146 { 147 BPath tarGzFilePath(tmpnam(NULL)); 148 status_t result = B_OK; 149 150 printf("will start fetching icons\n"); 151 152 result = Download(tarGzFilePath); 153 154 if (result == B_OK) { 155 printf("delete any existing stored data\n"); 156 StorageUtils::RemoveDirectoryContents(fLocalStorageDirectoryPath); 157 158 BFile *tarGzFile = new BFile(tarGzFilePath.Path(), O_RDONLY); 159 BDataIO* tarIn; 160 161 BZlibDecompressionParameters* zlibDecompressionParameters 162 = new BZlibDecompressionParameters(); 163 164 result = BZlibCompressionAlgorithm() 165 .CreateDecompressingInputStream(tarGzFile, 166 zlibDecompressionParameters, tarIn); 167 168 if (result == B_OK) { 169 BStopWatch watch("ServerIconExportUpdateProcess::DownloadAndUnpack_Unpack", true); 170 171 result = TarArchiveService::Unpack(*tarIn, 172 fLocalStorageDirectoryPath, NULL); 173 174 if (result == B_OK) { 175 double secs = watch.ElapsedTime() / 1000000.0; 176 fprintf(stdout, "did unpack icon tgz in (%6.3g secs)\n", secs); 177 178 if (0 != remove(tarGzFilePath.Path())) { 179 fprintf(stdout, "unable to delete the temporary tgz path; " 180 "%s\n", tarGzFilePath.Path()); 181 } 182 } 183 } 184 185 delete tarGzFile; 186 187 printf("did complete fetching icons\n"); 188 } 189 190 return result; 191 } 192 193 194 status_t 195 ServerIconExportUpdateProcess::HasLocalData(bool* result) const 196 { 197 BPath path; 198 off_t size; 199 GetStandardMetaDataPath(path); 200 return StorageUtils::ExistsObject(path, result, NULL, &size) 201 && size > 0; 202 } 203 204 205 void 206 ServerIconExportUpdateProcess::GetStandardMetaDataPath(BPath& path) const 207 { 208 path.SetTo(fLocalStorageDirectoryPath.Path()); 209 path.Append("hicn/info.json"); 210 } 211 212 213 void 214 ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath( 215 BString& jsonPath) const 216 { 217 // the "$" here indicates that the data is at the top level. 218 jsonPath.SetTo("$"); 219 } 220 221 222 status_t 223 ServerIconExportUpdateProcess::Download(BPath& tarGzFilePath) 224 { 225 return DownloadToLocalFileAtomically(tarGzFilePath, 226 ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz")); 227 } 228 229 230 231