diff --git a/mainApk.pas b/mainApk.pas index b548854..96f861f 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -130,6 +130,18 @@ type /// Elle part au verrouillage, avec lui. FKey, FKeySalt: TBytes; FKeyIters: Integer; + /// L'INSTANTANE BRUT, tel qu'il a ete recu. Pas une reserialisation de + /// TVault : celle-ci perdrait tout ce que le telephone ne lit pas - + /// le contenu des pieces jointes, l'avatar, les tombstones - c'est + /// l'invariant de PMA.VaultPatch. + /// + /// Il permet d'enregistrer SANS RETIRER le coffre d'abord. Le tirage + /// coutait 3,2 s pour 266 Ko, a chaque sauvegarde, alors qu'on tient deja + /// ce qu'il rapporte. Ce qu'il apportait vraiment, c'etait la certitude de + /// modifier la derniere version publiee - et le sha la donne aussi : si un + /// autre appareil a publie entre-temps, Gitea refuse en 409 et on retire + /// pour de bon. + FPlain: string; /// Code d'ouverture du cache local, choisi dans l'application. JAMAIS /// ENREGISTRE : il est vide a chaque lancement et doit etre retape. C'est /// ce qui le distingue du jeton, dont la persistance est un confort sans @@ -730,13 +742,30 @@ begin LClient := TSyncClient.Create(FUrl, FToken); for LAttempt := 1 to 3 do begin - Log(Format('save: attempt %d - GET', [LAttempt])); - // Sans empreinte connue : on VEUT le corps, pas un 304. - LGet := LClient.Fetch; - if LGet.Status <> ssOK then + // PREMIER ESSAI SANS TIRER. On tient l'instantane et le sha qui va + // avec ; le tirage ne servait qu'a s'assurer de modifier la + // derniere version publiee, et le sha le prouve mieux : s'il n'est + // plus le bon, Gitea refuse. On ne retire donc que lorsqu'on a + // vraiment quelque chose a apprendre. + if (LAttempt = 1) and (FPlain <> '') and (FETag <> '') then begin - LErr := Format('read failed (HTTP %d) %s', [LGet.HttpCode, LGet.Error]); - Break; + Log('save: publishing against the snapshot in hand'); + LGet.Status := ssOK; + LGet.Container := ''; + LGet.ETag := FETag; + LPlain := FPlain; + end + else + begin + Log(Format('save: attempt %d - GET', [LAttempt])); + // Sans empreinte connue : on VEUT le corps, pas un 304. + LGet := LClient.Fetch; + if LGet.Status <> ssOK then + begin + LErr := Format('read failed (HTTP %d) %s', [LGet.HttpCode, LGet.Error]); + Break; + end; + LPlain := ''; end; try @@ -745,7 +774,9 @@ begin // reutilise. Deriver deux fois le meme mot de passe coutait une // seconde fois quatre a six secondes, pour une cle equivalente. LSw := TStopwatch.StartNew; - LPlain := OpenContainer(LGet.Container, FSyncPwd); + // LPlain deja pose quand on publie contre l'instantane en main. + if LPlain = '' then + LPlain := OpenContainer(LGet.Container, FSyncPwd); LKey := FKey; LSalt := FKeySalt; LIter := FKeyIters; LNew := APatch(LPlain); Log(Format('save: decrypt+patch in %d ms', [LSw.ElapsedMilliseconds])); @@ -760,7 +791,10 @@ begin LSw := TStopwatch.StartNew; LBody := EncryptContainerWithKey(LNew, LKey, LSalt, LIter); Log(Format('save: re-encrypt in %d ms', [LSw.ElapsedMilliseconds])); + LSw := TStopwatch.StartNew; LPut := LClient.Put(LBody, LGet.ETag, AComment); + Log(Format('save: PUT %d chars in %d ms', + [Length(LBody), LSw.ElapsedMilliseconds])); if LPut.Status = ssOK then begin Log('save: published, new sha ' + LPut.ETag); @@ -781,6 +815,7 @@ begin if LPut.Status = ssConflict then begin Log('save: 409 - another device published, re-reading'); + LPlain := ''; Continue; end; @@ -1081,12 +1116,14 @@ begin FKey := nil; FKeySalt := nil; FKeyIters := 0; + FPlain := ''; ShowUnlock; end; procedure TForm8.AdoptVault(const APlainJson: string); begin FVault.LoadFromJson(APlainJson); + FPlain := APlainJson; Log(' ' + FVault.LiveCount.ToString + ' entries, ' + FVault.TrashCount.ToString + ' in trash'); FVaultUnreadable := False;