PortKiller Documentation

repository·main·Indexed 26 days ago

https://github.com/productdevbook/port-killer

A cross-platform developer tool for monitoring and managing network ports, Kubernetes port-forwarding sessions, and Cloudflare Tunnels. It provides a native UI to discover listening TCP ports, terminate occupying processes (gracefully or via force kill), and manage tunnel connections. Available for Windows, macOS, and Linux, with core functionality provided by the portkiller-core library.

Tokens
6.6K
Snippets
18
Records
41
Agent score
90%

What's inside PortKiller

  1. Overview of PortKiller features

    main

    PortKiller is a cross-platform port management tool designed for developers. It provides capabilities for:

    • Port Management: Auto-discovery of listening TCP ports, one-click process termination (graceful and force kill), searching/filtering by port or process name, and smart categorization (Web Server, Database, Development, System).
    • Kubernetes Port Forwarding: Management of kubectl port-forward sessions with auto-reconnect, connection logs, and status notifications.
    • Cloudflare Tunnels: Viewing and managing active Cloudflare Tunnel connections.
    • Platform Integration: Menu bar integration on macOS and System tray integration on Windows.
  2. SwiftUI Patterns and State Management

    main

    State Management

    Use the @Observable macro for state objects. Do not use the legacy ObservableObject or @Published patterns.

    View Structure

    • Keep individual views focused and under 200 lines.
    • Extract complex views into separate, reusable components.
    • Use custom View Modifiers for repeated styling.

    Concurrency in UI

    • Mark UI-related types with @MainActor to ensure updates run on the main thread.
    • Use actors for thread-safe state management.
    • Mark types as Sendable when they cross concurrency boundaries.
    • Store Task references to allow for proper cancellation in deinit.
    // Modern @Observable State
    @Observable
    @MainActor
    final class AppState {
        var ports: [PortInfo] = []
        var isScanning = false
    }
    
    // Custom View Modifier
    struct CardStyle: ViewModifier {
        func body(content: Content) -> some View {
            content
                .padding()
                .background(Color.white)
                .cornerRadius(8)
        }
    }
    
    // Thread-safe Actor
    actor PortScanner {
        func scanPorts() async -> [PortInfo] { return [] }
    }
  3. Naming Conventions for Swift

    main

    Follow Apple's Swift API Design Guidelines with these specific project rules:

    • Types & Protocols: Use PascalCase (e.g., PortInfo, PortScanning). Avoid abbreviations.
    • Variables & Functions: Use camelCase. Boolean variables must read as assertions (e.g., isScanning, canCheckForUpdates).
    • Constants: Group related constants within enums using static let properties. Avoid UPPER_SNAKE_CASE.
    • Enums: Use lowercase for cases and omit prefixes if the context is clear (e.g., use .webServer instead of .ProcessTypeWebServer).
    // Good Types
    struct PortInfo { }
    
    // Good Variables/Functions
    var isScanning = false
    func killProcess(pid: Int) { }
    
    // Good Constants
    enum UIConstants {
        static let width: CGFloat = 340
    }
    
    // Good Enums
    enum ProcessType {
        case webServer
    }
  4. Build and Package PortKiller for Windows

    main

    For developers looking to build or distribute the Windows application:

    Build for Debugging

    dotnet build -c Debug

    Package for Distribution (Self-contained)

    To create a single-file, self-contained executable for win-x64:

    dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
    dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
  5. Use PortKiller for Port Management

    main

    PortKiller allows you to manage listening TCP ports through a WinUI 3 interface.

    Basic Operations

    • View All Ports: The app automatically scans and displays all listening TCP ports.
    • Kill a Process: Click the kill button next to any port to terminate the process using a two-stage approach (graceful shutdown followed by a force kill).
    • Search: Use the search box to filter by port number or process name.
    • Refresh: Click the refresh button or wait for the 5-second auto-refresh.

    Favorites and Watching

    • Favorites: Click on a port to view details, then click "Add to Favorites" to access it quickly from the sidebar.
    • Watched Ports: Select "Watch Port" on a specific port to receive notifications when that port starts or stops. Managed via the sidebar.
    • All Ports: View all listening ports.
    • Favorites: Quick access to favorite ports.
    • Watched: Monitored ports with notifications.
    • Process Types: Filter by Web Server, Database, Development, System, or Other.
    • Settings: Configure refresh interval and notifications.
  6. Swift Language Standards for PortKiller

    main

    The project requires Swift 6.0 and mandates the use of modern features like async/await, actors, and structured concurrency. Developers must enable strict concurrency checking and avoid legacy Objective-C patterns unless required for system API interfacing.

    Type Inference

    Use type inference for readability when the context is clear, but use explicit types for clarity when necessary (e.g., TimeInterval).

    Optionals

    • Prefer optional chaining and nil coalescing over if let blocks.
    • Use guard for early returns to avoid nested if statements.

    Error Handling

    • Use try? for non-critical operations where failure can be safely ignored.
    • Use do-catch blocks for critical operations that require error handling.
    // Good - type is clear from context
    let ports = scanner.scanPorts()
    
    // Good - explicit type adds clarity
    let timeout: TimeInterval = 5.0
    
    // Good - nil coalescing
    let name = port.processName ?? "Unknown"
    
    // Good - guard for early returns
    guard let port = selectedPort else { return }
    
    // Good - non-critical error handling
    try? await Task.sleep(for: .milliseconds(500))
  7. Install PortKiller for Windows

    main

    You can install PortKiller on Windows using one of the following methods:

    1. Go to the GitHub Releases page.
    2. Download the latest PortKiller-vX.X.X-windows-x64.zip (or arm64 for ARM devices).
    3. Extract the ZIP to a folder of your choice.
    4. Run PortKiller.exe.

    Note: You must have the .NET 9 Runtime installed.

    Option 2: Build from Source

    Clone the repository and use the .NET CLI:

    git clone https://github.com/productdevbook/port-killer.git
    cd port-killer/platforms/windows
    cd PortKiller
    dotnet restore
    dotnet build
    dotnet run
    git clone https://github.com/productdevbook/port-killer.git
    cd port-killer/platforms/windows
    cd PortKiller
    dotnet restore
    dotnet build
    dotnet run
  8. Organize and structure Swift tests

    main

    When writing tests for PortKiller in Swift, use descriptive names within the @Test macro and follow the Arrange-Act-Assert pattern to ensure clarity and maintainability.

    @Test("Port range filter excludes ports outside range")
    func portRangeFilter() {
        // Arrange
        var filter = PortFilter()
        filter.minPort = 3000
        filter.maxPort = 5000
    
        // Act
        let portInRange = createPort(port: 4000)
        let portOutOfRange = createPort(port: 6000)
    
        // Assert
        #expect(filter.matches(portInRange, favorites: [], watched: []))
        #expect(!filter.matches(portOutOfRange, favorites: [], watched: []))
    }
  9. Code Quality and Complexity Rules

    main

    To maintain high code quality, adhere to these constraints:

    • Line Length: Keep lines under 120 characters.
    • Function Length: Keep functions under 50 lines; extract complex logic into helpers.
    • Complexity: Avoid deep nesting; use early returns with guard instead.
    • Magic Numbers: Never use raw numbers in logic; define them as constants in an enum or struct.
    • DRY (Don't Repeat Yourself): Extract repeated object creation or logic into helper functions.
    // Good - Early returns to avoid nesting
    guard !line.isEmpty else { continue }
    guard let pid = Int(components[1]) else { continue }
    
    // Good - Avoiding magic numbers
    enum AppConstants {
        static let defaultRefreshInterval: Int = 5
    }
    let interval = AppConstants.defaultRefreshInterval
  10. File Organization and Documentation Standards

    main

    File Structure

    Organize files by feature/responsibility (e.g., Models/, Managers/, Services/, Views/).

    Documentation

    • Public APIs: Use JSDoc-style comments for all public functions, including @param and @returns descriptions.
    • Inline Comments: Use for explaining complex logic or critical execution orders (e.g., preventing deadlocks).
    • Property Documentation: Use /// for non-obvious properties.

    Code Organization

    Use // MARK: to group code within a file in the following order:

    1. Properties
    2. Initialization
    3. Public Methods
    4. Private Methods
    /**
     * Scans all listening TCP ports using lsof.
     *
     * @returns Array of PortInfo objects representing all listening ports
     */
    func scanPorts() async -> [PortInfo] { ... }
    
    // MARK: - Port Operations
    func refresh() async { ... }