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