Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Just to see the time on the logs
- struct Logger {
- private static let dateFormatter: DateFormatter = {
- let formatter = DateFormatter()
- formatter.dateFormat = "yyyy-MM-dd hh:mm:ss.SSSSSZ"
- return formatter
- }()
- static func log(_ object: Any) {
- let date = Self.dateFormatter.string(from: Date())
- print("\(date): - \(object)")
- }
- }
- actor FileDownloader {
- static var fileIdCounter = 0
- let fileId: Int
- var onDidDownload: (() -> Void)? //In case we want to trigger something
- init(onDidDownload: (() -> Void)? = nil) {
- self.fileId = Self.fileIdCounter
- Self.fileIdCounter += 1
- self.onDidDownload = onDidDownload
- }
- func download() async throws {
- let rng = Int.random(in: 5...15)
- try? await Task.sleep(nanoseconds: UInt64(rng * 100_000_000))
- Logger.log("Download finished for fileId: \(fileId)")
- }
- }
- //Handle 5 downloads max concurrently, when on finished, the next one is directly launched.
- // This avoid using Groups, that need the full downloads of the group to finish before handling the next one.
- //There is currently no Cancel management, just a hard stop
- //`add(_:)` could start the whole download process if it isn't started
- //States "started, paused etc". could be added.
- actor DownloadManager {
- //Whole list of wdw
- var queue: [FileDownloader] = []
- var maxConcurrentDownloads: Int = 5
- var currentDownloads: [FileDownloader] = []
- //In case of downloads that trigger errors, currently just blacklisted withing app life, but could be handled differently ofc
- var blacklist: [FileDownloader] = []
- func prioritize(_ fileDownloaders: [FileDownloader]) {
- fileDownloaders.forEach {
- prioritize($0)
- }
- }
- func prioritize(_ fileDownloader: FileDownloader) {
- Logger.log("Prioritize \(fileDownloader.fileId)")
- guard !currentDownloads.contains(where: { $0.fileId == fileDownloader.fileId }) else {
- //Already downloading
- Logger.log("Dwd \(fileDownloader.fileId) is already being downloaded")
- return
- }
- guard !blacklist.contains(where: { $0.fileId == fileDownloader.fileId }) else {
- //Already tried to download this time
- Logger.log("Dwd \(fileDownloader.fileId) is blacklisted")
- return
- }
- if let queuedIndex = queue.firstIndex(where: { $0.fileId == fileDownloader.fileId }) {
- queue.remove(at: queuedIndex)
- queue.insert(fileDownloader, at: 0)
- Logger.log("Dwd \(fileDownloader.fileId) is priorized with success")
- }
- }
- func add(_ fileDownloader: FileDownloader) {
- queue.append(fileDownloader)
- }
- func add(_ fileDownloaders: [FileDownloader]) {
- queue.append(contentsOf: fileDownloaders)
- }
- func download() async {
- guard !queue.isEmpty else {
- Logger.log("Nothing to download, will set a timer to check in X minutes")
- return
- }
- let freeQueuesCount = maxConcurrentDownloads - currentDownloads.count
- guard freeQueuesCount > 0 else {
- Logger.log("Max concurrent reached with \(currentDownloads.map { "\($0.fileId)" }.joined(separator: ", "))")
- return
- }
- for _ in 0..<freeQueuesCount {
- let fileDownloader = queue.removeFirst()
- currentDownloads.append(fileDownloader)
- //Detached launch, that way we can launch in parralels
- Task {
- await downloadNext(fileDownloader)
- }
- }
- }
- func downloadNext(_ fileDownloader: FileDownloader) async {
- Logger.log("Launching: \(fileDownloader.fileId)")
- Logger.log("Current downloads: \(currentDownloads.map { "\($0.fileId)" }.joined(separator: ", "))")
- do {
- try await fileDownloader.download()
- } catch {
- print("File download failed for \(fileDownloader.fileId)")
- blacklist.append(fileDownloader)
- }
- await fileDownloader.onDidDownload?()
- currentDownloads.removeAll(where: { $0.fileId == fileDownloader.fileId })
- Task { await download() }
- }
- func stop() {
- Logger.log("STOP")
- queue.removeAll()
- }
- }
- //Code play
- // Justed added
- /*
- Task {
- await dwdManagement()
- }
- in `func application(_ application:didFinishLaunchingWithOptions:)` in a new sample app to test and play
- */
- func dwdManagement() async {
- let manager = DownloadManager()
- var dwds: [FileDownloader] = []
- for _ in 0...49 {
- dwds.append(FileDownloader())
- }
- dwds.append(FileDownloader(onDidDownload: {
- guard let last = dwds.last else { return }
- Logger.log("Did Finished Special one -> Prioritize last!")
- //It's also check if we can mess with the order
- Task { await manager.prioritize(last) }
- }))
- for _ in 0...49 {
- dwds.append(FileDownloader())
- }
- await manager.add(dwds)
- Task {
- //Quick test on "Stop"
- try? await Task.sleep(nanoseconds: 25_000_000_000)
- await manager.stop()
- }
- await manager.download()
- }
Advertisement
Add Comment
Please, Sign In to add comment