vibetunnel/ios/VibeTunnel/Models/Session.swift
2025-06-23 14:58:11 +02:00

164 lines
4.8 KiB
Swift

import Foundation
/// Represents a terminal session on the server.
///
/// Session contains all information about a running or completed
/// terminal session, including its status, process information,
/// and terminal dimensions.
struct Session: Codable, Identifiable, Equatable, Hashable {
let id: String
let command: [String] // Changed from String to [String] to match server
let workingDir: String
let name: String?
let status: SessionStatus
let exitCode: Int?
let startedAt: String
let lastModified: String?
let pid: Int?
// Terminal dimensions
let width: Int?
let height: Int?
let waiting: Bool?
// Optional fields from HQ mode
let source: String?
let remoteId: String?
let remoteName: String?
let remoteUrl: String?
enum CodingKeys: String, CodingKey {
case id
case command
case workingDir
case name
case status
case exitCode
case startedAt
case lastModified
case pid
case width
case height
case waiting
case source
case remoteId
case remoteName
case remoteUrl
}
/// User-friendly display name for the session.
///
/// Returns the custom name if not empty, otherwise the command.
var displayName: String {
if let name, !name.isEmpty {
return name
}
return command.joined(separator: " ")
}
/// Indicates whether the session is currently active.
///
/// - Returns: true if the session status is `.running`.
var isRunning: Bool {
status == .running
}
/// Formats the session start time for display.
///
/// - Returns: A localized time string or the raw timestamp if parsing fails.
///
/// Attempts to parse various date formats including ISO8601
/// and RFC3339 with or without fractional seconds.
var formattedStartTime: String {
// Parse and format the startedAt string
// Try ISO8601 first
let iso8601Formatter = ISO8601DateFormatter()
if let date = iso8601Formatter.date(from: startedAt) {
let displayFormatter = DateFormatter()
displayFormatter.dateStyle = .none
displayFormatter.timeStyle = .short
return displayFormatter.string(from: date)
}
// Try RFC3339 format (what Go uses)
let rfc3339Formatter = DateFormatter()
rfc3339Formatter.locale = Locale(identifier: "en_US_POSIX")
rfc3339Formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
if let date = rfc3339Formatter.date(from: startedAt) {
let displayFormatter = DateFormatter()
displayFormatter.dateStyle = .none
displayFormatter.timeStyle = .short
return displayFormatter.string(from: date)
}
// Try without fractional seconds
rfc3339Formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
if let date = rfc3339Formatter.date(from: startedAt) {
let displayFormatter = DateFormatter()
displayFormatter.dateStyle = .none
displayFormatter.timeStyle = .short
return displayFormatter.string(from: date)
}
return startedAt
}
}
/// Represents the lifecycle state of a session.
enum SessionStatus: String, Codable {
/// Session is being initialized.
case starting
/// Session is active and running.
case running
/// Session has terminated.
case exited
}
/// Data required to create a new terminal session.
///
/// SessionCreateData encapsulates all parameters needed
/// to start a new terminal session on the server.
struct SessionCreateData: Codable {
let command: [String]
let workingDir: String
let name: String?
let spawnTerminal: Bool?
let cols: Int?
let rows: Int?
enum CodingKeys: String, CodingKey {
case command
case workingDir
case name
case spawnTerminal = "spawn_terminal"
case cols
case rows
}
/// Creates session creation data with sensible defaults.
///
/// - Parameters:
/// - command: Command to execute (default: "zsh").
/// - workingDir: Working directory for the session.
/// - name: Optional custom name.
/// - spawnTerminal: Whether to spawn a terminal (default: true).
/// - cols: Terminal width in columns (default: 120).
/// - rows: Terminal height in rows (default: 30).
init(
command: String = "zsh",
workingDir: String,
name: String? = nil,
spawnTerminal: Bool = true,
cols: Int = 120,
rows: Int = 30
) {
self.command = [command]
self.workingDir = workingDir
self.name = name
self.spawnTerminal = spawnTerminal
self.cols = cols
self.rows = rows
}
}