Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/DataBackup/Sources/DataBackup/Backup/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 5 kB image not shown  

Quelle  DataBackup.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import FileUtility
import Foundation
import libthreemaSwift

public final actor DataBackup: DataBackupProtocol {

    // MARK: - Public types

    public typealias ProgressHandler = @Sendable (DataBackupProgress) -> Void

    // MARK: - Private properties

    private let backupURL: URL
    private let fileUtility: FileUtilityProtocol
    private let createTask: any DataBackupCreateTaskProtocol
    private let progressInterval: Duration
    private let onProgress: ProgressHandler?

    private var incompleteBackupURL: URL?
    private var lastReportedPhase: DataBackupProgress.Phase?
    private var lastReportedAt = ContinuousClock.now

    // MARK: - Lifetime

    public init(
        backupURL: URL,
        fileUtility: any FileUtilityProtocol,
        createTask: any DataBackupCreateTaskProtocol,
        progressInterval: Duration = .milliseconds(500),
        onProgress: ProgressHandler? = nil
    ) {
        self.backupURL = backupURL
        self.fileUtility = fileUtility
        self.createTask = createTask
        self.progressInterval = progressInterval
        self.onProgress = onProgress
    }

    // MARK: - Public methods

    public func perform() async throws {
        try createEmptyFile(at: backupURL)
        incompleteBackupURL = backupURL

        defer { cleanUpIfNeeded() }

        let fileHandle = try openFileHandle(url: backupURL)

        defer { closeFileHandle(fileHandle) }

        var done = false

        while !done {
            // Polling and writing never suspend, so this loop is not cancelled implicitly.
            try Task.checkCancellation()

            switch try createTask.poll() {
            case let .instruction(instruction):
                try handleInstruction(instruction, fileHandle: fileHandle)

            case .done:
                done = true
                incompleteBackupURL = nil
            }
        }
    }

    // MARK: - Private methods

    private func handleInstruction(_ payload: DataBackupCreateInstruction, fileHandle: FileHandle) throws {
        if let writeInstruction = payload.writeInstruction {
            try handleWriteInstruction(writeInstruction, fileHandle: fileHandle)
        }

        if let stateUpdate = payload.stateUpdate {
            handleStateUpdate(stateUpdate)
        }
    }

    private func handleWriteInstruction(_ instruction: DataBackupCreateWriteInstruction, fileHandle: FileHandle) throws {
        switch instruction {
        case let .local(.append(data)):
            try fileUtility.write(contents: data, offset: nil, to: fileHandle, fileURL: backupURL)

        case let .local(.writeAt(offset, data)):
            try fileUtility.write(contents: data, offset: offset, to: fileHandle, fileURL: backupURL)
        }
    }

    /// Reports progress, throttled.
    ///
    /// The backup task recomputes its state update on every poll, so within a phase only the item count moves and an
    /// update arrives once per written item. Phase changes are always reported, item counts of the phase that is
    /// already reported at most once per ``progressInterval``.
    private func handleStateUpdate(_ stateUpdate: DataBackupCreateStateUpdate) {
        let progress = DataBackupProgress(stateUpdate)
        let now = ContinuousClock.now

        guard progress.phase != lastReportedPhase || lastReportedAt.duration(to: now) >= progressInterval else {
            return
        }

        lastReportedPhase = progress.phase
        lastReportedAt = now

        DDLogVerbose("Backup create progress: \(progress.phase)")

        onProgress?(progress)
    }

    private func createEmptyFile(at url: URL) throws {
        do {
            if fileUtility.fileExists(at: url) {
                try fileUtility.delete(at: url)
            }
            try fileUtility.createEmptyFile(atURL: url)
        }
        catch {
            let fileName = backupURL.lastPathComponent
            DDLogError("Couldn't create an empty file named \(fileName): \(error)")
            throw error
        }
    }

    private func openFileHandle(url: URL) throws -> FileHandle {
        do {
            return try fileUtility.createFileHandle(forWritingToURL: backupURL)
        }
        catch {
            let fileName = backupURL.lastPathComponent
            DDLogError("Couldn't open the file handle for file name \(fileName): \(error)")
            throw error
        }
    }

    private func closeFileHandle(_ fileHandle: FileHandle) {
        do {
            try fileUtility.closeFileHandle(fileHandle)
        }
        catch {
            let fileDescriptor = fileHandle.fileDescriptor
            let fileName = backupURL.lastPathComponent
            DDLogError("Couldn't close the file handle \(fileDescriptor) for file name \(fileName): \(error)")
            // Absorb the error and only log the error.
        }
    }

    private func cleanUpIfNeeded() {
        guard let incompleteBackupURL else {
            return
        }
        do {
            try fileUtility.delete(at: incompleteBackupURL)
        }
        catch {
            let fileName = incompleteBackupURL.lastPathComponent
            DDLogError("Couldn't delete the file \(fileName): \(error)")
            // Absorb the error and only log the error.
        }
    }
}

Messung
CHZG
869910095

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.