caracal 0.3.6

Nostr client for Gemini
use super::route_prelude::*;
use nostr::nips::nip46::NostrConnectURI;
use nostr_connect::prelude::*;
use nostr_sdk::prelude::*;
use std::sync::Arc;

#[derive(Template)]
#[template(path = "nostr_connect.gmi", escape = "txt")]
pub struct NostrConnnectTemplate {}

#[derive(Template)]
#[template(path = "nostr_connect_ok.gmi", escape = "txt")]
pub struct NostrConnnectSuccessTemplate {}

#[derive(Template)]
#[template(path = "nostr_connect_failure.gmi", escape = "txt")]
pub struct NostrConnnectFailureTemplate {}

pub async fn nostr_connect_index(
    _ctx: RouteContext,
    _user: &'static mut CaracalUser,
) -> Response {
    Response::success(WindTemplate::render(NostrConnnectTemplate {}))
}

/// Nostr Connect. Connect to a remote signer.
/// The bunker URI is passed in the query
pub async fn nostr_connect_change(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let Ok(client_keys) = user.get_client_keys() else {
        return Response::temporary_failure("Client keys error");
    };

    let mut config = user.nostr_config();

    if let Some(input_uri) = dec_urlq(&ctx.url) {
        // From query

        if let Ok(uri) = NostrConnectURI::parse(&input_uri) {
            let connect_string = uri.to_string();

            if let Ok(signer) = NostrConnect::new(
                uri.clone(),
                client_keys,
                std::time::Duration::from_secs(20),
                None,
            ) {
                let mut nostr_config = user.nostr_config();
                nostr_config.last_bunker_uri = Some(connect_string);
                let _ = user.save_nostr_config(&nostr_config);

                user.signer = Arc::new(signer);
                user.client.set_signer(user.signer.clone()).await;

                user.connect_uri = Some(uri.clone());

                let _ = user.tx.send(0).await;

                Response::success(WindTemplate::render(
                    NostrConnnectSuccessTemplate {},
                ))
            } else {
                user.connect_uri = None;

                let _ = user.client.unset_signer().await;

                Response::success(WindTemplate::render(
                    NostrConnnectFailureTemplate {},
                ))
            }
        } else {
            user.connect_uri = None;
            Response::input(t!("invalid_input_bunker_uri"))
        }
    } else if let Some(uri) = config.last_bunker_uri.take() {
        // Try to reuse the last bunker URI

        let _ = user.save_nostr_config(&config);

        return Response::temporary_redirect(format!(
            "/connect/bunker?{}",
            encode(&uri)
        ));
    } else {
        return Response::input(t!("input_bunker_uri"));
    }
}