Receives a HashSinglePart result from CPartFileHashThread (via the CPartFileHashResultEvent dispatched on CamuleApp). Runs the same success/failure / AICH-recovery logic the original synchronous Phase 3 did, just with the boolean result already computed by the worker.
| 3541 | // success/failure / AICH-recovery logic the original synchronous Phase 3 |
| 3542 | // did, just with the boolean result already computed by the worker. |
| 3543 | void CPartFile::OnAsyncHashComplete(uint16 partNumber, bool ok, |
| 3544 | bool fromAICHRecoveryDataAvailable) |
| 3545 | { |
| 3546 | if (m_inDestructor || !theApp || !theApp->IsRunning()) { |
| 3547 | return; |
| 3548 | } |
| 3549 | if (partNumber >= GetPartCount()) { |
| 3550 | return; |
| 3551 | } |
| 3552 | |
| 3553 | const uint32 partRange = GetPartSize(partNumber) - 1; |
| 3554 | |
| 3555 | // Track whether this part's outcome changes persistent state. |
| 3556 | // Only those branches need a SavePartFile flush; the success path |
| 3557 | // for an already-complete part touches in-memory bookkeeping only |
| 3558 | // (VerifiedData, m_corrupted_list, status), which is fine to |
| 3559 | // persist on the next FlushBuffer-driven SavePartFile. Avoids |
| 3560 | // hammering the .met file on the main thread once per part — |
| 3561 | // that's what made the GUI freeze on async-hash drain. |
| 3562 | bool stateChanged = false; |
| 3563 | |
| 3564 | if (IsComplete(partNumber)) { |
| 3565 | if (!ok) { |
| 3566 | AddLogLineC(CFormat( |
| 3567 | _("Downloaded part %i is corrupt in file: %s") ) |
| 3568 | % partNumber % GetFileName()); |
| 3569 | AddGap(partNumber); |
| 3570 | if (!IsCorruptedPart(partNumber)) { |
| 3571 | m_corrupted_list.push_back(partNumber); |
| 3572 | } |
| 3573 | // request AICH recovery data; skip if we're already inside |
| 3574 | // an AICH recovery to avoid infinite recursion. |
| 3575 | if (!fromAICHRecoveryDataAvailable) { |
| 3576 | RequestAICHRecovery(partNumber); |
| 3577 | } |
| 3578 | m_iLostDueToCorruption += (partRange + 1); |
| 3579 | stateChanged = true; |
| 3580 | } else { |
| 3581 | if (!m_hashsetneeded) { |
| 3582 | AddDebugLogLineN(logPartFile, CFormat( |
| 3583 | "Finished part %u of '%s'") % partNumber % GetFileName()); |
| 3584 | } |
| 3585 | |
| 3586 | m_CorruptionBlackBox->VerifiedData(true, partNumber, 0, partRange); |
| 3587 | |
| 3588 | // If this part was carried as corrupted in the .met from a |
| 3589 | // prior session, removing it from m_corrupted_list IS a |
| 3590 | // persistent state change — without a save, next launch |
| 3591 | // would still flag it as needing recovery. |
| 3592 | if (IsCorruptedPart(partNumber)) { |
| 3593 | EraseFirstValue(m_corrupted_list, partNumber); |
| 3594 | stateChanged = true; |
| 3595 | } |
| 3596 | |
| 3597 | if (status == PS_EMPTY) { |
| 3598 | if (GetHashCount() == GetED2KPartHashCount() && !m_hashsetneeded) { |
| 3599 | SetStatus(PS_READY); |
| 3600 | theApp->sharedfiles->SafeAddKFile(this); |
no test coverage detected