TM-SGNL-iOS/SignalServiceKit/Messages/Attachments/V2/Downloads/QueuedAttachmentDownloadRecord.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

110 lines
3.5 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public import GRDB
public struct QueuedAttachmentDownloadRecord: Codable, FetchableRecord, MutablePersistableRecord {
public typealias IDType = Int64
/// Sqlite row id
public var id: IDType?
/// Id of the associated ``Attachment``.
public let attachmentId: Attachment.IDType
/// The priority at which to download.
/// Determines both which goes first (higher first) and which are allowed by current settings.
public internal(set) var priority: AttachmentDownloadPriority
/// A given ``Attachment`` has metadata enabling downloading from
/// many possible sources; this differentiates which should be used.
public enum SourceType: Int, Codable, CaseIterable {
case transitTier = 0
case mediaTierFullsize = 1
case mediaTierThumbnail = 2
}
/// Where we will be downloading the attachment from.
public let sourceType: SourceType
/// If the local time is not currently past this date, do not attempt to download.
/// Used for retry backoff. Starts at nil.
public internal(set) var minRetryTimestamp: UInt64?
/// Number of prior retry attempts so far (starts at 0).
public internal(set) var retryAttempts: UInt32
/// Path to the partially downloaded file. Check the length (and existence)
/// of the file on disk to determine how much progress has been made.
/// Exists in the same folder as fully-downloaded attachments.
/// TODO: unused; partial progress is not tracked/reused between app launches.
public let partialDownloadRelativeFilePath: String
public var partialDownloadFileUrl: URL {
return AttachmentStream.absoluteAttachmentFileURL(
relativeFilePath: partialDownloadRelativeFilePath
)
}
// MARK: - Initializers
public static func forNewDownload(
ofAttachmentWithId attachmentId: Attachment.IDType,
priority: AttachmentDownloadPriority = .default,
sourceType: SourceType
) -> QueuedAttachmentDownloadRecord {
return .init(
id: nil,
attachmentId: attachmentId,
priority: priority,
sourceType: sourceType,
// Initial state always allows downloads.
minRetryTimestamp: nil,
retryAttempts: 0,
partialDownloadRelativeFilePath: AttachmentStream.newRelativeFilePath()
)
}
// MARK: - Private
private init(
id: Int64?,
attachmentId: Int64,
priority: AttachmentDownloadPriority,
sourceType: SourceType,
minRetryTimestamp: UInt64?,
retryAttempts: UInt32,
partialDownloadRelativeFilePath: String
) {
self.id = id
self.attachmentId = attachmentId
self.priority = priority
self.sourceType = sourceType
self.minRetryTimestamp = minRetryTimestamp
self.retryAttempts = retryAttempts
self.partialDownloadRelativeFilePath = partialDownloadRelativeFilePath
}
// MARK: - MutablePersistableRecord
public static let databaseTableName: String = "AttachmentDownloadQueue"
public mutating func didInsert(with rowID: Int64, for column: String?) {
self.id = rowID
}
// MARK: - Codable
public enum CodingKeys: String, CodingKey {
case id
case attachmentId
case priority
case sourceType
case minRetryTimestamp
case retryAttempts
case partialDownloadRelativeFilePath = "localRelativeFilePath"
}
}