Swift bindings#191
Open
panfilov-vladislav wants to merge 23 commits into
Open
Conversation
- utils/bindgen: add swift.rs backend and Language::Swift subcommand - bindings/swift: commit generated Api.swift (2513 lines, 121 methods) - utils: add generate-swift-api.sh convenience script Run utils/generate-swift-api.sh to regenerate Api.swift after API changes.
…b targets OuisyncLibCore (Sources/) contains only the generated Api.swift and has no dependency on the xcframework. OuisyncLib (SourcesFFI/) wraps the FFI layer and depends on OuisyncLibCore. Tests now build against OuisyncLibCore.
- swift.rs: generate encodeToMsgPack/decodeFromMsgPack on all API types (simple enums, structs, complex enums, Request, Response); fix array wrapping for single named-field enum variants - Client.swift: TCP actor with NWConnection, HMAC-SHA256 auth, frame encode/decode, CheckedContinuation pending map, cancellation support - StateMonitor.swift: MonitorId (string-encoded) and StateMonitorNode - Session.swift: Session.create(configPath:) convenience initializer - generate-swift-api.sh: suppress cargo build output on stdout
Remove OuisyncClient, OuisyncError, OuisyncFile, OuisyncEntry, OuisyncRepository, OuisyncMessage, OuisyncLib, and OuisyncSession — all superseded by generated Api.swift types and the new Client actor. Extract NotificationStream into Sources/ since it has no FFI deps. OuisyncFFI.swift is kept as a stub pending step 5.
- build.sh: build ouisync-service instead of ouisync-ffi; link libouisync_service.a; run cbindgen with service/cbindgen.toml - service/cbindgen.toml: new cbindgen config; enum style="type" so ErrorCode is exported as typedef uint16_t (clean UInt16 in Swift) - OuisyncFFI.swift: replace dead FFI symbols with async OuisyncService wrapper around start_service / stop_service / init_log
- Session.swift: add public close() that cancels the underlying client - Package.swift: test target now depends on OuisyncLib (needs xcframework) - OuisyncLibTests.swift: integration tests — start OuisyncService, connect Session, exercise repository list/create/delete and file write/read/truncate
- Fix swift.rs: compare handle.value (UInt64) instead of handle struct (which lacks Equatable conformance) in generated == operators - Fix swift.rs: Request enum named fields use unlabeled call syntax (prefix _ ) so Swift 6 callers don't need argument labels - Fix swift.rs: Type::Bytes encodes as .binary(expr) not .binary([UInt8](expr)) - Regenerate Api.swift with the above fixes - Fix Client.swift: qualify withUnsafeBytes as Swift.withUnsafeBytes to resolve Swift 6 ambiguity with Data's instance method - Fix Client.swift: remove extraneous 'id:' label on .cancel() call site - Fix OuisyncFFI.swift: @_exported import OuisyncLibCore so Session, OuisyncError etc. are visible to OuisyncLib consumers; qualify OuisyncLibCore types to avoid clash with C ErrorCode from OuisyncLibFFI; use resume(with:) instead of resumeWith (correct CheckedContinuation API) - Fix service/cbindgen.toml: remove invalid [enum] section - Fix Package.swift: link SystemConfiguration framework (required by libouisync_service.a via the system_configuration crate) - Fix Tests: add missing 'import Foundation' for FileManager, Data, UUID - Add build-xcframework-macos.sh for native macOS host builds - All 8 integration tests now pass with swift test
Documents the architecture, build pipeline, code generation workflow, and library usage with examples.
Pins MessagePack.swift at 4.0.0 for reproducible builds.
… exists The guard in builder.swift required the "Update rust dependencies" output directory to exist before any build. This worked fine within the OuisyncLib package itself, but broke any external package that depended on OuisyncLib (or OuisyncLibCore) — the output directory lives in OuisyncLib's own .build tree, not in the downstream package's .build tree. Fix: also pass the guard when the pre-built xcframework is already present at output/OuisyncLibFFI.xcframework. Since SKIP=1 in config.sh the build script exits immediately anyway; the only thing that needs to exist is the xcframework artifact. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add a Known limitations entry explaining why Repository.subscribe() and Session.subscribeToNetwork() are absent: the current Client resolves a single CheckedContinuation per message ID, so streaming responses are silently dropped after the first. NotificationStream.swift is already scaffolded; a channels map in the receive loop and two manual extension functions (mirroring the Kotlin implementation) are what's needed to complete it. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Mirrors the structure of bindings/kotlin/example. The app starts the Ouisync service, opens a session, and presents three screens: - RepositoryListView — create / delete repositories; copy a write-access share token to the clipboard via the share button - FolderView — browse directory contents recursively; create files and directories with the + button - FileView — show file size and SHA-256; write UTF-8 text content via the pencil button; poll sync progress (subscribe() pending) Because swift run launches the process as a command-line tool (no keyboard focus), a run.sh script builds the binary, wraps it in a minimal .app bundle, and opens it with open(1). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- fs_util/Cargo.toml: add ios to the libc target cfg so the crate links correctly when cross-compiling for iOS targets - fs_util/src/safe_move.rs: extend blocking_rename_no_replace_atomic cfg to any(macos, ios) — renamex_np has been available on iOS 10+ - service/src/logger/mod.rs: route ios through stdout.rs, resolving the pre-existing TODO comment
Replaces the macOS-only script with one that reads all targets from config.sh, builds natively with cargo (no Docker), combines simulator slices with lipo, and produces a single xcframework containing macOS, iOS device, and iOS simulator slices. OVERVIEW.md updated: prerequisites now include the rustup target add one-liner for iOS toolchains, the build section documents both scripts, and the iOS limitation bullet is removed from Known Limitations.
Replaces the macOS-only SPM package with a single Xcode project targeting macOS 14+ and iOS 17+ from one shared codebase. Platform differences are isolated to #if os(macOS) in four spots. Notable changes: - ShareLink with ouisync:// scheme (converted from the API's https://ouisync.net/... token) so AirDrop works natively on both platforms - Incoming ouisync:// links registered in Info.plist open the app and pre-fill the Create Repository sheet with the token and suggested name - ouisync:// <-> https://ouisync.net/ conversion at share/receive time keeps custom scheme handling simple without Universal Links
Display the first 16 chars of each repository's info hash as a subtitle in the repo list, and log the full hash on startup. This makes it easy to verify that two devices share the same repository token when debugging sync issues. Also fix repo display names to show only the filename without the store path and .ouisyncdb extension.
The ouisync service does not persist the sync-enabled flag, so repos loaded from the store directory on startup come up with sync disabled. Call setSyncEnabled(true) on each repo after listRepositories() so syncing resumes every session without requiring explicit user action.
…ifications Client.swift gains a subscriptions registry (UInt64 → AsyncStream.Continuation) alongside the existing pending map. A new subscribe() method sends the request, waits for the server ack via the normal pending path, then returns an AsyncStream<Response> that receives all subsequent server-pushed events for that message ID. Cancellation sends Request.cancel to the server; connection drop finishes all active streams. swift.rs is updated to generate AsyncStream<T> methods for #[api(stream(T))] variants instead of skipping them. The generated wrapper filters response cases and hooks onTermination to cancel the inner forwarding task. Regenerated Api.swift exposes four new public methods: Repository.subscribe() -> AsyncStream<Void> Session.subscribeToNetwork() -> AsyncStream<NetworkEvent> Session.subscribeToStateMonitor(_:) -> AsyncStream<Void> Session.dhtLookup(_:_:) -> AsyncStream<String> NotificationStream.swift is deleted; it was never wired up and is superseded by the subscriptions map in Client.
Subscribe to repository change notifications in FolderView so synced files appear automatically without requiring a manual refresh.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds complete Swift bindings for ouisync, including a code-generated
API layer, build tooling, and a working example app for macOS and iOS.
What's included
Codegen
Auto-generates the full Swift API (
Api.swift) from the Rust servicedefinitions, covering all request/response types, error codes, and
repository/session/file operations, including
AsyncStream<T>methodsfor streaming/subscription endpoints.
Library
Client.swift: async/await IPC over TCP with HMAC auth, withstreaming subscription support and cancellation
StateMonitor.swift: hierarchical state monitoringOuisyncLibSwift package withOuisyncLibCore+OuisyncLibtargetsbuild-xcframework.sh: builds a universal XCFramework for macOS + iOS(device and simulator)
FFIBuilderSPM plugin that invokes the xcframework build as part ofthe Swift package build
Integration tests
Full integration test suite using Swift Testing, exercising repository
create/open/sync/share flows against a live service instance.
Example app
Multi-platform SwiftUI app (macOS + iOS) demonstrating: