xref: /haiku/src/apps/haikudepot/server/ServerRepositoryDataUpdateProcess.cpp (revision 68d37cfb3a755a7270d772b505ee15c8b18aa5e0)
1 /*
2  * Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 #include "ServerRepositoryDataUpdateProcess.h"
6 
7 #include <stdio.h>
8 #include <sys/stat.h>
9 #include <time.h>
10 
11 #include <AutoDeleter.h>
12 #include <Autolock.h>
13 #include <Catalog.h>
14 #include <FileIO.h>
15 #include <Url.h>
16 
17 #include "DumpExportRepository.h"
18 #include "DumpExportRepositoryJsonListener.h"
19 #include "DumpExportRepositorySource.h"
20 #include "PackageInfo.h"
21 #include "ServerSettings.h"
22 #include "StorageUtils.h"
23 #include "Logger.h"
24 
25 
26 #undef B_TRANSLATION_CONTEXT
27 #define B_TRANSLATION_CONTEXT "ServerRepositoryDataUpdateProcess"
28 
29 
30 /*! This repository listener (not at the JSON level) is feeding in the
31     repositories as they are parsed and processing them.  Processing
32     includes finding the matching depot record and coupling the data
33     from the server with the data about the depot.
34 */
35 
36 class DepotMatchingRepositoryListener :
37 	public DumpExportRepositoryListener {
38 public:
39 								DepotMatchingRepositoryListener(Model* model,
40 									Stoppable* stoppable);
41 	virtual						~DepotMatchingRepositoryListener();
42 
43 	virtual	bool				Handle(DumpExportRepository* item);
44 			void				Handle(DumpExportRepository* repository,
45 									DumpExportRepositorySource*
46 										repositorySource);
47 			void				Handle(const BString& identifier,
48 									DumpExportRepository* repository,
49 									DumpExportRepositorySource*
50 										repositorySource);
51 	virtual	void				Complete();
52 
53 private:
54 			void				_SetupRepositoryData(
55 									DepotInfoRef& depot,
56 									DumpExportRepository* repository,
57 									DumpExportRepositorySource*
58 										repositorySource);
59 
60 private:
61 			Model*				fModel;
62 			Stoppable*			fStoppable;
63 };
64 
65 
66 DepotMatchingRepositoryListener::DepotMatchingRepositoryListener(
67 	Model* model, Stoppable* stoppable)
68 	:
69 	fModel(model),
70 	fStoppable(stoppable)
71 {
72 }
73 
74 
75 DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener()
76 {
77 }
78 
79 
80 void
81 DepotMatchingRepositoryListener::_SetupRepositoryData(DepotInfoRef& depot,
82 	DumpExportRepository* repository,
83 	DumpExportRepositorySource* repositorySource)
84 {
85 	BString* repositoryCode = repository->Code();
86 	BString* repositorySourceCode = repositorySource->Code();
87 
88 	depot->SetWebAppRepositoryCode(*repositoryCode);
89 	depot->SetWebAppRepositorySourceCode(*repositorySourceCode);
90 
91 	if (Logger::IsDebugEnabled()) {
92 		HDDEBUG("[DepotMatchingRepositoryListener] associated depot [%s] (%s) "
93 			"with server repository source [%s] (%s)",
94 			depot->Name().String(),
95 			depot->URL().String(),
96 			repositorySourceCode->String(),
97 			repositorySource->Identifier()->String());
98 	} else {
99 		HDINFO("[DepotMatchingRepositoryListener] associated depot [%s] with "
100 			"server repository source [%s]",
101 			depot->Name().String(),
102 			repositorySourceCode->String());
103 	}
104 }
105 
106 
107 void
108 DepotMatchingRepositoryListener::Handle(const BString& identifier,
109 	DumpExportRepository* repository,
110 	DumpExportRepositorySource* repositorySource)
111 {
112 	if (!identifier.IsEmpty()) {
113 		AutoLocker<BLocker> locker(fModel->Lock());
114 		for (int32 i = 0; i < fModel->CountDepots(); i++) {
115 			DepotInfoRef depot = fModel->DepotAtIndex(i);
116 			BString depotUrl = depot->URL();
117 			if (identifier == depotUrl)
118 				_SetupRepositoryData(depot, repository, repositorySource);
119 		}
120 	}
121 }
122 
123 
124 void
125 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository,
126 	DumpExportRepositorySource* repositorySource)
127 {
128 	if (!repositorySource->IdentifierIsNull())
129 		Handle(*(repositorySource->Identifier()), repository, repositorySource);
130 
131 	// there may be additional identifiers for the remote repository and
132 	// these should also be taken into consideration.
133 
134 	for(int32 i = 0;
135 			i < repositorySource->CountExtraIdentifiers();
136 			i++)
137 	{
138 		Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository,
139 			repositorySource);
140 	}
141 }
142 
143 
144 bool
145 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository)
146 {
147 	int32 i;
148 	for (i = 0; i < repository->CountRepositorySources(); i++)
149 		Handle(repository, repository->RepositorySourcesItemAt(i));
150 	return !fStoppable->WasStopped();
151 }
152 
153 
154 void
155 DepotMatchingRepositoryListener::Complete()
156 {
157 }
158 
159 
160 ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess(
161 	Model* model,
162 	uint32 serverProcessOptions)
163 	:
164 	AbstractSingleFileServerProcess(serverProcessOptions),
165 	fModel(model)
166 {
167 }
168 
169 
170 ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess()
171 {
172 }
173 
174 
175 const char*
176 ServerRepositoryDataUpdateProcess::Name() const
177 {
178 	return "ServerRepositoryDataUpdateProcess";
179 }
180 
181 
182 const char*
183 ServerRepositoryDataUpdateProcess::Description() const
184 {
185 	return B_TRANSLATE("Synchronizing meta-data about repositories");
186 }
187 
188 
189 BString
190 ServerRepositoryDataUpdateProcess::UrlPathComponent()
191 {
192 	BString result;
193 	AutoLocker<BLocker> locker(fModel->Lock());
194 	result.SetToFormat("/__repository/all-%s.json.gz",
195 		fModel->Language()->PreferredLanguage()->Code());
196 	return result;
197 }
198 
199 
200 status_t
201 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const
202 {
203 	AutoLocker<BLocker> locker(fModel->Lock());
204 	return fModel->DumpExportRepositoryDataPath(path);
205 }
206 
207 
208 status_t
209 ServerRepositoryDataUpdateProcess::ProcessLocalData()
210 {
211 	DepotMatchingRepositoryListener* itemListener =
212 		new DepotMatchingRepositoryListener(fModel, this);
213 	ObjectDeleter<DepotMatchingRepositoryListener>
214 		itemListenerDeleter(itemListener);
215 
216 	BulkContainerDumpExportRepositoryJsonListener* listener =
217 		new BulkContainerDumpExportRepositoryJsonListener(itemListener);
218 	ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener>
219 		listenerDeleter(listener);
220 
221 	BPath localPath;
222 	status_t result = GetLocalPath(localPath);
223 
224 	if (result != B_OK)
225 		return result;
226 
227 	result = ParseJsonFromFileWithListener(listener, localPath);
228 
229 	if (result != B_OK)
230 		return result;
231 
232 	return listener->ErrorStatus();
233 }
234 
235 
236 status_t
237 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
238 {
239 	return GetLocalPath(path);
240 }
241 
242 
243 void
244 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
245 	BString& jsonPath) const
246 {
247 	jsonPath.SetTo("$.info");
248 }
249