paint-brush
Verschlüsselte Portale: Wie wir eine schnelle App erstellt haben, die Rust verwendetvon@ockam
10,773 Lesungen
10,773 Lesungen

Verschlüsselte Portale: Wie wir eine schnelle App erstellt haben, die Rust verwendet

von Ockam5m2024/01/01
Read on Terminal Reader

Zu lang; Lesen

Wie die in Swift erstellte Portals for Mac-App die Ockam Rust-Bibliothek nutzt, um Dienste privat über Ende-zu-Ende-verschlüsselte Portale mit Ihren Freunden zu teilen.
featured image - Verschlüsselte Portale: Wie wir eine schnelle App erstellt haben, die Rust verwendet
Ockam HackerNoon profile picture
0-item
1-item

Portals ist eine in Swift erstellte Mac -App. Es ist Open Source und nutzt die Ockam Rust-Bibliothek, um TCP- oder HTTP-Dienste von Ihrem Mac über Ende-zu-Ende-verschlüsselte Ockam-Portale privat mit Ihren Freunden zu teilen. Ein gemeinsamer Dienst erscheint auf ihrem lokalen Host !


In diesem Beitrag befassen wir uns mit der Interaktion der SwiftUI-MacOS-App mit Rust-Code.


Wenn Sie neugierig sind, probieren Sie Portals für Mac aus. In diesem Artikel erfahren Sie mehr darüber. Die Installation erfolgt mit Homebrew wie folgt:


 brew install build-trust/ockam/portals


Hier ist ein 2-minütiges Video der Anwendung in Aktion:

Swift <> Rost

Die Portals-Funktionalität wurde bereits in der Ockam Rust-Bibliothek implementiert. Unser Ziel war es, ein großartiges macOS-natives Erlebnis zu schaffen.


Unser erster Versuch, die App zu erstellen, war die Verwendung von Tauri. Das machte Sinn, da wir die Rust-Bibliothek von Ockam verwenden wollten und die meisten Leute in unserem Team sich damit auskennen, Dinge in Rust zu bauen. Diese erste Version war einfach zu erstellen und verfügte über alle Grundfunktionen, die wir wollten. Allerdings war die Erfahrung mit der App nicht besonders gut. Tauri gab uns nur minimale Kontrolle darüber, wie das Menü gerendert wurde und was passierte, wenn ein Benutzer mit dem Menü interagierte. Diese Version der App schien im Vergleich zu den supereinfach zu verwendenden Menüleistenelementen, die in macOS Sonoma integriert sind, zu einer 10 Jahre alten Version von macOS zu gehören.


Uns wurde klar, dass wir die App mit SwiftUI erstellen müssen, um die gewünschte umfassende Erfahrung zu erzielen.


Leider konnten wir keine Standardlösung für die Integration von Swift und Rust finden, die uns das Beste aus beiden Welten bieten würde; die Sicherheit von Rust und das reichhaltige macOS-native Erlebnis von SwiftUI. Nach einigem weiteren Graben wurde uns klar, dass wir die beiden über C-89 verbinden können. Rust ist mit der C-Aufrufkonvention kompatibel und Swift ist mit Objective-C, einer Obermenge von C-89, interoperabel.


Wie Swift und Rust kommunizieren



Wir haben die Rust-Datenstrukturen, die für Swift sichtbar sein mussten, zweimal geschrieben. Eine Version ist in Rust idiomatisch und einfach zu verwenden. Die andere Version ist C-kompatibel und verwendet Zeiger und Speicher, die manuell mit malloc zugewiesen werden. Wir haben auch einige C-kompatible APIs offengelegt, die Rohzeiger in unsicherem Rust verwenden, um die idiomatischen Datenstrukturen in ihre C-kompatiblen Versionen zu konvertieren. Schließlich haben wir mit Hilfe der cbindgen-Bibliothek automatisch einen C-Header generiert.


Auf der Swift-Seite hätten wir die C-APIs direkt aufrufen können, aber C-Datenstrukturen sind in Swift keine erstklassigen Bürger. Dies erschwert die idiomatische Verwendung im SwiftUI-Code. Stattdessen haben wir uns entschieden, die Datenstrukturen in Swift zu duplizieren und zwischen C und Swift zu konvertieren. Das mag mühsam erscheinen, aber in der Praxis ändert sich der gemeinsame Zustand nicht sehr oft. Die Möglichkeit, Komponenten in SwiftUI mithilfe von Konstrukten wie if let ... , ForEach , enum usw. schnell zu erstellen, ist äußerst hilfreich und den Kompromiss wert.


Hier ist ein Beispiel derselben Struktur in ihren 4 Formen:


 // Rust idiomatic structure #[derive(Default, Clone, Debug, Eq, PartialEq)] pub struct LocalService { pub name: String, pub address: String, pub port: u16, pub shared_with: Vec<Invitee>, pub available: bool, } // Rust C-compatible structure #[repr(C)] pub struct LocalService { pub(super) name: *const c_char, pub(super) address: *const c_char, pub(super) port: u16, pub(super) shared_with: *const *const Invitee, pub(super) available: u8, } // Generated C header structure typedef struct C_LocalService { const char *name; const char *address; uint16_t port; const struct C_Invitee *const *shared_with; uint8_t available; } C_LocalService; // Swift idiomatic structure class LocalService { let name: String @Published var address: String? @Published var port: UInt16 @Published var sharedWith: [Invitee] @Published var available: Bool }


Die Swift-App ist zur Kompilierungszeit statisch mit unserer Rust-Bibliothek verknüpft. Der Datenfluss ist einfach: UI-Interaktionen werden von Swift als Aktionen durch den Aufruf von C-APIs an Rust gesendet, Änderungsereignisse werden nur von Rust ausgegeben und Swift wird über Rückrufe benachrichtigt, die zu Aktualisierungen der UI führen.


Der meiste Code in den SwiftUI-Ansichten sieht genauso aus wie jede andere SwiftUI-Anwendung.


 VStack(alignment: .leading, spacing: 0) { Text(service.sourceName).lineLimit(1) HStack(spacing: 0) { Image(systemName: "circle.fill") .font(.system(size: 7)) .foregroundColor( service.enabled ? (service.available ? .green : .red) : .orange) if !service.enabled { Text(verbatim: "Not connected") } else { if service.available { Text(verbatim: service.address.unsafelyUnwrapped + ":" + String(service.port)) } else { Text(verbatim: "Connecting") } } } ...


Wenn Sie mehr erfahren möchten, schauen Sie sich den Code für die Kiste ockam_app_lib und die Portals- App in Swift an. Das Makefile im Swift-Ordner ist auch ein guter Ort, um zu erkunden, wie alles aufgebaut und miteinander verknüpft ist.


Wenn Sie daran interessiert sind, zum Swift- oder Rust-Code von Portals for Mac beizutragen, fügen wir jede Woche neue gute Erstausgaben hinzu und helfen gerne neuen Mitwirkenden. Treten Sie uns im Mitwirkenden-Discord bei.


Erscheint auch hier .