The relay now answers a stateless ping with pong. The Relay card auto-checks on appear and address changes, showing latency or the connection error; this verifies the endpoint speaks the share protocol, not just that a TCP port is open.
92 lines
2.4 KiB
Swift
92 lines
2.4 KiB
Swift
import Foundation
|
|
|
|
/// Which side of the room the setup screen is preparing. Once a room is
|
|
/// running the distinction only changes labels: every peer can send and
|
|
/// receive, just like the CLI.
|
|
enum RoomMode: String, CaseIterable, Identifiable {
|
|
case send
|
|
case receive
|
|
|
|
var id: String { rawValue }
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .send: return "Send"
|
|
case .receive: return "Receive"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .send: return "arrow.up.circle.fill"
|
|
case .receive: return "arrow.down.circle.fill"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// One file's progress as reported by the Go engine. The JSON field names
|
|
/// match `swarm.FileStatus`; no conversion layer is needed.
|
|
struct FileProgress: Codable, Identifiable, Hashable {
|
|
let name: String
|
|
let size: Int64
|
|
let haveChunks: Int64
|
|
let totalChunks: Int64
|
|
let complete: Bool
|
|
|
|
var id: String { name }
|
|
|
|
var fraction: Double {
|
|
guard totalChunks > 0 else { return 0 }
|
|
return min(1, max(0, Double(haveChunks) / Double(totalChunks)))
|
|
}
|
|
|
|
var formattedSize: String {
|
|
ByteCountFormatter.string(fromByteCount: size, countStyle: .file)
|
|
}
|
|
}
|
|
|
|
/// The whole room snapshot decoded from `ShareSession.statusJSON()`. The
|
|
/// Go bridge keeps the same shape across launches so the UI never has to
|
|
/// know about gomobile objects beyond the session itself.
|
|
struct RoomStatus: Codable {
|
|
var code: String
|
|
var relay: String
|
|
var outDir: String
|
|
var running: Bool
|
|
var peers: Int
|
|
var files: [FileProgress]
|
|
var error: String?
|
|
|
|
var allComplete: Bool {
|
|
!files.isEmpty && files.allSatisfy(\.complete)
|
|
}
|
|
|
|
var receivedFiles: [FileProgress] {
|
|
files.filter(\.complete)
|
|
}
|
|
}
|
|
|
|
/// Result of the relay's stateless ping/pong probe. `ok` is true only when
|
|
/// the configured address accepted a connection and answered with pong,
|
|
/// not merely when the TCP port was open.
|
|
struct RelayCheck: Codable, Equatable {
|
|
let ok: Bool
|
|
let relay: String
|
|
let latencyMs: Int64
|
|
let error: String?
|
|
}
|
|
|
|
/// A file that has already been copied into the app's seed directory.
|
|
/// Holding the copied URL (rather than the security-scoped picker URL)
|
|
/// means the Go engine can keep reading it after the picker goes away.
|
|
struct PickedFile: Identifiable, Hashable {
|
|
let id = UUID()
|
|
let url: URL
|
|
let name: String
|
|
let size: Int64
|
|
|
|
var formattedSize: String {
|
|
ByteCountFormatter.string(fromByteCount: size, countStyle: .file)
|
|
}
|
|
}
|