fix(android): a network call that never returns no longer kills the interface
Reported symptom, with the local server stopped: Sync leaves the app inert - neither Open vault nor Sync responds, and nothing is displayed. Log and Server settings still work, because they are local to the page. The log proves where it stops: the GET line is there, the "HTTP ... in ... ms" line that immediately follows the call is not. So the request never returned, SetBusy(False) never ran, and the two actions stayed disabled - a disabled button fires no click, hence the silence. THTTPClient is given 15 s timeouts and the Android request does inherit them, so this should not happen; rather than keep chasing why it did, the situation is now impossible. A deadline timer, armed while a request is in flight and longer than the HTTP timeouts so the precise network error still wins when it works. On expiry the interface comes back and says so. The thread is abandoned, not cancelled: it dies when its socket fails, and if it somehow succeeds its result still shows. The page's bridge queue had the same shape of bug: a throw while removing the iframe left "sending" true forever, and every later command was dropped in silence. The removal is now in a try/finally. Also fixed while in there: SetBusy hardcoded "Sync" as the button label, so a vault-less device lost "Download vault" on every busy transition. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+43
-2
@@ -119,6 +119,14 @@ type
|
||||
FClipTimer: TTimer;
|
||||
FCopied: string;
|
||||
|
||||
/// ECHEANCE SUR UNE OPERATION RESEAU. Sans elle, un appel qui ne rend
|
||||
/// jamais la main laisse l'interface morte et muette : les deux actions
|
||||
/// restent desactivees, aucun message n'apparait, et rien n'y ramene -
|
||||
/// c'est arrive avec le serveur local arrete. Les delais de THTTPClient
|
||||
/// sont censes couvrir ce cas ; celui-ci couvre le jour ou ils ne le font
|
||||
/// pas, quelle qu'en soit la raison.
|
||||
FDeadline: TTimer;
|
||||
|
||||
// --- verrouillage sur inactivite
|
||||
FIdleTimer: TTimer;
|
||||
FLastActivity: TDateTime;
|
||||
@@ -161,6 +169,7 @@ type
|
||||
procedure PushConfig;
|
||||
procedure OpenEntry(AVaultIndex: Integer);
|
||||
procedure OnClipTimer(Sender: TObject);
|
||||
procedure OnDeadline(Sender: TObject);
|
||||
procedure OnHardwareBack(Sender: TObject; var Key: Word;
|
||||
var KeyChar: WideChar; Shift: TShiftState);
|
||||
|
||||
@@ -228,6 +237,14 @@ begin
|
||||
FClipTimer.Interval := CLIPBOARD_CLEAR_SECONDS * 1000;
|
||||
FClipTimer.OnTimer := OnClipTimer;
|
||||
|
||||
// Plus long que les delais de THTTPClient (15 s), pour que le message precis
|
||||
// du client reseau arrive le premier quand il fonctionne. Celui-ci n'est que
|
||||
// le filet.
|
||||
FDeadline := TTimer.Create(Self);
|
||||
FDeadline.Enabled := False;
|
||||
FDeadline.Interval := 25000;
|
||||
FDeadline.OnTimer := OnDeadline;
|
||||
|
||||
FTotpTimer := TTimer.Create(Self);
|
||||
FTotpTimer.Enabled := False;
|
||||
FTotpTimer.Interval := 1000;
|
||||
@@ -1022,11 +1039,35 @@ begin
|
||||
end;
|
||||
|
||||
procedure TForm8.SetBusy(ABusy: Boolean);
|
||||
var
|
||||
LCanOpen: Boolean;
|
||||
LLabel: string;
|
||||
begin
|
||||
FBusy := ABusy;
|
||||
WebCall(Format('PM.setActions(%s, "Sync", %s)',
|
||||
[LowerCase(BoolToStr(HasVault and not FVaultUnreadable, True)),
|
||||
FDeadline.Enabled := False; // reposee a zero, pas prolongee
|
||||
FDeadline.Enabled := ABusy;
|
||||
LCanOpen := HasVault and not FVaultUnreadable;
|
||||
// L'intitule suit l'etat du cache et non un mot fixe : sans coffre local,
|
||||
// l'action n'est pas une synchronisation mais un premier telechargement, et
|
||||
// le reprendre en dur ici effacait cette distinction a chaque passage.
|
||||
if LCanOpen then LLabel := 'Sync' else LLabel := 'Download vault';
|
||||
WebCall(Format('PM.setActions(%s, %s, %s)',
|
||||
[LowerCase(BoolToStr(LCanOpen, True)), JsArg(LLabel),
|
||||
LowerCase(BoolToStr(ABusy, True))]));
|
||||
end;
|
||||
|
||||
/// L'operation reseau n'a pas rendu la main dans le delai. On rend l'interface
|
||||
/// a l'utilisateur et on le dit. Le thread, lui, est ABANDONNE : il mourra
|
||||
/// quand sa socket finira par echouer, et s'il aboutit malgre tout, son
|
||||
/// resultat s'affichera - il n'y a rien a annuler.
|
||||
procedure TForm8.OnDeadline(Sender: TObject);
|
||||
begin
|
||||
FDeadline.Enabled := False;
|
||||
if not FBusy then Exit;
|
||||
Log(' no reply after ' + (FDeadline.Interval div 1000).ToString +
|
||||
' s - request abandoned');
|
||||
Status('No reply from the server');
|
||||
SetBusy(False);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user