paint-brush
Portails cryptés : comment nous avons créé une application Swift qui utilise Rustpar@ockam
10,763 lectures
10,763 lectures

Portails cryptés : comment nous avons créé une application Swift qui utilise Rust

par Ockam5m2024/01/01
Read on Terminal Reader

Trop long; Pour lire

Comment l'application Portals for Mac, construite dans Swift, utilise la bibliothèque Ockam Rust pour partager des services en privé avec vos amis via des portails cryptés de bout en bout.
featured image - Portails cryptés : comment nous avons créé une application Swift qui utilise Rust
Ockam HackerNoon profile picture
0-item
1-item

Portals est une application Mac intégrée à Swift. Il est open source et utilise la bibliothèque Ockam Rust pour partager en privé les services TCP ou HTTP de votre Mac avec vos amis via des portails Ockam cryptés de bout en bout. Un service partagé apparaît sur leur localhost !


Dans cet article, nous verrons comment l'application SwiftUI macOS interagit avec le code Rust.


Si vous êtes curieux d'essayer Portals pour Mac. Vous pouvez en savoir plus à ce sujet dans cet article et l'installer utilise Homebrew comme suit :


 brew install build-trust/ockam/portals


Voici une vidéo de 2 minutes de l'application en action :

Rapide <> Rouille

La fonctionnalité Portals était déjà implémentée dans la bibliothèque Ockam Rust. Nous avons décidé de créer une excellente expérience native macOS.


Notre première tentative de création de l'application consistait à utiliser Tauri. Cela était logique car nous voulions utiliser la bibliothèque Rust d'Ockam et la plupart des membres de notre équipe sont à l'aise pour créer des éléments dans Rust. Cette première version était facile à construire et possédait toutes les fonctions de base que nous souhaitions. Cependant, l’expérience d’utilisation de l’application n’était pas excellente. Tauri ne nous a donné qu'un contrôle minimal sur la façon dont le menu était rendu et sur ce qui se passait lorsqu'un utilisateur interagissait avec le menu. Cette version de l'application semblait appartenir à une version de macOS vieille de 10 ans par rapport aux éléments de la barre de menus très faciles à utiliser intégrés à macOS Sonoma.


Nous avons réalisé que pour bénéficier de l'expérience riche que nous souhaitons, nous devons créer l'application à l'aide de SwiftUI.


Malheureusement, nous n'avons pas pu trouver de solution prête à l'emploi pour intégrer Swift et Rust, qui nous offrirait le meilleur des deux mondes ; la sécurité de Rust et la riche expérience native macOS de SwiftUI. Après quelques recherches supplémentaires, nous avons réalisé que nous pouvions connecter les deux en utilisant le C-89. Rust est compatible avec la convention d'appel C et Swift est interopérable avec Objective-C, qui est un surensemble de C-89.


Comment Swift et Rust communiquent



Nous avons écrit les structures de données Rust qui devaient être visibles deux fois par Swift. Une version est idiomatique dans Rust et facile à utiliser. L'autre version est compatible C en utilisant des pointeurs et de la mémoire allouée manuellement avec malloc. Nous avons également exposé certaines API compatibles C qui utilisent des pointeurs bruts dans Rust non sécurisé pour convertir les structures de données idiomatiques vers leurs versions compatibles C. Enfin nous avons généré automatiquement un en-tête C à l'aide de la bibliothèque cbindgen.


Du côté de Swift, nous aurions pu appeler directement les API C, mais les structures de données C ne sont pas des citoyens de première classe dans Swift. Cela les rend plus difficiles à utiliser de manière idiomatique dans le code SwiftUI. Au lieu de cela, nous avons choisi de dupliquer les structures de données dans Swift et de les convertir entre C et Swift. Cela peut paraître fastidieux, mais en pratique, l’état partagé ne change pas très souvent. La possibilité de créer rapidement des composants dans SwiftUI en utilisant des constructions telles que if let ... , ForEach , enum etc. est très utile et vaut le compromis.


Voici un exemple de la même structure sous ses 4 formes :


 // 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 }


L'application Swift est liée statiquement à notre bibliothèque Rust au moment de la compilation. Le flux de données est simple : les interactions de l'interface utilisateur sont envoyées de Swift à Rust sous forme d'actions en appelant des API C, les événements de modification sont émis uniquement par Rust et Swift est averti à l'aide de rappels qui conduisent à des mises à jour de l'interface utilisateur.


La plupart du code dans les vues SwiftUI ressemble à n'importe quelle autre application SwiftUI.


 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") } } } ...


Si vous êtes curieux d'en savoir plus, consultez le code de la caisse ockam_app_lib et de l' application Portals dans Swift . Le Makefile dans le dossier Swift est également un bon endroit pour explorer comment tout est construit et lié entre eux.


Si vous souhaitez contribuer au code Swift ou Rust de Portals for Mac , nous ajoutons de nouveaux bons premiers numéros chaque semaine et aimons aider les nouveaux contributeurs. Rejoignez-nous sur le discord des contributeurs .


Apparaît également ici .