mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-25 14:57:37 +00:00
add docs
This commit is contained in:
parent
5d6d630c61
commit
411b79832d
10 changed files with 110 additions and 12 deletions
|
|
@ -4,7 +4,12 @@ import Hummingbird
|
|||
import HummingbirdCore
|
||||
import NIOCore
|
||||
|
||||
/// Middleware that implements HTTP Basic Authentication
|
||||
/// Middleware that implements HTTP Basic Authentication.
|
||||
///
|
||||
/// Provides password-based access control for the VibeTunnel dashboard.
|
||||
/// Validates incoming requests against a configured password using
|
||||
/// standard HTTP Basic Authentication. Exempts health check endpoints
|
||||
/// from authentication requirements.
|
||||
struct BasicAuthMiddleware<Context: RequestContext>: RouterMiddleware {
|
||||
let password: String
|
||||
let realm: String
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
import Foundation
|
||||
import Logging
|
||||
|
||||
/// Generates Asciinema cast v2 format files from terminal session output
|
||||
/// Generates Asciinema cast v2 format files from terminal session output.
|
||||
///
|
||||
/// Creates recordings of terminal sessions in the Asciinema cast format,
|
||||
/// which can be played back using Asciinema players. Handles timing information,
|
||||
/// terminal dimensions, and output/input event recording.
|
||||
///
|
||||
/// Format specification: https://docs.asciinema.org/manual/asciicast/v2/
|
||||
struct CastFileGenerator {
|
||||
private let logger = Logger(label: "VibeTunnel.CastFileGenerator")
|
||||
|
||||
/// Header structure for Asciinema cast v2 format.
|
||||
///
|
||||
/// Contains metadata about the terminal recording including
|
||||
/// dimensions, timing, and environment information.
|
||||
struct CastHeader: Codable {
|
||||
let version: Int = 2
|
||||
let width: Int
|
||||
|
|
@ -30,6 +39,9 @@ struct CastFileGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a single event in the Asciinema recording.
|
||||
///
|
||||
/// Each event captures either terminal output or input at a specific timestamp.
|
||||
struct CastEvent {
|
||||
let time: TimeInterval
|
||||
let eventType: String
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ import Foundation
|
|||
import os
|
||||
import Security
|
||||
|
||||
/// Service for managing dashboard password in keychain
|
||||
/// Service for managing dashboard password in keychain.
|
||||
///
|
||||
/// Provides secure storage and retrieval of the dashboard authentication
|
||||
/// password using the macOS Keychain. Handles password generation,
|
||||
/// updates, and deletion with proper error handling and logging.
|
||||
@MainActor
|
||||
final class DashboardKeychain {
|
||||
static let shared = DashboardKeychain()
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
import Foundation
|
||||
import HTTPTypes
|
||||
|
||||
/// Protocol for HTTP client abstraction to enable testing
|
||||
/// Protocol for HTTP client abstraction to enable testing.
|
||||
///
|
||||
/// Defines the interface for making HTTP requests, allowing for
|
||||
/// easy mocking and testing of network-dependent code.
|
||||
public protocol HTTPClientProtocol {
|
||||
func data(for request: HTTPRequest, body: Data?) async throws -> (Data, HTTPResponse)
|
||||
}
|
||||
|
||||
/// Real HTTP client implementation
|
||||
/// Real HTTP client implementation.
|
||||
///
|
||||
/// Concrete implementation of HTTPClientProtocol using URLSession
|
||||
/// for actual network requests. Converts between HTTPTypes and
|
||||
/// Foundation's URLRequest/URLResponse types.
|
||||
public final class HTTPClient: HTTPClientProtocol {
|
||||
private let session: URLSession
|
||||
|
||||
|
|
@ -29,6 +36,7 @@ public final class HTTPClient: HTTPClientProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur during HTTP client operations.
|
||||
enum HTTPClientError: Error {
|
||||
case invalidResponse
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class ServerManager {
|
|||
private(set) var currentServer: ServerProtocol?
|
||||
private(set) var isRunning = false
|
||||
private(set) var isSwitching = false
|
||||
private(set) var isRestarting = false
|
||||
private(set) var lastError: Error?
|
||||
|
||||
private let logger = Logger(subsystem: "com.steipete.VibeTunnel", category: "ServerManager")
|
||||
|
|
@ -193,11 +194,25 @@ class ServerManager {
|
|||
))
|
||||
|
||||
// Update ServerMonitor for compatibility
|
||||
ServerMonitor.shared.isServerRunning = false
|
||||
// Only set to false if we're not in the middle of a restart
|
||||
if !isRestarting {
|
||||
ServerMonitor.shared.isServerRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
/// Restart the current server
|
||||
func restart() async {
|
||||
// Set restarting flag to prevent UI from showing "stopped" state
|
||||
isRestarting = true
|
||||
defer { isRestarting = false }
|
||||
|
||||
// Log that we're restarting
|
||||
logSubject.send(ServerLogEntry(
|
||||
level: .info,
|
||||
message: "Restarting server...",
|
||||
source: serverMode
|
||||
))
|
||||
|
||||
await stop()
|
||||
await start()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,9 @@ public final class ServerMonitor {
|
|||
|
||||
/// Syncs state with ServerManager
|
||||
private func syncWithServerManager() async {
|
||||
isServerRunning = ServerManager.shared.isRunning
|
||||
// Consider the server as running if it's actually running OR if it's restarting
|
||||
// This prevents the UI from showing "stopped" during restart
|
||||
isServerRunning = ServerManager.shared.isRunning || ServerManager.shared.isRestarting
|
||||
}
|
||||
|
||||
/// Starts the server if not already running
|
||||
|
|
@ -68,7 +70,9 @@ public final class ServerMonitor {
|
|||
|
||||
/// Restarts the server
|
||||
public func restartServer() async throws {
|
||||
// During restart, we maintain the running state to prevent UI flicker
|
||||
await ServerManager.shared.restart()
|
||||
// Sync after restart completes
|
||||
await syncWithServerManager()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import os.log
|
|||
import Sparkle
|
||||
import UserNotifications
|
||||
|
||||
/// SparkleUpdaterManager with automatic update downloads enabled
|
||||
/// SparkleUpdaterManager with automatic update downloads enabled.
|
||||
///
|
||||
/// Manages application updates using the Sparkle framework. Handles automatic
|
||||
/// update checking, downloading, and installation while respecting user preferences
|
||||
/// and update channels. Integrates with macOS notifications for update announcements.
|
||||
@available(macOS 10.15, *)
|
||||
@MainActor
|
||||
public final class SparkleUpdaterManager: NSObject, SPUUpdaterDelegate {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
|
||||
/// Manages interactions with the tty-fwd command-line tool
|
||||
/// Manages interactions with the tty-fwd command-line tool.
|
||||
///
|
||||
/// Provides a high-level interface for executing the bundled tty-fwd
|
||||
/// binary, handling process management, error conditions, and ensuring
|
||||
/// proper executable permissions. Used for terminal multiplexing operations.
|
||||
@MainActor
|
||||
final class TTYForwardManager {
|
||||
static let shared = TTYForwardManager()
|
||||
|
|
@ -101,7 +105,10 @@ final class TTYForwardManager {
|
|||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur when working with the tty-fwd binary
|
||||
/// Errors that can occur when working with the tty-fwd binary.
|
||||
///
|
||||
/// Represents failures specific to tty-fwd execution including
|
||||
/// missing executable, permission issues, and runtime failures.
|
||||
enum TTYForwardError: LocalizedError {
|
||||
case executableNotFound
|
||||
case notExecutable
|
||||
|
|
|
|||
|
|
@ -2,14 +2,21 @@ import Combine
|
|||
import Foundation
|
||||
import Logging
|
||||
|
||||
/// Holds pipes for a terminal session
|
||||
/// Holds pipes for a terminal session.
|
||||
///
|
||||
/// Encapsulates the standard I/O pipes used for communicating
|
||||
/// with a terminal process.
|
||||
private struct SessionPipes {
|
||||
let stdin: Pipe
|
||||
let stdout: Pipe
|
||||
let stderr: Pipe
|
||||
}
|
||||
|
||||
/// Manages terminal sessions and command execution
|
||||
/// Manages terminal sessions and command execution.
|
||||
///
|
||||
/// An actor that handles the lifecycle of terminal sessions, including
|
||||
/// process creation, I/O handling, and command execution. Provides
|
||||
/// thread-safe management of multiple concurrent terminal sessions.
|
||||
actor TerminalManager {
|
||||
private var sessions: [UUID: TunnelSession] = [:]
|
||||
private var processes: [UUID: Process] = [:]
|
||||
|
|
|
|||
32
VibeTunnel/Presentation/Views/SharedComponents.swift
Normal file
32
VibeTunnel/Presentation/Views/SharedComponents.swift
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: - Credit Link Component
|
||||
|
||||
/// Credit link component for individual contributors.
|
||||
///
|
||||
/// This component displays a contributor's handle as a clickable link
|
||||
/// that opens their website when clicked.
|
||||
struct CreditLink: View {
|
||||
let name: String
|
||||
let url: String
|
||||
@State private var isHovering = false
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
if let linkURL = URL(string: url) {
|
||||
NSWorkspace.shared.open(linkURL)
|
||||
}
|
||||
}, label: {
|
||||
Text(name)
|
||||
.font(.caption)
|
||||
.underline(isHovering, color: .accentColor)
|
||||
})
|
||||
.buttonStyle(.link)
|
||||
.pointingHandCursor()
|
||||
.onHover { hovering in
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
isHovering = hovering
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue