xref: /haiku/src/apps/haikudepot/server/ServerRepositoryDataUpdateProcess.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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",
194 		fModel->Language()->PreferredLanguage()->ID());
195 	return result;
196 }
197 
198 
199 status_t
200 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const
201 {
202 	AutoLocker<BLocker> locker(fModel->Lock());
203 	return fModel->DumpExportRepositoryDataPath(path);
204 }
205 
206 
207 status_t
208 ServerRepositoryDataUpdateProcess::ProcessLocalData()
209 {
210 	DepotMatchingRepositoryListener* itemListener =
211 		new DepotMatchingRepositoryListener(fModel, this);
212 	ObjectDeleter<DepotMatchingRepositoryListener>
213 		itemListenerDeleter(itemListener);
214 
215 	BulkContainerDumpExportRepositoryJsonListener* listener =
216 		new BulkContainerDumpExportRepositoryJsonListener(itemListener);
217 	ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener>
218 		listenerDeleter(listener);
219 
220 	BPath localPath;
221 	status_t result = GetLocalPath(localPath);
222 
223 	if (result != B_OK)
224 		return result;
225 
226 	result = ParseJsonFromFileWithListener(listener, localPath);
227 
228 	if (result != B_OK)
229 		return result;
230 
231 	return listener->ErrorStatus();
232 }
233 
234 
235 status_t
236 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
237 {
238 	return GetLocalPath(path);
239 }
240 
241 
242 void
243 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
244 	BString& jsonPath) const
245 {
246 	jsonPath.SetTo("$.info");
247 }
248