aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Models
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-07-24 12:32:41 -0700
committerDustin Mierau <dustin@mierau.me>2024-07-24 12:32:41 -0700
commit8633db7e6ca9f38345d7be0ab90193d6325904bf (patch)
treea950663e587c0bb0b051a61882ca9df6949a2446 /Hotline/Models
parent844317f8a3f5c7b11394653c8563c6e9c24d7e85 (diff)
First pass at uploads and a big refactoring of transfer clients. Also now showing download progress bar on file icon in dock (like Safari).
Diffstat (limited to 'Hotline/Models')
-rw-r--r--Hotline/Models/FilePreview.swift16
-rw-r--r--Hotline/Models/Hotline.swift206
-rw-r--r--Hotline/Models/TransferInfo.swift1
3 files changed, 175 insertions, 48 deletions
diff --git a/Hotline/Models/FilePreview.swift b/Hotline/Models/FilePreview.swift
index d558c4c..3960a0d 100644
--- a/Hotline/Models/FilePreview.swift
+++ b/Hotline/Models/FilePreview.swift
@@ -15,9 +15,9 @@ enum FilePreviewType: Equatable {
}
@Observable
-final class FilePreview: HotlineFileClientDelegate {
+final class FilePreview: HotlineFilePreviewClientDelegate {
@ObservationIgnored let info: PreviewFileInfo
- @ObservationIgnored var client: HotlineFileClient? = nil
+ @ObservationIgnored var client: HotlineFilePreviewClient? = nil
var state: FilePreviewState = .unloaded
var progress: Double = 0.0
@@ -49,20 +49,20 @@ final class FilePreview: HotlineFileClientDelegate {
init(info: PreviewFileInfo) {
self.info = info
- self.client = HotlineFileClient(address: info.address, port: UInt16(info.port), reference: info.id, size: UInt32(info.size), type: .preview)
+ self.client = HotlineFilePreviewClient(address: info.address, port: UInt16(info.port), reference: info.id, size: UInt32(info.size))
self.client?.delegate = self
}
func download() {
- self.client?.downloadToMemory()
+ self.client?.start()
}
func cancel() {
- self.client?.cancel(deleteIncompleteFile: true)
+ self.client?.cancel()
}
- func hotlineFileStatusChanged(client: HotlineFileClient, reference: UInt32, status: HotlineFileClientStatus, timeRemaining: TimeInterval) {
- print("FILE STATUS CHANGED", status)
+ func hotlineTransferStatusChanged(client: any HotlineTransferClient, reference: UInt32, status: HotlineTransferStatus, timeRemaining: TimeInterval) {
+ print("FilePreview: Download status changed:", status)
switch status {
case .unconnected:
@@ -86,7 +86,7 @@ final class FilePreview: HotlineFileClientDelegate {
}
}
- func hotlineFileDownloadedData(client: HotlineFileClient, reference: UInt32, data: Data) {
+ func hotlineFilePreviewComplete(client: HotlineFilePreviewClient, reference: UInt32, data: Data) {
self.state = .loaded
self.data = data
diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift
index c57434a..69a11d3 100644
--- a/Hotline/Models/Hotline.swift
+++ b/Hotline/Models/Hotline.swift
@@ -1,7 +1,7 @@
import SwiftUI
@Observable
-class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
+class Hotline: Equatable, HotlineClientDelegate, HotlineFileDownloadClientDelegate, HotlineFilePreviewClientDelegate, HotlineFileUploadClientDelegate {
let id: UUID = UUID()
let trackerClient: HotlineTrackerClient
let client: HotlineClient
@@ -137,11 +137,11 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
var accountsLoaded: Bool = false
var instantMessages: [UInt16:[InstantMessage]] = [:]
var transfers: [TransferInfo] = []
- var downloads: [HotlineFileClient] = []
+ var downloads: [HotlineTransferClient] = []
var unreadInstantMessages: [UInt16:UInt16] = [:]
var unreadPublicChat: Bool = false
- @ObservationIgnored var bannerClient: HotlineFileClient?
+ @ObservationIgnored var bannerClient: HotlineFilePreviewClient?
#if os(macOS)
var bannerImage: NSImage? = nil
#elseif os(iOS)
@@ -502,13 +502,15 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
if
let self = self,
+// let server = self.server,
let address = self.server?.address,
let port = self.server?.port,
let referenceNumber = downloadReferenceNumber,
let transferSize = downloadTransferSize {
- print("DOWNLOADING TO MEMORY")
- let fileClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .file)
+ let fileClient = HotlineFileDownloadClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize))
+// let previewClient = HotlineFilePreviewClient(server: self.server, reference: referenceNumber, size: UInt32(transferSize), type: .fileDownload)
+// let fileClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .fileDownload)
fileClient.delegate = self
self.downloads.append(fileClient)
@@ -516,7 +518,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
transfer.downloadCallback = callback
self.transfers.append(transfer)
- fileClient.downloadToFile()
+ fileClient.start()
}
}
}
@@ -542,8 +544,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
let referenceNumber = downloadReferenceNumber,
let transferSize = downloadTransferSize {
- print("DOWNLOADING TO MEMORY")
- let fileClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .file)
+ let fileClient = HotlineFileDownloadClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize))
fileClient.delegate = self
self.downloads.append(fileClient)
@@ -552,10 +553,80 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
transfer.progressCallback = progressCallback
self.transfers.append(transfer)
- fileClient.downloadToFile(to: fileURL)
+ fileClient.start(to: fileURL)
}
}
}
+
+ @MainActor func uploadFile(url fileURL: URL, path: [String], complete callback: ((TransferInfo) -> Void)? = nil) {
+ let fileName = fileURL.lastPathComponent
+
+ guard fileURL.isFileURL, !fileName.isEmpty else {
+ print("NOT A FILE URL?")
+ return
+ }
+
+ let filePath = fileURL.path(percentEncoded: false)
+
+ var fileIsDirectory: ObjCBool = false
+ guard FileManager.default.fileExists(atPath: filePath, isDirectory: &fileIsDirectory),
+ fileIsDirectory.boolValue == false else {
+ print("FILE IS A DIRECTORY?")
+ return
+ }
+
+ var fileSize: UInt = 0
+
+ // Data size
+ let fileAttributes = try? FileManager.default.attributesOfItem(atPath: filePath)
+ if let sizeAttribute = fileAttributes?[.size] as? NSNumber {
+ print("DATA SIZE \(sizeAttribute.uintValue)")
+ fileSize += sizeAttribute.uintValue
+ }
+
+ // Resource size
+ let resourceURL = fileURL.appendingPathComponent("..namedfork/rsrc")
+
+
+ print("RESOURCE PATH \(resourceURL)")
+ let resourceAttributes = try? FileManager.default.attributesOfItem(atPath: resourceURL.path(percentEncoded: false))
+ if let sizeAttribute = resourceAttributes?[.size] as? NSNumber {
+ print("RESOURCE SIZE \(sizeAttribute.uintValue)")
+ fileSize += sizeAttribute.uintValue
+ }
+
+ print("FILE SIZE? \(fileSize)")
+
+ guard fileSize > 0 else {
+ print("FILE IS EMPTY??")
+ return
+ }
+
+ print("FILE SIZE: \(fileSize) NAME: \(fileName) PATH: \(path)")
+
+ self.client.sendUploadFile(name: fileName, path: path) { [weak self] success, uploadReferenceNumber in
+ print("UPLOAD REFERENCE: \(String(describing: uploadReferenceNumber))")
+
+ if let self = self,
+ let address = self.server?.address,
+ let port = self.server?.port,
+ let referenceNumber = uploadReferenceNumber,
+ let fileClient = HotlineFileUploadClient(upload: fileURL, address: address, port: UInt16(port), reference: referenceNumber) {
+
+ print("GOING TO UPLOAD")
+
+ fileClient.delegate = self
+ self.downloads.append(fileClient)
+
+ let transfer = TransferInfo(id: referenceNumber, title: fileName, size: fileSize)
+ transfer.uploadCallback = callback
+ self.transfers.append(transfer)
+
+ fileClient.start()
+ }
+ }
+
+ }
@MainActor func getFileDetails(_ fileName: String, path: [String]) async -> FileDetails? {
var fullPath: [String] = []
@@ -611,27 +682,6 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
let transferSize = downloadTransferSize {
info = PreviewFileInfo(id: referenceNumber, address: address, port: port, size: transferSize, name: fileName)
-
-// let fileClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .preview)
-// fileClient.delegate = self
-// self.downloads.append(fileClient)
-
-// if addTransfer {
-// let transfer = TransferInfo(id: referenceNumber, title: fileName, size: UInt(transferSize))
-// transfer.previewCallback = callback
-// self.transfers.append(transfer)
-// }
-
-// fileClient.downloadToMemory()
-
- print("DOWNLOADING TO MEMORY")
-// fileClient.downloadToMemory({ [weak self] fileData in
-// print("DOWNLOADED PREVIEW DATA", fileData?.count)
-// self?.downloads.removeAll { $0.referenceNumber == referenceNumber }
-// callback?(fileData != nil, fileData)
-// })
-
-// self.downloads.append(fileClient)
}
callback?(info)
@@ -651,7 +701,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
if let i = self.downloads.firstIndex(where: { $0.referenceNumber == id }) {
let fileClient = self.downloads.remove(at: i)
- fileClient.cancel(deleteIncompleteFile: true)
+ fileClient.cancel()
}
}
@@ -662,7 +712,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
self.downloads = []
for fileClient in downloads {
- fileClient.cancel(deleteIncompleteFile: true)
+ fileClient.cancel()
}
}
@@ -696,9 +746,9 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
let port = self.server?.port,
let referenceNumber = downloadReferenceNumber,
let transferSize = downloadTransferSize {
- self.bannerClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .preview)
+ self.bannerClient = HotlineFilePreviewClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize))
self.bannerClient?.delegate = self
- self.bannerClient?.downloadToMemory()
+ self.bannerClient?.start()
}
}
}
@@ -856,9 +906,9 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
}
- // MARK: - Hotline File Delegate
+ // MARK: - Hotline Transfer Delegate
- func hotlineFileStatusChanged(client: HotlineFileClient, reference: UInt32, status: HotlineFileClientStatus, timeRemaining: TimeInterval) {
+ func hotlineTransferStatusChanged(client: HotlineTransferClient, reference: UInt32, status: HotlineTransferStatus, timeRemaining: TimeInterval) {
switch status {
case .unconnected:
break
@@ -880,7 +930,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
transfer.failed = true
transfer.timeRemaining = 0.0
}
- if let b = self.bannerClient, reference == b.referenceNumber {
+ if let b = self.bannerClient, b.referenceNumber == reference {
b.delegate = nil
self.bannerClient = nil
}
@@ -893,13 +943,55 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
}
}
- func hotlineFileReceivedInfo(client: HotlineFileClient, reference: UInt32, info: HotlineFileInfoFork) {
+ func hotlineFileDownloadReceivedInfo(client: HotlineFileDownloadClient, reference: UInt32, info: HotlineFileInfoFork) {
if let transfer = self.transfers.first(where: { $0.id == reference }) {
transfer.title = info.name
}
}
- func hotlineFileDownloadedData(client: HotlineFileClient, reference: UInt32, data: Data) {
+// func hotlineFileReceivedInfo(client: HotlineFileClient, reference: UInt32, info: HotlineFileInfoFork) {
+// if let transfer = self.transfers.first(where: { $0.id == reference }) {
+// transfer.title = info.name
+// }
+// }
+
+// func hotlineTransferStatusChanged(client: HotlineTransferClient, status: HotlineTransferStatus, timeRemaining: TimeInterval) {
+// switch status {
+// case .unconnected:
+// break
+// case .connecting:
+// break
+// case .connected:
+// break
+// case .progress(let progress):
+// if let transfer = self.transfers.first(where: { $0.id == client.referenceNumber }) {
+// transfer.progress = progress
+// transfer.timeRemaining = timeRemaining
+// transfer.progressCallback?(transfer, progress)
+// }
+// case .failed(_):
+// if let i = self.downloads.firstIndex(where: { $0.referenceNumber == client.referenceNumber }) {
+// self.downloads.remove(at: i)
+// }
+// if let transfer = self.transfers.first(where: { $0.id == client.referenceNumber }) {
+// transfer.failed = true
+// transfer.timeRemaining = 0.0
+// }
+// if let b = self.bannerClient, reference == b.referenceNumber {
+// b.delegate = nil
+// self.bannerClient = nil
+// }
+// case .completed:
+// if let transfer = self.transfers.first(where: { $0.id == client.referenceNumber }) {
+// transfer.completed = true
+// transfer.timeRemaining = 0.0
+// }
+// break
+// }
+// }
+
+
+ func hotlineFilePreviewComplete(client: HotlineFilePreviewClient, reference: UInt32, data: Data) {
if let b = self.bannerClient, b.referenceNumber == reference {
#if os(macOS)
self.bannerImage = NSImage(data: data)
@@ -919,7 +1011,27 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
}
}
- func hotlineFileDownloadedFile(client: HotlineFileClient, reference: UInt32, at: URL) {
+// func hotlineFileDownloadedData(client: HotlineFileClient, reference: UInt32, data: Data) {
+// if let b = self.bannerClient, b.referenceNumber == reference {
+// #if os(macOS)
+// self.bannerImage = NSImage(data: data)
+// #elseif os(iOS)
+// self.bannerImage = UIImage(data: data)
+// #endif
+// }
+// else
+// if let i = self.transfers.firstIndex(where: { $0.id == reference }) {
+// let transfer = self.transfers[i]
+// transfer.previewCallback?(transfer, data)
+// self.transfers.remove(at: i)
+// }
+//
+// if let i = self.downloads.firstIndex(where: { $0.referenceNumber == reference }) {
+// self.downloads.remove(at: i)
+// }
+// }
+
+ func hotlineFileDownloadComplete(client: HotlineFileDownloadClient, reference: UInt32, at: URL) {
if let i = self.transfers.firstIndex(where: { $0.id == reference }) {
let transfer = self.transfers[i]
transfer.fileURL = at
@@ -934,6 +1046,20 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate {
}
}
+ func hotlineFileUploadComplete(client: HotlineFileUploadClient, reference: UInt32) {
+ if let i = self.transfers.firstIndex(where: { $0.id == reference }) {
+ let transfer = self.transfers[i]
+ transfer.uploadCallback?(transfer)
+ if Prefs.shared.playSounds && Prefs.shared.playFileTransferCompleteSound {
+ SoundEffectPlayer.shared.playSoundEffect(.transferComplete)
+ }
+ }
+
+ if let i = self.downloads.firstIndex(where: { $0.referenceNumber == reference }) {
+ self.downloads.remove(at: i)
+ }
+ }
+
// MARK: - Utilities
func updateServerTitle() {
diff --git a/Hotline/Models/TransferInfo.swift b/Hotline/Models/TransferInfo.swift
index 8b8d97a..50b23f5 100644
--- a/Hotline/Models/TransferInfo.swift
+++ b/Hotline/Models/TransferInfo.swift
@@ -16,6 +16,7 @@ class TransferInfo: Identifiable, Equatable, Hashable {
var progressCallback: ((TransferInfo, Double) -> Void)? = nil
var downloadCallback: ((TransferInfo, URL) -> Void)? = nil
+ var uploadCallback: ((TransferInfo) -> Void)? = nil
var previewCallback: ((TransferInfo, Data) -> Void)? = nil
init(id: UInt32, title: String, size: UInt) {