Skip to content

Commit

Permalink
implemented Tesseract client side
Browse files Browse the repository at this point in the history
  • Loading branch information
ypopovych committed Nov 21, 2023
1 parent c1c4220 commit ed252e3
Show file tree
Hide file tree
Showing 38 changed files with 810 additions and 196 deletions.
19 changes: 1 addition & 18 deletions Examples/Swift/DApp/AlertProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
import TesseractUtils
import CApp

public class AlertProvider: ObservableObject {
final class AlertProvider: ObservableObject {
public struct Alert: Identifiable {
let message: String
public var id: String { message }
Expand All @@ -21,21 +21,4 @@ public class AlertProvider: ObservableObject {
func showAlert(alert: String) {
self.alert = Alert(message: alert)
}

func toCore() -> CApp.AlertProvider {
var provider = CApp.AlertProvider(value: self)
provider.show_alert = alert_provider_show_alert
return provider
}
}

private func alert_provider_show_alert(this: UnsafePointer<CApp.AlertProvider>!, message: CStringRef!) {
let message = message!.copied()
Task {
try! await this.unowned().get().showAlert(alert: message)
}
}

extension CApp.AlertProvider: CSwiftDropPtr {
public typealias SObject = AlertProvider
}
43 changes: 29 additions & 14 deletions Examples/Swift/DApp/AppCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,41 @@
//

import Foundation
import TesseractTransportsClient
import CApp
import TesseractClient

class AppCore {
private var rust: AppContextPtr
final class TesseractTransportDelegate: TesseractDelegate {
private let alerts: AlertProvider

init(alerts: AlertProvider) {
try! self.rust = TResult<AppContextPtr>.wrap { value, error in
app_init(alerts.toCore(), IPCTransportIOS().toCore(), value, error)
}.get()
self.alerts = alerts
}

func signTx(tx: String) async throws -> String {
try await app_sign_data(self.rust, tx)
.result.castError(TesseractError.self).get()
func select(transports: Dictionary<String, TesseractTransportsClient.Status>) async -> String? {
assert(transports.count == 1, "How the heck do we have more than one transport here?")
let transport = transports.first!
switch transport.value {
case .ready: return transport.key
case .unavailable(let why):
await alerts.showAlert(alert: "Transport '\(transport.key)' is not available because of the following reason: \(why)")
return nil
case .error(let err):
await alerts.showAlert(alert: "Transport '\(transport.key)' is not available because the transport produced an error: \(err)")
return nil
}

}
}

struct AppCore {
private let service: TestService

init(alerts: AlertProvider) {
service = try! Tesseract
.default(delegate: TesseractTransportDelegate(alerts: alerts))
.service(TestService.self)
}

deinit {
app_deinit(&self.rust)
func signTx(tx: String) async throws -> String {
try await service.signTransaction(req: tx)
}
}

extension AppContextPtr: CType {}
45 changes: 11 additions & 34 deletions Examples/Swift/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
9244C7BF29246CBF0055E6B6 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9244C7BE29246CBF0055E6B6 /* ContentView.swift */; };
9244C7C129246CC10055E6B6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9244C7C029246CC10055E6B6 /* Assets.xcassets */; };
9244C7C429246CC10055E6B6 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9244C7C329246CC10055E6B6 /* Preview Assets.xcassets */; };
92611F192B0CED79003AFE3F /* TesseractClient in Frameworks */ = {isa = PBXBuildFile; productRef = 92611F182B0CED79003AFE3F /* TesseractClient */; };
929FF53A29246E0D00F79FD7 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 929FF53929246E0D00F79FD7 /* UniformTypeIdentifiers.framework */; };
929FF53D29246E0D00F79FD7 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 929FF53C29246E0D00F79FD7 /* Media.xcassets */; };
929FF53F29246E0D00F79FD7 /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929FF53E29246E0D00F79FD7 /* ActionViewController.swift */; };
929FF54229246E0D00F79FD7 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 929FF54029246E0D00F79FD7 /* MainInterface.storyboard */; };
929FF54629246E0D00F79FD7 /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 929FF53729246E0D00F79FD7 /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
929FF54F29246F0C00F79FD7 /* AppCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929FF54D29246F0C00F79FD7 /* AppCore.swift */; };
92B2FB59292D4BCD00260349 /* AlertProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92B2FB58292D4BCD00260349 /* AlertProvider.swift */; };
92D79B1E2AD82D2700D22BDC /* TesseractTransportsClient in Frameworks */ = {isa = PBXBuildFile; productRef = 92D79B1D2AD82D2700D22BDC /* TesseractTransportsClient */; };
BAED6AE8292C3AA000A9BA2D /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAED6AE7292C3AA000A9BA2D /* WalletData.swift */; };
BAED6AEA292C3AA600A9BA2D /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAED6AE7292C3AA000A9BA2D /* WalletData.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -86,7 +86,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92D79B1E2AD82D2700D22BDC /* TesseractTransportsClient in Frameworks */,
92611F192B0CED79003AFE3F /* TesseractClient in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -134,13 +134,13 @@
9244C7A729246C100055E6B6 /* DApp */ = {
isa = PBXGroup;
children = (
92B2FB58292D4BCD00260349 /* AlertProvider.swift */,
929FF54D29246F0C00F79FD7 /* AppCore.swift */,
929FF54E29246F0C00F79FD7 /* Info.plist */,
9244C7A829246C100055E6B6 /* DAppApp.swift */,
9244C7AA29246C100055E6B6 /* ContentView.swift */,
9244C7AC29246C120055E6B6 /* Assets.xcassets */,
9244C7AE29246C120055E6B6 /* Preview Content */,
92B2FB58292D4BCD00260349 /* AlertProvider.swift */,
);
path = DApp;
sourceTree = "<group>";
Expand Down Expand Up @@ -207,11 +207,10 @@
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
9244C7A429246C100055E6B6 /* RustDApp */ = {
9244C7A429246C100055E6B6 /* DApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9244C7B329246C120055E6B6 /* Build configuration list for PBXNativeTarget "RustDApp" */;
buildConfigurationList = 9244C7B329246C120055E6B6 /* Build configuration list for PBXNativeTarget "DApp" */;
buildPhases = (
929FF558292470A600F79FD7 /* Build Rust */,
9244C7A129246C100055E6B6 /* Sources */,
9244C7A229246C100055E6B6 /* Frameworks */,
9244C7A329246C100055E6B6 /* Resources */,
Expand All @@ -220,9 +219,9 @@
);
dependencies = (
);
name = RustDApp;
name = DApp;
packageProductDependencies = (
92D79B1D2AD82D2700D22BDC /* TesseractTransportsClient */,
92611F182B0CED79003AFE3F /* TesseractClient */,
);
productName = ExampleDapp;
productReference = 9244C7A529246C100055E6B6 /* DApp.app */;
Expand Down Expand Up @@ -301,7 +300,7 @@
projectDirPath = "";
projectRoot = "";
targets = (
9244C7A429246C100055E6B6 /* RustDApp */,
9244C7A429246C100055E6B6 /* DApp */,
9244C7B929246CBF0055E6B6 /* Wallet */,
929FF53629246E0D00F79FD7 /* Extension */,
);
Expand Down Expand Up @@ -338,28 +337,6 @@
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
929FF558292470A600F79FD7 /* Build Rust */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Build Rust";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "exec bash ${SRCROOT}/Rust/xcode_build_step.sh CApp app\n";
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
9244C7A129246C100055E6B6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
Expand Down Expand Up @@ -716,7 +693,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9244C7B329246C120055E6B6 /* Build configuration list for PBXNativeTarget "RustDApp" */ = {
9244C7B329246C120055E6B6 /* Build configuration list for PBXNativeTarget "DApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9244C7B429246C120055E6B6 /* Debug */,
Expand Down Expand Up @@ -750,9 +727,9 @@
isa = XCSwiftPackageProductDependency;
productName = TesseractService;
};
92D79B1D2AD82D2700D22BDC /* TesseractTransportsClient */ = {
92611F182B0CED79003AFE3F /* TesseractClient */ = {
isa = XCSwiftPackageProductDependency;
productName = TesseractTransportsClient;
productName = TesseractClient;
};
/* End XCSwiftPackageProductDependency section */
};
Expand Down
4 changes: 2 additions & 2 deletions Examples/Swift/Extension/TestSigningService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ protocol TestSigningServiceDelegate: AnyObject {
func acceptTx(tx: String) async throws -> Bool
}

class TestSigningService: TestService {
class TestSigningService: TestService {
var signature: String
weak var delegate: TestSigningServiceDelegate?

Expand All @@ -21,7 +21,7 @@ class TestSigningService: TestService {
self.signature = signature
}

func signTransation(req: String) async throws -> String {
func signTransaction(req: String) async throws -> String {
guard let delegate = self.delegate else {
throw TesseractError.null(TestSigningService.self)
}
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import PackageDescription

// Set it to true to use local binary (for development)
let useLocalBinary = false
let useLocalBinary = true

// URL and checksum of prebuilt rust Core
let binaryUrl = "https://github.com/tesseract-one/Tesseract.swift/releases/download/0.5.2/Tesseract-Core.bin.zip"
Expand Down
6 changes: 3 additions & 3 deletions Rust/tesseract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ edition = "2021"
[dependencies]
tesseract-swift-utils = { path = "../utils" }
tesseract-swift-transports = { path = "../transports" }
tesseract = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "master" }
tesseract-protocol-test = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "master", optional = true }
tesseract-protocol-substrate = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "master", optional = true }
tesseract = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "dapp-fixes" }
tesseract-protocol-test = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "dapp-fixes", optional = true }
tesseract-protocol-substrate = { git = "https://github.com/tesseract-one/Tesseract.rs.git", branch = "dapp-fixes", optional = true }
async-trait = "0.1"
errorcon = "0.1"
log = "0.4"
Expand Down
110 changes: 110 additions & 0 deletions Rust/tesseract/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::sync::Arc;
use std::{mem::ManuallyDrop, collections::HashMap};

use async_trait::async_trait;
use tesseract::Protocol;
use tesseract::client::{Transport, Tesseract, Service, Delegate, transport,};
use tesseract::serialize::Serializer as TSerializer;
use tesseract_swift_transports::client::{ClientTransport, ClientStatus};
use tesseract_swift_transports::error::TesseractSwiftError;
use tesseract_swift_utils::array::CArray;
use tesseract_swift_utils::future_impls::CFutureString;
use tesseract_swift_utils::traits::AsCRef;
use tesseract_swift_utils::{
ptr::{SyncPtr, CAnyDropPtr}, Void, array::CArrayRef,
map::CKeyValue, string::CString
};

pub type ClientTransportsStatusRef<'a> = CArrayRef<'a, CKeyValue<CString, ClientStatus>>;

#[repr(C)]
pub struct ClientTesseractDelegate {
ptr: CAnyDropPtr,
select_transport: unsafe extern "C" fn(
this: &ClientTesseractDelegate,
transports: ClientTransportsStatusRef,
) -> ManuallyDrop<CFutureString>,
}

#[async_trait]
impl Delegate for ClientTesseractDelegate {
async fn select_transport(
&self,
transports: &HashMap<String, transport::Status>,
) -> Option<String> {
let arr: CArray<CKeyValue<CString, ClientStatus>> = transports.clone().into();
let future = unsafe {
ManuallyDrop::into_inner((self.select_transport)(self, arr.as_cref()))
};

let option: Option<CString> = future.try_into_future().unwrap().await
.map(|s| Some(s))
.or_else(|err| {
let terror = TesseractSwiftError::from(err);
if terror.is_cancelled() { Ok(None) } else { Err(terror) }
}).unwrap();
option.map(|s| s.try_into().unwrap())
}
}

#[repr(C)]
pub enum Serializer {
Json, Cbor
}

impl From<Serializer> for TSerializer {
fn from(value: Serializer) -> Self {
match value {
Serializer::Json => Self::Json,
Serializer::Cbor => Self::Cbor,
}
}
}

#[repr(C)]
pub struct ClientTesseract(SyncPtr<Void>);

impl Drop for ClientTesseract {
fn drop(&mut self) {
let _ = unsafe { self.0.take_typed::<Tesseract<ClientTesseractDelegate>>() };
}
}

impl ClientTesseract {
pub fn new(tesseract: Tesseract<ClientTesseractDelegate>) -> Self {
Self(SyncPtr::new(tesseract).as_void())
}

pub fn service<P: Protocol + Copy + 'static>(&self, r#for: P) -> Arc<impl Service<Protocol = P>> {
let tesseract = unsafe {
self.0.as_typed_ref::<Tesseract<ClientTesseractDelegate>>()
};
tesseract.unwrap().service(r#for)
}

pub fn transport<T: Transport + 'static + Sync + Send>(&mut self, transport: T) -> Self {
let tesseract = unsafe {
self.0.take_typed::<Tesseract<ClientTesseractDelegate>>()
};
Self::new(tesseract.transport(transport))
}
}

#[no_mangle]
pub extern "C" fn tesseract_client_new(
delegate: ClientTesseractDelegate, serializer: Serializer
) -> ManuallyDrop<ClientTesseract> {
ManuallyDrop::new(ClientTesseract::new(Tesseract::new_with_serializer(Arc::new(delegate), serializer.into())))
}

#[no_mangle]
pub extern "C" fn tesseract_client_add_transport(
tesseract: &mut ClientTesseract, transport: ClientTransport
) -> ManuallyDrop<ClientTesseract> {
ManuallyDrop::new(tesseract.transport(transport))
}

#[no_mangle]
pub extern "C" fn tesseract_client_free(tesseract: &mut ManuallyDrop<ClientTesseract>) {
let _ = unsafe { ManuallyDrop::take(tesseract) };
}
Loading

0 comments on commit ed252e3

Please sign in to comment.