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