Skip to main content

Overview

SeeleSeek is a native macOS SwiftUI application written in Swift 6. The codebase is organized around three main concerns:
  • App-level state — a single AppState object injected via SwiftUI environment that owns all feature states and the network client.
  • Networking — a layered stack (server connection → peer connections → protocol parsing) coordinated by NetworkClient.
  • Features — self-contained modules under Features/, each with observable state and a Views/ subdirectory.
All UI runs on the main actor. Network I/O uses Swift actors (ServerConnection, PeerConnection, DatabaseManager) to isolate mutable state.

Directory Structure

seeleseek/
├── seeleseekApp.swift          # App entry point, scene setup, menu commands
├── App/                        # AppState and global environment key
├── Core/
│   ├── Network/
│   │   ├── NetworkClient.swift         # Central coordinator
│   │   ├── Connections/
│   │   │   ├── ServerConnection.swift  # TCP connection to slsknet.org
│   │   │   ├── PeerConnection.swift    # Single peer TCP connection
│   │   │   └── PeerConnectionPool.swift
│   │   ├── Protocol/
│   │   │   ├── MessageCode.swift       # Enum of all message codes
│   │   │   ├── MessageBuilder.swift    # Serialize outgoing messages
│   │   │   └── MessageParser.swift     # Deserialize incoming frames
│   │   ├── Handlers/
│   │   │   └── ServerMessageHandler.swift
│   │   └── Services/
│   ├── Models/                 # Shared value types (SearchResult, SharedFile, etc.)
│   ├── Services/               # Share manager, listener, NAT, metadata
│   ├── Storage/                # User info cache
│   └── Utilities/
├── Database/
│   └── DatabaseManager.swift   # Actor-based GRDB coordinator + migrations
├── Features/
│   ├── Search/
│   ├── Transfers/
│   ├── Browse/
│   ├── Chat/
│   ├── Social/
│   ├── Wishlist/
│   ├── Settings/
│   ├── Statistics/
│   ├── Connection/
│   ├── Console/
│   ├── MenuBar/
│   ├── Metadata/
│   └── Update/
├── DesignSystem/               # Shared UI components and SeeleColors
├── Navigation/                 # Sidebar definition and MainView
├── Intents/                    # App Intents / Shortcuts support
└── Preview/                    # SwiftUI preview helpers

App Entry Point

SeeleSeekApp creates a single AppState instance at launch, registers it with AppDependencyManager (for App Intents), and injects it into the view hierarchy via a custom environment key.
@main
struct SeeleSeekApp: App {
    @State private var appState: AppState

    init() {
        let state = AppState()
        _appState = State(initialValue: state)
        AppDependencyManager.shared.add(dependency: state)
    }

    var body: some Scene {
        WindowGroup {
            MainView()
                .environment(\.appState, appState)
                .task { appState.configure() }
        }
    }
}
appState.configure() wires up the NetworkClient callbacks to all feature states and initializes the database.

State Management

SeeleSeek uses Swift 6 @Observable classes throughout, replacing ObservableObject/@Published.

@Observable classes

Feature states (e.g. SearchState, TransferState) are @Observable classes marked @MainActor. SwiftUI tracks property reads automatically without @Published.

@MainActor for UI

All state that drives UI is isolated to @MainActor. Updates from background actors are dispatched with await MainActor.run { } or by calling @MainActor-isolated methods.
NetworkClient itself is @Observable @MainActor. Its properties (connection status, distributed network info) can be read directly in SwiftUI views.

Networking Layer

NetworkClient

NetworkClient (Core/Network/NetworkClient.swift) is the central coordinator. It owns:
  • A ServerConnection for the Soulseek server TCP socket.
  • A PeerConnectionPool managing all active peer connections.
  • A ServerMessageHandler that dispatches parsed server messages to callbacks.
Feature states register callbacks on NetworkClient during appState.configure(). For example, SearchState sets networkClient.onSearchResults to receive incoming search results.
AppState.configure()
    └── SearchState  →  networkClient.onSearchResults  = { ... }
    └── TransferState → networkClient.onFileTransferConnection = { ... }
    └── ChatState    →  networkClient.onRoomMessage    = { ... }
    └── ...

ServerConnection

An actor (Core/Network/Connections/ServerConnection.swift) wrapping NWConnection to the Soulseek server (server.slsknet.org:2242). It:
  • Buffers incoming TCP bytes and yields complete framed messages to an AsyncStream<Data>.
  • Enables TCP keepalive (probe every 60 s, give up after 3 missed probes) to detect silent connection loss.
  • Implements exponential backoff reconnect (5 s → 10 s → 30 s → 60 s cap) in NetworkClient.

PeerConnection and PeerConnectionPool

PeerConnection (Core/Network/Connections/PeerConnection.swift) is an actor managing a single peer TCP socket. It handles:
  • Connection types: P (peer messages), F (file transfer), D (distributed network).
  • Incoming and outgoing handshake (PeerInit / PierceFirewall).
  • Per-token TransferRequest handlers to support concurrent downloads on a single connection.
  • SeeleSeek-extension messages (codes 10000+) for capability handshake and album artwork requests.
PeerConnectionPool tracks all active PeerConnection instances and routes incoming events up to NetworkClient callbacks.

Protocol Layer

FileResponsibility
MessageCode.swiftEnums for server (ServerMessageCode), peer (PeerMessageCode), distributed (DistributedMessageCode), and SeeleSeek-extension (SeeleSeekPeerCode) message codes
MessageBuilder.swiftStatic methods that serialize each message type into Data with the correct length-prefixed framing
MessageParser.swiftParses framed Data into typed message structs

Database Layer

DatabaseManager (Database/DatabaseManager.swift) is a singleton actor backed by a GRDB DatabasePool in WAL mode. It runs versioned migrations and exposes generic read / write methods. Feature-specific repositories (e.g. TransferRepository, SearchRepository) call through DatabaseManager. Schema migrations:
VersionTables added
v1transfers, search_queries, search_results, user_shares, shared_files, settings, transfer_history
v2buddies, my_interests, my_profile
v3blocked_users
v4private_messages
v5wishlists
v6sampleRate, bitDepth columns on search_results; localPath on transfer_history
The SQLite file lives at ~/Library/Application Support/SeeleSeek/seeleseek.sqlite.

Feature Pattern

Each feature module follows a consistent structure:
Features/Search/
├── SearchState.swift       # @Observable @MainActor class
└── Views/
    ├── SearchView.swift
    ├── SearchResultsView.swift
    └── ...
*State.swift holds all mutable state for the feature and exposes methods that are called from both the UI (button taps) and NetworkClient callbacks (incoming network events). Views read state via the environment and call methods on the state object. Navigation/ defines the sidebar item enum (.search, .transfers, .browse, etc.) and MainView, which switches the content area based on appState.sidebarSelection. The app uses a hidden title bar (windowStyle(.hiddenTitleBar)) with a default window size of 1200×800.

Design System

DesignSystem/ provides shared SwiftUI components and SeeleColors (including the accent color applied app-wide in seeleseekApp.swift).