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