xref: /haiku/src/apps/haikudepot/server/ServerRepositoryDataUpdateProcess.cpp (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
1 /*
2  * Copyright 2017-2023, 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->Identifier().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 			if (identifier == depot->Identifier())
117 				_SetupRepositoryData(depot, repository, repositorySource);
118 		}
119 	}
120 }
121 
122 
123 void
124 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository,
125 	DumpExportRepositorySource* repositorySource)
126 {
127 	if (!repositorySource->IdentifierIsNull())
128 		Handle(*(repositorySource->Identifier()), repository, repositorySource);
129 
130 	// there may be additional identifiers for the remote repository and
131 	// these should also be taken into consideration.
132 
133 	for(int32 i = 0;
134 			i < repositorySource->CountExtraIdentifiers();
135 			i++)
136 	{
137 		Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository,
138 			repositorySource);
139 	}
140 }
141 
142 
143 bool
144 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository)
145 {
146 	int32 i;
147 	for (i = 0; i < repository->CountRepositorySources(); i++)
148 		Handle(repository, repository->RepositorySourcesItemAt(i));
149 	return !fStoppable->WasStopped();
150 }
151 
152 
153 void
154 DepotMatchingRepositoryListener::Complete()
155 {
156 }
157 
158 
159 ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess(
160 	Model* model,
161 	uint32 serverProcessOptions)
162 	:
163 	AbstractSingleFileServerProcess(serverProcessOptions),
164 	fModel(model)
165 {
166 }
167 
168 
169 ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess()
170 {
171 }
172 
173 
174 const char*
175 ServerRepositoryDataUpdateProcess::Name() const
176 {
177 	return "ServerRepositoryDataUpdateProcess";
178 }
179 
180 
181 const char*
182 ServerRepositoryDataUpdateProcess::Description() const
183 {
184 	return B_TRANSLATE("Synchronizing meta-data about repositories");
185 }
186 
187 
188 BString
189 ServerRepositoryDataUpdateProcess::UrlPathComponent()
190 {
191 	BString result;
192 	AutoLocker<BLocker> locker(fModel->Lock());
193 	result.SetToFormat("/__repository/all-%s.json.gz", fModel->PreferredLanguage()->ID());
194 	return result;
195 }
196 
197 
198 status_t
199 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const
200 {
201 	AutoLocker<BLocker> locker(fModel->Lock());
202 	return StorageUtils::DumpExportRepositoryDataPath(path, fModel->PreferredLanguage());
203 }
204 
205 
206 status_t
207 ServerRepositoryDataUpdateProcess::ProcessLocalData()
208 {
209 	DepotMatchingRepositoryListener* itemListener =
210 		new DepotMatchingRepositoryListener(fModel, this);
211 	ObjectDeleter<DepotMatchingRepositoryListener>
212 		itemListenerDeleter(itemListener);
213 
214 	BulkContainerDumpExportRepositoryJsonListener* listener =
215 		new BulkContainerDumpExportRepositoryJsonListener(itemListener);
216 	ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener>
217 		listenerDeleter(listener);
218 
219 	BPath localPath;
220 	status_t result = GetLocalPath(localPath);
221 
222 	if (result != B_OK)
223 		return result;
224 
225 	result = ParseJsonFromFileWithListener(listener, localPath);
226 
227 	if (result != B_OK)
228 		return result;
229 
230 	return listener->ErrorStatus();
231 }
232 
233 
234 status_t
235 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
236 {
237 	return GetLocalPath(path);
238 }
239 
240 
241 void
242 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
243 	BString& jsonPath) const
244 {
245 	jsonPath.SetTo("$.info");
246 }
247