paint-brush
Зашифрованные порталы: как мы создали Swift-приложение, использующее Rust к@ockam
10,751 чтения
10,751 чтения

Зашифрованные порталы: как мы создали Swift-приложение, использующее Rust

к Ockam5m2024/01/01
Read on Terminal Reader

Слишком долго; Читать

Как приложение Portals для Mac, созданное на Swift, использует библиотеку Ockam Rust для конфиденциального обмена услугами с вашими друзьями через порталы со сквозным шифрованием.
featured image - Зашифрованные порталы: как мы создали Swift-приложение, использующее Rust
Ockam HackerNoon profile picture
0-item
1-item

, созданное на Swift. Он имеет открытый исходный код и использует библиотеку Rust для конфиденциального обмена службами TCP или HTTP с вашего Mac с друзьями через порталы Ockam со сквозным шифрованием. На их локальном хосте появляется общий сервис!


В этом посте мы рассмотрим, как приложение SwiftUI для macOS взаимодействует с кодом Rust.


Если вам интересно попробовать Portals для Mac. Вы можете узнать больше об этом , а установить его с помощью Homebrew можно следующим образом:


 brew install build-trust/ockam/portals


Вот двухминутное видео применения приложения в действии:

Свифт <> Ржавчина

Функционал «Порталы» уже реализован в библиотеке Okam Rust. Мы намеревались создать отличный интерфейс для macOS.


Наша первая попытка создания приложения была с использованием Tauri. Это имело смысл, поскольку мы хотели использовать библиотеку ржавчины Ockam, и большинству людей в нашей команде комфортно создавать вещи на Rust. Эту первую версию было легко собрать, и она содержала все необходимые нам базовые функции. Однако опыт использования приложения был не очень хорошим. Tauri дал нам лишь минимальный контроль над тем, как отображается меню и что происходит, когда пользователь взаимодействует с меню. Эта версия приложения выглядела так, как будто она принадлежала 10-летней версии macOS, по сравнению с очень простыми в использовании элементами меню, встроенными в macOS Sonoma.


Мы поняли, что для того, чтобы получить желаемый богатый опыт, мы должны создать приложение с использованием SwiftUI.


К сожалению, мы не смогли найти готовое решение для интеграции Swift и Rust, которое дало бы нам лучшее из обоих миров; безопасность Rust и богатый опыт SwiftUI, родной для macOS. Еще немного покопавшись, мы поняли, что можем соединить их с помощью C-89. Rust совместим с соглашением о вызовах C, а Swift совместим с Objective-C, который является расширенным набором C-89.


Как общаются Swift и Rust



Мы написали структуры данных Rust, которые должны были быть видны Swift дважды. Одна версия идиоматична для Rust и проста в использовании. Другая версия совместима с C и использует указатели и память, выделяемую вручную с помощью malloc. Мы также представили некоторые C-совместимые API, которые используют необработанные указатели в unsafe Rust для преобразования идиоматических структур данных в их C-совместимые версии. Наконец, мы автоматически сгенерировали заголовок C с помощью библиотеки cbindgen.


Что касается Swift, мы могли бы напрямую вызывать API C, но структуры данных C не являются первоклассными элементами в Swift. Это усложняет их идиоматическое использование в коде SwiftUI. Вместо этого мы решили дублировать структуры данных в Swift и конвертировать их между C и Swift. Это может показаться обременительным, но на практике общее состояние меняется не так уж и часто. Возможность быстро создавать компоненты в SwiftUI с использованием таких конструкций, как if let ... , ForEach , enum и т. д., очень полезна и стоит того.


Вот пример той же структуры в четырех ее формах:


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


Приложение Swift статически связано с нашей библиотекой Rust во время компиляции. Поток данных прост: взаимодействия пользовательского интерфейса передаются из Swift в Rust как действия путем вызова C API, события изменений отправляются только Rust, а Swift уведомляется с помощью обратных вызовов, которые приводят к обновлениям пользовательского интерфейса.


Большая часть кода в представлениях SwiftUI выглядит так же, как и любое другое приложение 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") } } } ...


Если вам интересно узнать больше, ознакомьтесь с кодом крейта и . в папке Swift также является хорошим местом для изучения того, как все создается и связывается вместе.


Если вы заинтересованы в том, чтобы внести свой вклад в код Swift или Rust для , мы добавляем новые каждую неделю и любим помогать новым участникам. Присоединяйтесь к нам в .


Также появляется .


바카라사이트 바카라사이트 온라인바카라