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