xref: /haiku/src/apps/haikudepot/server/ServerRepositoryDataUpdateProcess.cpp (revision 9bb9cc8896854f6a0a28f586f6025e8eb2623f0b)
1 /*
2  * Copyright 2017-2019, 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 	return fModel->DumpExportRepositoryDataPath(path);
193 }
194 
195 
196 status_t
197 ServerRepositoryDataUpdateProcess::ProcessLocalData()
198 {
199 	DepotMatchingRepositoryListener* itemListener =
200 		new DepotMatchingRepositoryListener(fModel, this);
201 	ObjectDeleter<DepotMatchingRepositoryListener>
202 		itemListenerDeleter(itemListener);
203 
204 	BulkContainerDumpExportRepositoryJsonListener* listener =
205 		new BulkContainerDumpExportRepositoryJsonListener(itemListener);
206 	ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener>
207 		listenerDeleter(listener);
208 
209 	BPath localPath;
210 	status_t result = GetLocalPath(localPath);
211 
212 	if (result != B_OK)
213 		return result;
214 
215 	result = ParseJsonFromFileWithListener(listener, localPath);
216 
217 	if (result != B_OK)
218 		return result;
219 
220 	return listener->ErrorStatus();
221 }
222 
223 
224 status_t
225 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
226 {
227 	return GetLocalPath(path);
228 }
229 
230 
231 void
232 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
233 	BString& jsonPath) const
234 {
235 	jsonPath.SetTo("$.info");
236 }
237