Hello folks is it possible to implement Internet Identity on a UI that is Rust based (no JS, CSS, HTML or any JS Framework).
internet_identity.rs
use ic_cdk::api::call::call;
use ic_cdk::export::Principal;
use serde::{Deserialize, Serialize};
use candid::{CandidType, Decode, Encode};
#[derive(CandidType, Deserialize, Debug)]
pub struct AuthResponse {
pub principal: Principal,
pub success: bool,
pub error: Option<String>,
}
pub async fn authenticate_user() -> Result<AuthResponse, String> {
let canister_id = Principal::from_text("your_internet_identity_canister_id").unwrap();
let result: Result<(AuthResponse,), (ic_cdk::api::call::RejectionCode, String)> = call(canister_id, "authenticate", ()).await;
result.map(|(response,)| response).map_err(|e| e.1)
}
authentication_ui.rs
use crate::authentication::internet_identity::authenticate_user;
use crate::i3m::gui::{
button::{ButtonBuilder, ButtonMessage},
grid::{Column, GridBuilder, Row},
message::{MessageDirection, UiMessage},
text::{TextBuilder, TextMessage},
widget::{WidgetBuilder},
BuildContext, UiNode, UserInterface,
};
use std::sync::Mutex;
use lazy_static::lazy_static;
use ic_cdk::export::Principal;
use i3m_core::pool::Handle;
lazy_static! {
static ref AUTHENTICATED_USER: Mutex<Option<Principal>> = Mutex::new(None);
}
pub struct AuthenticationUI {
root: Handle<UiNode>,
login_button: Handle<UiNode>,
status_text: Handle<UiNode>,
}
impl AuthenticationUI {
pub fn new(ctx: &mut BuildContext) -> Self {
let status_text = TextBuilder::new(WidgetBuilder::new())
.with_text("Please authenticate using Internet Identity...")
.build(ctx);
let login_button = ButtonBuilder::new(WidgetBuilder::new())
.with_text("Login")
.build(ctx);
let root = GridBuilder::new(
WidgetBuilder::new()
.with_child(status_text)
.with_child(login_button),
)
.add_row(Row::stretch())
.add_row(Row::stretch())
.add_column(Column::stretch())
.build(ctx);
Self {
root,
login_button,
status_text,
}
}
pub fn handle_message(&mut self, ui: &mut UserInterface, message: &UiMessage) {
if let Some(ButtonMessage::Click) = message.data() {
if message.destination() == self.login_button {
self.authenticate(ui);
}
}
}
fn authenticate(&self, ui: &mut UserInterface) {
let future = async {
match authenticate_user().await {
Ok(response) => {
if response.success {
let mut user = AUTHENTICATED_USER.lock().unwrap();
*user = Some(response.principal);
ui.send_message(TextMessage::text(
self.status_text,
MessageDirection::ToWidget,
format!("User authenticated: {:?}", response.principal),
));
// start_editor().await;
} else {
ui.send_message(TextMessage::text(
self.status_text,
MessageDirection::ToWidget,
format!("Authentication failed: {:?}", response.error),
));
}
}
Err(e) => {
ui.send_message(TextMessage::text(
self.status_text,
MessageDirection::ToWidget,
format!("Authentication error: {:?}", e),
));
}
}
};
// Spawn the future to run asynchronously
crate::i3m::core::futures::executor::block_on(future);
}
}