xref: /haiku/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp (revision b2acee1cb986b696adfad7daabfe9279949a3e54)
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