HaikuDepot: notify work status from main window
[haiku.git] / src / apps / haikudepot / server / BulkLoadStateMachine.cpp
blobe7a5a5b1e04e7c73e1af3e3f6a683bb01d3a3024
1 /*
2 * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5 #include "BulkLoadStateMachine.h"
7 #include <Autolock.h>
8 #include <NetworkInterface.h>
9 #include <NetworkRoster.h>
11 #include "Logger.h"
12 #include "PkgDataUpdateProcess.h"
13 #include "RepositoryDataUpdateProcess.h"
14 #include "ServerIconExportUpdateProcess.h"
15 #include "ServerSettings.h"
18 BulkLoadStateMachine::BulkLoadStateMachine(Model* model)
20 fBulkLoadContext(NULL),
21 fModel(model)
26 BulkLoadStateMachine::~BulkLoadStateMachine()
28 Stop();
32 bool
33 BulkLoadStateMachine::IsRunning()
35 BAutolock locker(&fLock);
36 return fBulkLoadContext != NULL;
40 /*! This gets invoked when one of the background processes has exited. */
42 void
43 BulkLoadStateMachine::ServerProcessExited()
45 ContextPoll();
49 static const char* bulk_load_state_name(bulk_load_state state) {
50 switch(state) {
51 case BULK_LOAD_INITIAL:
52 return "BULK_LOAD_INITIAL";
53 case BULK_LOAD_REPOSITORY_AND_REFERENCE:
54 return "BULK_LOAD_REPOSITORY_AND_REFERENCE";
55 case BULK_LOAD_PKGS_AND_ICONS:
56 return "BULK_LOAD_PKGS_AND_ICONS";
57 case BULK_LOAD_COMPLETE:
58 return "BULK_LOAD_COMPLETE";
59 default:
60 return "???";
65 void
66 BulkLoadStateMachine::SetContextState(bulk_load_state state)
68 if (Logger::IsDebugEnabled()) {
69 printf("bulk load - transition to state [%s]\n",
70 bulk_load_state_name(state));
73 fBulkLoadContext->SetState(state);
77 /*! Bulk loading data into the model can be considered to be a state
78 machine. This method is invoked each time that an event state
79 change happens.
82 void
83 BulkLoadStateMachine::ContextPoll()
85 BAutolock locker(&fLock);
87 if (Logger::IsDebugEnabled())
88 printf("bulk load - context poll\n");
90 if (CanTransitionTo(BULK_LOAD_REPOSITORY_AND_REFERENCE)) {
91 SetContextState(BULK_LOAD_REPOSITORY_AND_REFERENCE);
92 InitiateBulkPopulateIcons();
93 if (InitiateBulkRepositories() != B_OK)
94 ContextPoll();
95 return;
98 if (CanTransitionTo(BULK_LOAD_PKGS_AND_ICONS)) {
99 fModel->LogDepotsWithNoWebAppRepositoryCode();
100 SetContextState(BULK_LOAD_PKGS_AND_ICONS);
101 InitiateBulkPopulatePackagesForAllDepots();
102 return;
105 if (CanTransitionTo(BULK_LOAD_COMPLETE)) {
106 SetContextState(BULK_LOAD_COMPLETE);
107 delete fBulkLoadContext;
108 fBulkLoadContext = NULL;
109 return;
114 bool
115 BulkLoadStateMachine::CanTransitionTo(bulk_load_state targetState)
117 if (fBulkLoadContext != NULL) {
118 bulk_load_state existingState = fBulkLoadContext->State();
120 switch (targetState) {
121 case BULK_LOAD_INITIAL:
122 return false;
123 case BULK_LOAD_REPOSITORY_AND_REFERENCE:
124 return existingState == BULK_LOAD_INITIAL;
125 case BULK_LOAD_PKGS_AND_ICONS:
126 return (existingState == BULK_LOAD_REPOSITORY_AND_REFERENCE)
127 && ((fBulkLoadContext->RepositoryProcess() == NULL)
128 || !fBulkLoadContext->RepositoryProcess()->IsRunning());
129 case BULK_LOAD_COMPLETE:
130 if ((existingState == BULK_LOAD_PKGS_AND_ICONS)
131 && ((fBulkLoadContext->IconProcess() == NULL)
132 || !fBulkLoadContext->IconProcess()->IsRunning())) {
133 int32 i;
135 for (i = 0; i < fBulkLoadContext->CountPkgProcesses(); i++) {
136 AbstractServerProcess* process =
137 fBulkLoadContext->PkgProcessAt(i);
138 if (process->IsRunning())
139 return false;
142 return true;
144 break;
148 return false;
152 void
153 BulkLoadStateMachine::StopAllProcesses()
155 BAutolock locker(&fLock);
157 if (fBulkLoadContext != NULL) {
158 if (NULL != fBulkLoadContext->IconProcess())
159 fBulkLoadContext->IconProcess()->Stop();
161 if (NULL != fBulkLoadContext->RepositoryProcess())
162 fBulkLoadContext->RepositoryProcess()->Stop();
164 int32 i;
166 for(i = 0; i < fBulkLoadContext->CountPkgProcesses(); i++) {
167 AbstractServerProcess* serverProcess =
168 fBulkLoadContext->PkgProcessAt(i);
169 serverProcess->Stop();
175 void
176 BulkLoadStateMachine::Start()
178 if (Logger::IsInfoEnabled())
179 printf("bulk load - start\n");
181 Stop();
184 BAutolock locker(&fLock);
186 if (!IsRunning()) {
187 fBulkLoadContext = new BulkLoadContext();
189 if (ServerSettings::ForceNoNetwork() || !HasNetwork())
190 fBulkLoadContext->AddProcessOption(
191 SERVER_PROCESS_NO_NETWORKING);
193 if (ServerSettings::PreferCache())
194 fBulkLoadContext->AddProcessOption(SERVER_PROCESS_PREFER_CACHE);
196 if (ServerSettings::DropCache())
197 fBulkLoadContext->AddProcessOption(SERVER_PROCESS_DROP_CACHE);
199 ContextPoll();
205 void
206 BulkLoadStateMachine::Stop()
208 StopAllProcesses();
210 // spin lock to wait for the bulk-load processes to complete.
212 while (IsRunning())
213 snooze(500000);
217 /*! This method is the initial function that is invoked on starting a new
218 thread. It will start a server process that is part of the bulk-load.
221 status_t
222 BulkLoadStateMachine::StartProcess(void* cookie)
224 AbstractServerProcess* process =
225 static_cast<AbstractServerProcess*>(cookie);
227 if (Logger::IsInfoEnabled()) {
228 printf("bulk load - starting process [%s]\n",
229 process->Name());
232 process->Run();
233 return B_OK;
237 status_t
238 BulkLoadStateMachine::InitiateServerProcess(AbstractServerProcess* process)
240 if (Logger::IsInfoEnabled())
241 printf("bulk load - initiating [%s]\n", process->Name());
243 thread_id tid = spawn_thread(&StartProcess,
244 process->Name(), B_NORMAL_PRIORITY, process);
246 if (tid >= 0) {
247 resume_thread(tid);
248 return B_OK;
251 return B_ERROR;
255 status_t
256 BulkLoadStateMachine::InitiateBulkRepositories()
258 status_t result = B_OK;
259 BPath dataPath;
261 fBulkLoadContext->SetRepositoryProcess(NULL);
262 result = fModel->DumpExportRepositoryDataPath(dataPath);
264 if (result != B_OK) {
265 BAutolock locker(&fLock);
266 printf("unable to obtain the path for storing the repository data\n");
267 ContextPoll();
268 return B_ERROR;
271 fBulkLoadContext->SetRepositoryProcess(
272 new RepositoryDataUpdateProcess(this, dataPath, fModel,
273 fBulkLoadContext->ProcessOptions()));
274 return InitiateServerProcess(fBulkLoadContext->RepositoryProcess());
278 status_t
279 BulkLoadStateMachine::InitiateBulkPopulateIcons()
281 BPath path;
283 if (fModel->IconStoragePath(path) != B_OK) {
284 BAutolock locker(&fLock);
285 printf("unable to obtain the path for storing icons\n");
286 ContextPoll();
287 return B_ERROR;
290 AbstractServerProcess *process = new ServerIconExportUpdateProcess(
291 this, path, fModel, fBulkLoadContext->ProcessOptions());
292 fBulkLoadContext->SetIconProcess(process);
293 return InitiateServerProcess(process);
297 status_t
298 BulkLoadStateMachine::InitiateBulkPopulatePackagesForDepot(
299 const DepotInfo& depotInfo)
301 BString repositorySourceCode = depotInfo.WebAppRepositorySourceCode();
303 if (repositorySourceCode.Length() == 0) {
304 printf("the depot [%s] has no repository source code\n",
305 depotInfo.Name().String());
306 return B_ERROR;
309 BPath repositorySourcePkgDataPath;
311 if (fModel->DumpExportPkgDataPath(repositorySourcePkgDataPath,
312 repositorySourceCode) != B_OK) {
313 BAutolock locker(&fLock);
314 printf("unable to obtain the path for storing data for [%s]\n",
315 repositorySourceCode.String());
316 ContextPoll();
317 return B_ERROR;
320 AbstractServerProcess *process = new PkgDataUpdateProcess(
321 this, repositorySourcePkgDataPath, fModel->PreferredLanguage(),
322 repositorySourceCode, depotInfo.Name(), fModel,
323 fBulkLoadContext->ProcessOptions());
324 fBulkLoadContext->AddPkgProcess(process);
326 return InitiateServerProcess(process);
330 // static
331 void
332 BulkLoadStateMachine::InitiatePopulatePackagesForDepotCallback(
333 const DepotInfo& depotInfo, void* context)
335 BulkLoadStateMachine* stateMachine =
336 static_cast<BulkLoadStateMachine*>(context);
337 stateMachine->InitiateBulkPopulatePackagesForDepot(depotInfo);
341 void
342 BulkLoadStateMachine::InitiateBulkPopulatePackagesForAllDepots()
344 fModel->ForAllDepots(&InitiatePopulatePackagesForDepotCallback, this);
346 printf("did initiate populate package data for %" B_PRId32 " depots\n",
347 fBulkLoadContext->CountPkgProcesses());
349 if (0 == fBulkLoadContext->CountPkgProcesses())
350 ContextPoll();
354 bool
355 BulkLoadStateMachine::HasNetwork()
357 BNetworkRoster& roster = BNetworkRoster::Default();
358 BNetworkInterface interface;
359 uint32 cookie = 0;
360 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
361 uint32 flags = interface.Flags();
362 if ((flags & IFF_LOOPBACK) == 0
363 && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) {
364 return true;
368 return false;