HaikuDepot: Fixes for pkg view and network
This change addresses a number of issues around the synchronization
of data from the server when the user is viewing a package.
Handling of issues when the server is not network accessible is
improved. The user is also given the option is disable network
communications as problems are reported to them.
Resolves #19802
Change-Id: Iaa8214ba279a6bbf0f196643468d0f86a23ead1c
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9714
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
Diff
src/apps/haikudepot/packagemodel/PackageLocalInfo.cpp | 2 +-
src/apps/haikudepot/packagemodel/PackageLocalizedText.cpp | 4 ----
src/apps/haikudepot/server/CacheScreenshotProcess.cpp | 11 +++++++++--
src/apps/haikudepot/server/IncrementViewCounterProcess.cpp | 2 +-
src/apps/haikudepot/server/PopulatePkgChangelogFromServerProcess.cpp | 11 +++++++++--
src/apps/haikudepot/server/PopulatePkgUserRatingsFromServerProcess.cpp | 5 +++++
src/apps/haikudepot/server/ServerHelper.cpp | 28 +++++++++++++++++++++++-----
src/apps/haikudepot/ui/MainWindow.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
src/apps/haikudepot/ui/MainWindow.h | 9 +++------
src/apps/haikudepot/ui/PackageInfoView.cpp | 14 +++++++++-----
10 files changed, 114 insertions(+), 53 deletions(-)
@@ -333,7 +333,7 @@
PackageLocalInfoBuilder&
PackageLocalInfoBuilder::WithViewed()
{
if (!fSource.IsSet() || fSource->Viewed()) {
if (!fSource.IsSet() || !fSource->Viewed()) {
_InitFromSource();
fViewed = true;
}
@@ -82,9 +82,6 @@
PackageLocalizedText::SetHasChangelog(bool value)
{
fHasChangelog = value;
if (!value)
SetChangelog("");
}
@@ -92,7 +89,6 @@
PackageLocalizedText::SetChangelog(const BString& value)
{
fChangelog = value;
fHasChangelog = !value.IsEmpty();
}
@@ -1,12 +1,14 @@
/*
* Copyright 2023, Andrew Lindesay <apl@lindesay.co.nz>.
* Copyright 2023-2025, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "CacheScreenshotProcess.h"
#include <Catalog.h>
#include "Logger.h"
#include "Model.h"
#include "ServerHelper.h"
#undef B_TRANSLATION_CONTEXT
@@ -44,5 +46,10 @@
status_t
CacheScreenshotProcess::RunInternal()
{
if (!ServerHelper::IsNetworkAvailable()) {
HDINFO("no network so will not cache screenshot");
return B_OK;
}
return fModel->GetPackageScreenshotRepository()->CacheScreenshot(fScreenshotCoordinate);
}
}
@@ -75,7 +75,7 @@
int32 attempts = ATTEMPTS;
status_t result = B_OK;
while (attempts > 0 && !WasStopped()) {
while (attempts > 0 && !WasStopped() && ServerHelper::IsNetworkAvailable()) {
BMessage resultEnvelope;
WebAppInterfaceRef webApp = fModel->WebApp();
result = webApp->IncrementViewCounter(fPackage, depot, resultEnvelope);
@@ -51,6 +51,11 @@
status_t
PopulatePkgChangelogFromServerProcess::RunInternal()
{
if (!ServerHelper::IsNetworkAvailable()) {
HDINFO("no network so will not populate changelog");
return B_OK;
}
BMessage responsePayload;
@@ -66,8 +71,10 @@
if (result == B_OK) {
if (resultMessage.FindString("content", &content) == B_OK) {
result = _UpdateChangelog(content.Trim());
HDDEBUG("changelog populated for [%s]", fPackageName.String());
content.Trim();
result = _UpdateChangelog(content);
HDDEBUG("changelog populated for [%s] (length %" B_PRIi32 ")",
fPackageName.String(), content.Length());
} else {
HDDEBUG("no changelog present for [%s]", fPackageName.String());
}
@@ -53,6 +53,11 @@
status_t
PopulatePkgUserRatingsFromServerProcess::RunInternal()
{
if (!ServerHelper::IsNetworkAvailable()) {
HDINFO("no network so will not populate user ratings");
return B_OK;
}
status_t status = B_OK;
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -116,6 +116,12 @@
void
ServerHelper::AlertTransportError(BMessage* message)
{
if (ServerSettings::ForceNoNetwork()) {
HDERROR("Even though the user has opted to force no networking, a network transport error"
" is being alerted.");
return;
}
status_t error = B_OK;
int64 errnoInt64;
message->FindInt64("errno", &errnoInt64);
@@ -133,17 +139,23 @@
break;
}
alertText.SetToFormat(B_TRANSLATE("A network transport error has arisen"
" communicating with the server system: %s"),
alertText.SetToFormat(B_TRANSLATE("A network transport error has arisen communicating with the"
" server system: %s"),
errorDescription.String());
BAlert* alert = new BAlert(
B_TRANSLATE("Network transport error"),
alertText,
B_TRANSLATE("OK"));
BAlert* alert = new BAlert(B_TRANSLATE("Network transport error"), alertText,
B_TRANSLATE("Stop network use"), B_TRANSLATE("OK"));
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
switch (alert->Go()) {
case 0:
HDINFO("user has opted to disable use of networking");
ServerSettings::SetForceNoNetwork(true);
break;
default:
break;
}
}
@@ -52,6 +52,7 @@
#include "RatePackageWindow.h"
#include "RatingUtils.h"
#include "ScreenshotWindow.h"
#include "ServerHelper.h"
#include "SettingsWindow.h"
#include "ShuttingDownWindow.h"
#include "ToLatestUserUsageConditionsWindow.h"
@@ -1125,8 +1126,10 @@
if (message->FindString("name", &name) == B_OK) {
const PackageInfoRef& viewedPackage = fPackageInfoView->Package();
if (viewedPackage.IsSet()) {
if (viewedPackage->Name() == name)
_IncrementViewCounter(viewedPackage);
const BString& viewedPackageName = viewedPackage->Name();
if (viewedPackageName == name)
_IncrementViewCounter(viewedPackageName);
else
HDINFO("incr. view counter; name mismatch");
} else {
@@ -1142,23 +1145,38 @@
void
MainWindow::_IncrementViewCounter(const PackageInfoRef package)
MainWindow::_IncrementViewCounter(const BString& packageName)
{
bool shouldIncrementViewCounter = false;
const char* packageNameStr = packageName.String();
const PackageInfoRef package = fModel.PackageForName(packageName);
bool canShareAnonymousUsageData = fModel.CanShareAnonymousUsageData();
if (canShareAnonymousUsageData && !PackageUtils::Viewed(package)) {
fModel.AddPackage(PackageInfoBuilder(package)
.WithLocalInfo(
PackageLocalInfoBuilder(package->LocalInfo()).WithViewed().BuildRef())
.BuildRef());
shouldIncrementViewCounter = true;
if (!package.IsSet()) {
HDERROR("the package [%s] it not available -- won't increment the view counter",
packageNameStr);
return;
}
if (shouldIncrementViewCounter) {
ProcessCoordinator* incrementViewCoordinator
= ProcessCoordinatorFactory::CreateIncrementViewCounter(&fModel, package);
_AddProcessCoordinator(incrementViewCoordinator);
bool canShareAnonymousUsageData = fModel.CanShareAnonymousUsageData();
if (canShareAnonymousUsageData && !PackageUtils::Viewed(package)) {
if (ServerHelper::IsNetworkAvailable()) {
PackageLocalInfoRef localInfoRef
= PackageLocalInfoBuilder(package->LocalInfo()).WithViewed().BuildRef();
fModel.AddPackage(PackageInfoBuilder(package).WithLocalInfo(localInfoRef).BuildRef());
ProcessCoordinator* incrementViewCoordinator
= ProcessCoordinatorFactory::CreateIncrementViewCounter(&fModel, package);
_AddProcessCoordinator(incrementViewCoordinator);
HDINFO("pkg [%s] will increment counter", packageNameStr);
} else {
HDINFO("pkg [%s] won't increment counter; network unavailable", packageNameStr);
}
}
}
@@ -1364,21 +1382,36 @@
const char* packageNameStr = package->Name().String();
PackageLocalizedTextRef localized = package->LocalizedText();
bool networkAvailable = ServerHelper::IsNetworkAvailable();
if (localized.IsSet()) {
if (localized->HasChangelog() && (forcePopulate || localized->Changelog().IsEmpty())) {
_AddProcessCoordinator(ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(
&fModel, package->Name()));
HDINFO("pkg [%s] will have changelog updated from server.", packageNameStr);
} else {
HDDEBUG("pkg [%s] not have changelog updated from server.", packageNameStr);
if (forcePopulate || localized->Changelog().IsEmpty()) {
if (localized->HasChangelog()) {
if (networkAvailable) {
_AddProcessCoordinator(
ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(&fModel,
package->Name()));
HDINFO("pkg [%s] will have changelog updated from server.", packageNameStr);
} else {
HDINFO(
"pkg [%s] will not have changelog updated from server; network unavailable",
packageNameStr);
}
} else {
HDINFO("pkg [%s] does not have a changelog -- won't try fetch it.", packageNameStr);
}
}
}
if (forcePopulate || RatingUtils::ShouldTryPopulateUserRatings(package->UserRatingInfo())) {
_AddProcessCoordinator(
ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(&fModel, package->Name()));
HDINFO("pkg [%s] will have user ratings updated from server.", packageNameStr);
if (networkAvailable) {
_AddProcessCoordinator(ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(
&fModel, package->Name()));
HDINFO("pkg [%s] will have user ratings updated from server.", packageNameStr);
} else {
HDINFO("pkg [%s] won't have user ratings updated from server; network unavailable",
packageNameStr);
}
} else {
HDDEBUG("pkg [%s] not have user ratings updated from server.", packageNameStr);
}
@@ -100,12 +100,9 @@
void _AdoptPackage(const PackageInfoRef& package);
void _ClearPackage();
void _SetupDelayedIncrementViewCounter(
const PackageInfoRef package);
void _HandleIncrementViewCounter(
const BMessage* message);
void _IncrementViewCounter(
const PackageInfoRef package);
void _SetupDelayedIncrementViewCounter(const PackageInfoRef package);
void _HandleIncrementViewCounter(const BMessage* message);
void _IncrementViewCounter(const BString& packageName);
void _PopulatePackageAsync(bool forcePopulate);
void _StartBulkLoad(bool force = false);
@@ -48,6 +48,7 @@
#include "ProcessCoordinatorFactory.h"
#include "RatingView.h"
#include "ScrollableGroupView.h"
#include "ServerHelper.h"
#include "SharedIcons.h"
#include "TextView.h"
@@ -1473,28 +1474,31 @@
PackageInfoView::_SetPackageScreenshotThumb(const PackageInfoRef& package)
{
ScreenshotCoordinate desiredCoordinate = _ScreenshotThumbCoordinate(package);
const char* packageNameCStr = package->Name().String();
bool hasCachedBitmap = false;
if (desiredCoordinate.IsValid()) {
bool present = false;
if (fModel->GetPackageScreenshotRepository()->HasCachedScreenshot(desiredCoordinate,
&present)
!= B_OK) {
HDERROR("unable to ascertain if screenshot is present for pkg [%s]",
package->Name().String());
HDERROR("unable to ascertain if screenshot is present for pkg [%s]", packageNameCStr);
} else if (present) {
HDDEBUG("screenshot is already cached for [%s] -- will load it",
HDDEBUG("screenshot is already cached for [%s] -- will load the cached data",
package->Name().String());
_HandleScreenshotCached(package, desiredCoordinate);
hasCachedBitmap = true;
} else if (!ServerHelper::IsNetworkAvailable()) {
HDINFO("screenshot won't be cached [%s] -- network unavailable", packageNameCStr);
} else {
HDDEBUG("screenshot is not cached [%s] -- will cache it", package->Name().String());
HDDEBUG("screenshot is not cached [%s] -- will cache it", packageNameCStr);
ProcessCoordinator* processCoordinator
= ProcessCoordinatorFactory::CacheScreenshotCoordinator(fModel, desiredCoordinate);
fProcessCoordinatorConsumer->Consume(processCoordinator);
}
} else {
HDDEBUG("no screenshot for pkg [%s]", package->Name().String());
HDDEBUG("no screenshot for pkg [%s]", packageNameCStr);
}
if (!hasCachedBitmap)