Files
TZGyn bf5d19900c Add a relay ping and backend status to the iOS app
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.
2026-10-27 21:59:27 +08:00

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)
}
}