1/*
2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Tappe <zooey@hirschkaefer.de>
7 */
8
9
10#include <package/RefreshRepositoryRequest.h>
11
12#include <Catalog.h>
13#include <Directory.h>
14#include <Path.h>
15
16#include <JobQueue.h>
17
18#include <package/ActivateRepositoryCacheJob.h>
19#include <package/ChecksumAccessors.h>
20#include <package/ValidateChecksumJob.h>
21#include <package/RepositoryCache.h>
22#include <package/RepositoryConfig.h>
23#include <package/PackageRoster.h>
24
25#include "FetchFileJob.h"
26
27#undef B_TRANSLATION_CONTEXT
28#define B_TRANSLATION_CONTEXT "RefreshRepositoryRequest"
29
30
31namespace BPackageKit {
32
33
34using namespace BPrivate;
35
36
37BRefreshRepositoryRequest::BRefreshRepositoryRequest(const BContext& context,
38	const BRepositoryConfig& repoConfig)
39	:
40	inherited(context),
41	fRepoConfig(repoConfig)
42{
43}
44
45
46BRefreshRepositoryRequest::~BRefreshRepositoryRequest()
47{
48}
49
50
51status_t
52BRefreshRepositoryRequest::CreateInitialJobs()
53{
54	status_t result = InitCheck();
55	if (result != B_OK)
56		return B_NO_INIT;
57
58	if ((result = fRepoConfig.InitCheck()) != B_OK)
59		return result;
60
61	// fetch the current checksum and compare with our cache's checksum,
62	// if they differ, fetch the updated cache
63	result = fContext.GetNewTempfile("repochecksum-", &fFetchedChecksumFile);
64	if (result != B_OK)
65		return result;
66	BString repoChecksumURL
67		= BString(fRepoConfig.BaseURL()) << "/" << "repo.sha256";
68	BString title = B_TRANSLATE("Fetching repository checksum from %url");
69	title.ReplaceAll("%url", fRepoConfig.BaseURL());
70	FetchFileJob* fetchChecksumJob = new (std::nothrow) FetchFileJob(
71		fContext, title, repoChecksumURL, fFetchedChecksumFile);
72	if (fetchChecksumJob == NULL)
73		return B_NO_MEMORY;
74	if ((result = QueueJob(fetchChecksumJob)) != B_OK) {
75		delete fetchChecksumJob;
76		return result;
77	}
78
79	BRepositoryCache repoCache;
80	BPackageRoster roster;
81	// We purposely don't check this error, because this may be for a new repo,
82	// which doesn't have a cache file yet. The true passed to
83	// GeneralFileChecksumAccessor below will handle this case, and cause the
84	// repo data to be fetched and cached for the future in JobSucceeded below.
85	roster.GetRepositoryCache(fRepoConfig.Name(), &repoCache);
86
87	title = B_TRANSLATE("Validating checksum for %repositoryName");
88	title.ReplaceAll("%repositoryName", fRepoConfig.Name());
89	ValidateChecksumJob* validateChecksumJob
90		= new (std::nothrow) ValidateChecksumJob(fContext,
91			title,
92			new (std::nothrow) ChecksumFileChecksumAccessor(
93				fFetchedChecksumFile),
94			new (std::nothrow) GeneralFileChecksumAccessor(repoCache.Entry(),
95				true),
96			false);
97	if (validateChecksumJob == NULL)
98		return B_NO_MEMORY;
99	validateChecksumJob->AddDependency(fetchChecksumJob);
100	if ((result = QueueJob(validateChecksumJob)) != B_OK) {
101		delete validateChecksumJob;
102		return result;
103	}
104	fValidateChecksumJob = validateChecksumJob;
105
106	return B_OK;
107}
108
109
110void
111BRefreshRepositoryRequest::JobSucceeded(BSupportKit::BJob* job)
112{
113	if (job == fValidateChecksumJob
114		&& !fValidateChecksumJob->ChecksumsMatch()) {
115		// the remote repo cache has a different checksum, we fetch it
116		fValidateChecksumJob = NULL;
117			// don't re-trigger fetching if anything goes wrong, fail instead
118		_FetchRepositoryCache();
119	}
120}
121
122
123status_t
124BRefreshRepositoryRequest::_FetchRepositoryCache()
125{
126	// download repository cache and put it in either the common/user cache
127	// path, depending on where the corresponding repo-config lives
128
129	// job fetching the cache
130	BEntry tempRepoCache;
131	status_t result = fContext.GetNewTempfile("repocache-", &tempRepoCache);
132	if (result != B_OK)
133		return result;
134	BString repoCacheURL = BString(fRepoConfig.BaseURL()) << "/" << "repo";
135	BString title = B_TRANSLATE("Fetching repository-cache from %url");
136	title.ReplaceAll("%url", fRepoConfig.BaseURL());
137	FetchFileJob* fetchCacheJob = new (std::nothrow) FetchFileJob(fContext,
138		title, repoCacheURL, tempRepoCache);
139	if (fetchCacheJob == NULL)
140		return B_NO_MEMORY;
141	if ((result = QueueJob(fetchCacheJob)) != B_OK) {
142		delete fetchCacheJob;
143		return result;
144	}
145
146	// job validating the cache's checksum
147	title = B_TRANSLATE("Validating checksum for %repositoryName");
148	title.ReplaceAll("%repositoryName", fRepoConfig.Name());
149	ValidateChecksumJob* validateChecksumJob
150		= new (std::nothrow) ValidateChecksumJob(fContext,
151			title,
152			new (std::nothrow) ChecksumFileChecksumAccessor(
153				fFetchedChecksumFile),
154			new (std::nothrow) GeneralFileChecksumAccessor(tempRepoCache));
155	if (validateChecksumJob == NULL)
156		return B_NO_MEMORY;
157	validateChecksumJob->AddDependency(fetchCacheJob);
158	if ((result = QueueJob(validateChecksumJob)) != B_OK) {
159		delete validateChecksumJob;
160		return result;
161	}
162
163	// job activating the cache
164	BPath targetRepoCachePath;
165	BPackageRoster roster;
166	result = fRepoConfig.IsUserSpecific()
167		? roster.GetUserRepositoryCachePath(&targetRepoCachePath, true)
168		: roster.GetCommonRepositoryCachePath(&targetRepoCachePath, true);
169	if (result != B_OK)
170		return result;
171	BDirectory targetDirectory(targetRepoCachePath.Path());
172	ActivateRepositoryCacheJob* activateJob
173		= new (std::nothrow) ActivateRepositoryCacheJob(fContext,
174			BString("Activating repository cache for ") << fRepoConfig.Name(),
175			tempRepoCache, fRepoConfig.Name(), targetDirectory);
176	if (activateJob == NULL)
177		return B_NO_MEMORY;
178	activateJob->AddDependency(validateChecksumJob);
179	if ((result = QueueJob(activateJob)) != B_OK) {
180		delete activateJob;
181		return result;
182	}
183
184	return B_OK;
185}
186
187
188}	// namespace BPackageKit
189