refactor: use specta for commands (#192)

* feat: add tauri-specta

* refactor: system library

* chore: format
This commit is contained in:
雨宮蓮
2024-05-25 15:21:40 +07:00
committed by GitHub
parent 7449000f5f
commit bba324ea53
92 changed files with 2164 additions and 2071 deletions

74
src-tauri/Cargo.lock generated
View File

@@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "addr2line"
version = "0.21.0"
@@ -2481,6 +2487,12 @@ dependencies = [
"serde",
]
[[package]]
name = "indoc"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "infer"
version = "0.15.0"
@@ -2883,6 +2895,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"serde_json",
"specta",
"tauri",
"tauri-build",
"tauri-plugin-clipboard-manager",
@@ -2897,6 +2910,7 @@ dependencies = [
"tauri-plugin-updater",
"tauri-plugin-upload",
"tauri-plugin-window-state",
"tauri-specta",
"tokio",
"webpage",
]
@@ -3698,6 +3712,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pathdiff"
version = "0.2.1"
@@ -4960,6 +4980,31 @@ dependencies = [
"system-deps",
]
[[package]]
name = "specta"
version = "2.0.0-rc.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3624a07cbde326fdf1ec37cbd39d06a224660fa0199b7db7316f2349583df981"
dependencies = [
"once_cell",
"paste",
"serde",
"specta-macros",
"thiserror",
]
[[package]]
name = "specta-macros"
version = "2.0.0-rc.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef33e9678ae36993fcbfc46aa29568ef10d32fd54428808759c6a450998c43ec"
dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "spin"
version = "0.9.8"
@@ -5209,6 +5254,7 @@ dependencies = [
"serde_json",
"serde_repr",
"serialize-to-javascript",
"specta",
"state",
"swift-rs",
"tauri-build",
@@ -5574,6 +5620,34 @@ dependencies = [
"wry",
]
[[package]]
name = "tauri-specta"
version = "2.0.0-rc.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856a2bbbbd4d39ae2c1e6d22aec50623596708ff8f7e4c598123dbc5165f5f76"
dependencies = [
"heck 0.5.0",
"indoc",
"serde",
"serde_json",
"specta",
"tauri",
"tauri-specta-macros",
"thiserror",
]
[[package]]
name = "tauri-specta-macros"
version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6f9e90bf2012877e2c4029a1bf756277183e9c7c77b850ef965711553998012"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.63",
]
[[package]]
name = "tauri-utils"
version = "2.0.0-beta.15"

View File

@@ -37,6 +37,8 @@ tauri-plugin-decorum = "0.1.0"
webpage = { version = "2.0", features = ["serde"] }
keyring = "2"
keyring-search = "0.2.0"
specta = "=2.0.0-rc.12"
tauri-specta = { version = "=2.0.0-rc.10", features = ["typescript"] }
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25.0"

View File

@@ -1,82 +1,83 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-capability",
"description": "Capability for the desktop",
"platforms": ["linux", "macOS", "windows"],
"windows": [
"main",
"splash",
"settings",
"search",
"nwc",
"activity",
"zap-*",
"event-*",
"user-*",
"editor-*",
"column-*"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"notification:allow-is-permission-granted",
"notification:allow-request-permission",
"notification:default",
"os:allow-locale",
"os:allow-platform",
"updater:default",
"updater:allow-check",
"updater:allow-download-and-install",
"window:allow-start-dragging",
"window:allow-create",
"window:allow-close",
"window:allow-set-focus",
"window:allow-center",
"window:allow-minimize",
"window:allow-maximize",
"window:allow-set-size",
"window:allow-set-focus",
"window:allow-start-dragging",
"decorum:allow-show-snap-overlay",
"clipboard-manager:allow-write-text",
"clipboard-manager:allow-read-text",
"webview:allow-create-webview-window",
"webview:allow-create-webview",
"webview:allow-set-webview-size",
"webview:allow-set-webview-position",
"webview:allow-webview-close",
"dialog:allow-open",
"dialog:allow-ask",
"dialog:allow-message",
"process:allow-restart",
"fs:allow-read-file",
"shell:allow-open",
{
"identifier": "http:default",
"allow": [
{
"url": "http://**/"
},
{
"url": "https://**/"
}
]
},
{
"identifier": "fs:allow-read-text-file",
"allow": [
{
"path": "$RESOURCE/locales/*"
},
{
"path": "$RESOURCE/resources/*"
}
]
}
]
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-capability",
"description": "Capability for the desktop",
"platforms": ["linux", "macOS", "windows"],
"windows": [
"main",
"splash",
"settings",
"search",
"nwc",
"activity",
"zap-*",
"event-*",
"user-*",
"editor-*",
"column-*"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"notification:allow-is-permission-granted",
"notification:allow-request-permission",
"notification:default",
"os:allow-locale",
"os:allow-platform",
"os:allow-os-type",
"updater:default",
"updater:allow-check",
"updater:allow-download-and-install",
"window:allow-start-dragging",
"window:allow-create",
"window:allow-close",
"window:allow-set-focus",
"window:allow-center",
"window:allow-minimize",
"window:allow-maximize",
"window:allow-set-size",
"window:allow-set-focus",
"window:allow-start-dragging",
"decorum:allow-show-snap-overlay",
"clipboard-manager:allow-write-text",
"clipboard-manager:allow-read-text",
"webview:allow-create-webview-window",
"webview:allow-create-webview",
"webview:allow-set-webview-size",
"webview:allow-set-webview-position",
"webview:allow-webview-close",
"dialog:allow-open",
"dialog:allow-ask",
"dialog:allow-message",
"process:allow-restart",
"fs:allow-read-file",
"shell:allow-open",
{
"identifier": "http:default",
"allow": [
{
"url": "http://**/"
},
{
"url": "https://**/"
}
]
},
{
"identifier": "fs:allow-read-text-file",
"allow": [
{
"path": "$RESOURCE/locales/*"
},
{
"path": "$RESOURCE/resources/*"
}
]
}
]
}

View File

@@ -1 +1 @@
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","window:allow-center","window:allow-minimize","window:allow-maximize","window:allow-set-size","window:allow-set-focus","window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","fs:allow-read-file","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}}
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","os:allow-os-type","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","window:allow-center","window:allow-minimize","window:allow-maximize","window:allow-set-size","window:allow-set-focus","window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","fs:allow-read-file","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}}

View File

@@ -1,3 +1,2 @@
pub mod folder;
pub mod opg;
pub mod window;

View File

@@ -1,6 +1,7 @@
use std::process::Command;
#[tauri::command]
#[specta::specta]
pub async fn show_in_folder(path: String) {
#[cfg(target_os = "windows")]
{

View File

@@ -1,16 +0,0 @@
use std::time::Duration;
use webpage::{Opengraph, Webpage, WebpageOptions};
#[tauri::command]
pub fn fetch_opg(url: String) -> Result<Opengraph, String> {
let mut options = WebpageOptions::default();
options.allow_insecure = true;
options.max_redirections = 2;
options.timeout = Duration::from_secs(10);
if let Ok(data) = Webpage::from_url(&url, options) {
Ok(data.html.opengraph)
} else {
Err("Get open graph failed".into())
}
}

View File

@@ -10,6 +10,7 @@ use tauri::{LogicalPosition, LogicalSize, Manager, WebviewUrl};
use tauri_plugin_decorum::WebviewWindowExt;
#[tauri::command]
#[specta::specta]
pub fn create_column(
label: &str,
x: f32,
@@ -45,6 +46,7 @@ pub fn create_column(
}
#[tauri::command]
#[specta::specta]
pub fn close_column(label: &str, app_handle: tauri::AppHandle) -> Result<bool, ()> {
match app_handle.get_webview(label) {
Some(webview) => {
@@ -59,6 +61,7 @@ pub fn close_column(label: &str, app_handle: tauri::AppHandle) -> Result<bool, (
}
#[tauri::command]
#[specta::specta]
pub fn reposition_column(
label: &str,
x: f32,
@@ -78,6 +81,7 @@ pub fn reposition_column(
}
#[tauri::command]
#[specta::specta]
pub fn resize_column(
label: &str,
width: f32,
@@ -97,6 +101,7 @@ pub fn resize_column(
}
#[tauri::command]
#[specta::specta]
pub fn open_window(
label: &str,
title: &str,
@@ -166,6 +171,7 @@ pub fn open_window(
}
#[tauri::command]
#[specta::specta]
pub fn set_badge(count: i32) {
#[cfg(target_os = "macos")]
unsafe {

View File

@@ -24,6 +24,61 @@ pub struct Nostr {
}
fn main() {
let invoke_handler = {
let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![
nostr::relay::get_relays,
nostr::relay::connect_relay,
nostr::relay::remove_relay,
nostr::keys::get_accounts,
nostr::keys::create_account,
nostr::keys::save_account,
nostr::keys::get_encrypted_key,
nostr::keys::nostr_connect,
nostr::keys::load_account,
nostr::keys::event_to_bech32,
nostr::keys::user_to_bech32,
nostr::keys::to_npub,
nostr::keys::verify_nip05,
nostr::metadata::run_notification,
nostr::metadata::get_activities,
nostr::metadata::get_current_user_profile,
nostr::metadata::get_profile,
nostr::metadata::get_contact_list,
nostr::metadata::set_contact_list,
nostr::metadata::create_profile,
nostr::metadata::follow,
nostr::metadata::unfollow,
nostr::metadata::get_nstore,
nostr::metadata::set_nstore,
nostr::metadata::set_nwc,
nostr::metadata::load_nwc,
nostr::metadata::get_balance,
nostr::metadata::zap_profile,
nostr::metadata::zap_event,
nostr::metadata::friend_to_friend,
nostr::event::get_event,
nostr::event::get_replies,
nostr::event::get_events_by,
nostr::event::get_local_events,
nostr::event::get_global_events,
nostr::event::get_hashtag_events,
nostr::event::publish,
nostr::event::repost,
commands::folder::show_in_folder,
commands::window::create_column,
commands::window::close_column,
commands::window::reposition_column,
commands::window::resize_column,
commands::window::open_window,
commands::window::set_badge
]);
#[cfg(debug_assertions)]
let builder = builder.path("../packages/system/src/commands.ts");
builder.build().unwrap()
};
tauri::Builder::default()
.setup(|app| {
let main_window = app.get_webview_window("main").unwrap();
@@ -98,55 +153,7 @@ fn main() {
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_upload::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.invoke_handler(tauri::generate_handler![
nostr::relay::get_relays,
nostr::relay::connect_relay,
nostr::relay::remove_relay,
nostr::keys::get_accounts,
nostr::keys::create_account,
nostr::keys::save_account,
nostr::keys::get_encrypted_key,
nostr::keys::nostr_connect,
nostr::keys::load_account,
nostr::keys::event_to_bech32,
nostr::keys::user_to_bech32,
nostr::keys::to_npub,
nostr::keys::verify_nip05,
nostr::metadata::run_notification,
nostr::metadata::get_activities,
nostr::metadata::get_current_user_profile,
nostr::metadata::get_profile,
nostr::metadata::get_contact_list,
nostr::metadata::set_contact_list,
nostr::metadata::create_profile,
nostr::metadata::follow,
nostr::metadata::unfollow,
nostr::metadata::get_nstore,
nostr::metadata::set_nstore,
nostr::metadata::set_nwc,
nostr::metadata::load_nwc,
nostr::metadata::get_balance,
nostr::metadata::zap_profile,
nostr::metadata::zap_event,
nostr::metadata::friend_to_friend,
nostr::event::get_event,
nostr::event::get_thread,
nostr::event::get_events_by,
nostr::event::get_local_events,
nostr::event::get_global_events,
nostr::event::get_hashtag_events,
nostr::event::get_group_events,
nostr::event::publish,
nostr::event::repost,
commands::folder::show_in_folder,
commands::window::create_column,
commands::window::close_column,
commands::window::reposition_column,
commands::window::resize_column,
commands::window::open_window,
commands::window::set_badge,
commands::opg::fetch_opg,
])
.invoke_handler(invoke_handler)
.run(tauri::generate_context!())
.expect("error while running tauri application")
}

View File

@@ -4,6 +4,7 @@ use std::{str::FromStr, time::Duration};
use tauri::State;
#[tauri::command]
#[specta::specta]
pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let event_id: Option<EventId> = match Nip19::from_bech32(id) {
@@ -49,7 +50,8 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result<String, Stri
}
#[tauri::command]
pub async fn get_thread(id: &str, state: State<'_, Nostr>) -> Result<Vec<Event>, String> {
#[specta::specta]
pub async fn get_replies(id: &str, state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let client = &state.client;
match EventId::from_hex(id) {
@@ -57,7 +59,7 @@ pub async fn get_thread(id: &str, state: State<'_, Nostr>) -> Result<Vec<Event>,
let filter = Filter::new().kinds(vec![Kind::TextNote]).event(event_id);
match client.get_events_of(vec![filter], None).await {
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
}
@@ -66,12 +68,12 @@ pub async fn get_thread(id: &str, state: State<'_, Nostr>) -> Result<Vec<Event>,
}
#[tauri::command]
#[specta::specta]
pub async fn get_events_by(
public_key: &str,
limit: usize,
as_of: Option<&str>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
) -> Result<Vec<String>, String> {
let client = &state.client;
match PublicKey::from_str(public_key) {
@@ -83,11 +85,11 @@ pub async fn get_events_by(
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.author(author)
.limit(limit)
.limit(20)
.until(until);
match client.get_events_of(vec![filter], None).await {
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
}
@@ -96,12 +98,12 @@ pub async fn get_events_by(
}
#[tauri::command]
#[specta::specta]
pub async fn get_local_events(
pubkeys: Vec<String>,
limit: usize,
until: Option<&str>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
) -> Result<Vec<String>, String> {
let client = &state.client;
let as_of = match until {
Some(until) => Timestamp::from_str(until).unwrap(),
@@ -119,7 +121,7 @@ pub async fn get_local_events(
.collect();
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.limit(limit)
.limit(20)
.authors(authors)
.until(as_of);
@@ -127,17 +129,17 @@ pub async fn get_local_events(
.get_events_of(vec![filter], Some(Duration::from_secs(8)))
.await
{
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn get_global_events(
limit: usize,
until: Option<&str>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
) -> Result<Vec<String>, String> {
let client = &state.client;
let as_of = match until {
Some(until) => Timestamp::from_str(until).unwrap(),
@@ -146,25 +148,25 @@ pub async fn get_global_events(
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.limit(limit)
.limit(20)
.until(as_of);
match client
.get_events_of(vec![filter], Some(Duration::from_secs(8)))
.await
{
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn get_hashtag_events(
hashtags: Vec<&str>,
limit: usize,
until: Option<&str>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
) -> Result<Vec<String>, String> {
let client = &state.client;
let as_of = match until {
Some(until) => Timestamp::from_str(until).unwrap(),
@@ -172,45 +174,18 @@ pub async fn get_hashtag_events(
};
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.limit(limit)
.limit(20)
.until(as_of)
.hashtags(hashtags);
match client.get_events_of(vec![filter], None).await {
Ok(events) => Ok(events),
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
pub async fn get_group_events(
list: Vec<&str>,
limit: usize,
until: Option<&str>,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
let client = &state.client;
let as_of = match until {
Some(until) => Timestamp::from_str(until).unwrap(),
None => Timestamp::now(),
};
let authors: Vec<PublicKey> = list
.into_iter()
.map(|hex| PublicKey::from_hex(hex).unwrap())
.collect();
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Repost])
.limit(limit)
.until(as_of)
.authors(authors);
match client.get_events_of(vec![filter], None).await {
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn publish(
content: &str,
tags: Vec<Vec<&str>>,
@@ -226,12 +201,13 @@ pub async fn publish(
}
#[tauri::command]
pub async fn repost(raw: &str, state: State<'_, Nostr>) -> Result<EventId, String> {
#[specta::specta]
pub async fn repost(raw: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let event = Event::from_json(raw).unwrap();
match client.repost(&event, None).await {
Ok(event_id) => Ok(event_id),
Ok(event_id) => Ok(event_id.to_string()),
Err(err) => Err(err.to_string()),
}
}

View File

@@ -2,17 +2,20 @@ use crate::Nostr;
use keyring::Entry;
use keyring_search::{Limit, List, Search};
use nostr_sdk::prelude::*;
use serde::Serialize;
use specta::Type;
use std::str::FromStr;
use std::time::Duration;
use tauri::State;
#[derive(serde::Serialize)]
#[derive(Serialize, Type)]
pub struct Account {
npub: String,
nsec: String,
}
#[tauri::command]
#[specta::specta]
pub fn get_accounts() -> Result<String, String> {
let search = Search::new().unwrap();
let results = search.by("Account", "nostr_secret");
@@ -24,6 +27,7 @@ pub fn get_accounts() -> Result<String, String> {
}
#[tauri::command]
#[specta::specta]
pub fn create_account() -> Result<Account, ()> {
let keys = Keys::generate();
let public_key = keys.public_key();
@@ -38,6 +42,7 @@ pub fn create_account() -> Result<Account, ()> {
}
#[tauri::command]
#[specta::specta]
pub async fn save_account(
nsec: &str,
password: &str,
@@ -80,6 +85,7 @@ pub async fn save_account(
}
#[tauri::command]
#[specta::specta]
pub async fn load_account(npub: &str, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client;
let keyring = Entry::new(&npub, "nostr_secret").unwrap();
@@ -165,6 +171,7 @@ pub async fn load_account(npub: &str, state: State<'_, Nostr>) -> Result<bool, S
}
#[tauri::command]
#[specta::specta]
pub async fn nostr_connect(
npub: &str,
uri: &str,
@@ -203,6 +210,7 @@ pub async fn nostr_connect(
}
#[tauri::command(async)]
#[specta::specta]
pub fn get_encrypted_key(npub: &str, password: &str) -> Result<String, String> {
let keyring = Entry::new(npub, "nostr_secret").unwrap();
@@ -221,6 +229,7 @@ pub fn get_encrypted_key(npub: &str, password: &str) -> Result<String, String> {
}
#[tauri::command]
#[specta::specta]
pub fn event_to_bech32(id: &str, relays: Vec<String>) -> Result<String, ()> {
let event_id = EventId::from_hex(id).unwrap();
let event = Nip19Event::new(event_id, relays);
@@ -229,6 +238,7 @@ pub fn event_to_bech32(id: &str, relays: Vec<String>) -> Result<String, ()> {
}
#[tauri::command]
#[specta::specta]
pub fn user_to_bech32(key: &str, relays: Vec<String>) -> Result<String, ()> {
let pubkey = PublicKey::from_str(key).unwrap();
let profile = Nip19Profile::new(pubkey, relays).unwrap();
@@ -237,6 +247,7 @@ pub fn user_to_bech32(key: &str, relays: Vec<String>) -> Result<String, ()> {
}
#[tauri::command]
#[specta::specta]
pub fn to_npub(hex: &str) -> Result<String, ()> {
let public_key = PublicKey::from_str(hex).unwrap();
let npub = Nip19::Pubkey(public_key);
@@ -245,6 +256,7 @@ pub fn to_npub(hex: &str) -> Result<String, ()> {
}
#[tauri::command]
#[specta::specta]
pub async fn verify_nip05(key: &str, nip05: &str) -> Result<bool, String> {
match PublicKey::from_str(key) {
Ok(public_key) => {

View File

@@ -6,6 +6,7 @@ use tauri::{Manager, State};
use url::Url;
#[tauri::command]
#[specta::specta]
pub fn run_notification(accounts: Vec<String>, app: tauri::AppHandle) -> Result<(), ()> {
tauri::async_runtime::spawn(async move {
let window = app.get_window("main").unwrap();
@@ -49,11 +50,12 @@ pub fn run_notification(accounts: Vec<String>, app: tauri::AppHandle) -> Result<
}
#[tauri::command]
#[specta::specta]
pub async fn get_activities(
account: &str,
kind: &str,
state: State<'_, Nostr>,
) -> Result<Vec<Event>, String> {
) -> Result<Vec<String>, String> {
let client = &state.client;
if let Ok(pubkey) = PublicKey::from_str(account) {
@@ -65,7 +67,7 @@ pub async fn get_activities(
.until(Timestamp::now());
match client.get_events_of(vec![filter], None).await {
Ok(events) => Ok(events),
Ok(events) => Ok(events.into_iter().map(|ev| ev.as_json()).collect()),
Err(err) => Err(err.to_string()),
}
} else {
@@ -77,6 +79,7 @@ pub async fn get_activities(
}
#[tauri::command]
#[specta::specta]
pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client;
@@ -114,7 +117,8 @@ pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result<boo
}
#[tauri::command]
pub async fn get_current_user_profile(state: State<'_, Nostr>) -> Result<Metadata, String> {
#[specta::specta]
pub async fn get_current_user_profile(state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let signer = client.signer().await.unwrap();
let public_key = signer.public_key().await.unwrap();
@@ -130,7 +134,7 @@ pub async fn get_current_user_profile(state: State<'_, Nostr>) -> Result<Metadat
Ok(events) => {
if let Some(event) = events.first() {
if let Ok(metadata) = Metadata::from_json(&event.content) {
Ok(metadata)
Ok(metadata.as_json())
} else {
Err("Parse metadata failed".into())
}
@@ -143,7 +147,8 @@ pub async fn get_current_user_profile(state: State<'_, Nostr>) -> Result<Metadat
}
#[tauri::command]
pub async fn get_profile(id: &str, state: State<'_, Nostr>) -> Result<Metadata, String> {
#[specta::specta]
pub async fn get_profile(id: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let public_key: Option<PublicKey> = match Nip19::from_bech32(id) {
Ok(val) => match val {
@@ -166,13 +171,13 @@ pub async fn get_profile(id: &str, state: State<'_, Nostr>) -> Result<Metadata,
if let Ok(events) = query {
if let Some(event) = events.first() {
if let Ok(metadata) = Metadata::from_json(&event.content) {
Ok(metadata)
Ok(metadata.as_json())
} else {
Err("Parse metadata failed".into())
}
} else {
let rand_metadata = Metadata::new();
Ok(rand_metadata)
Ok(rand_metadata.as_json())
}
} else {
Err("Get metadata failed".into())
@@ -183,6 +188,7 @@ pub async fn get_profile(id: &str, state: State<'_, Nostr>) -> Result<Metadata,
}
#[tauri::command]
#[specta::specta]
pub async fn set_contact_list(pubkeys: Vec<&str>, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client;
let contact_list: Vec<Contact> = pubkeys
@@ -197,6 +203,7 @@ pub async fn set_contact_list(pubkeys: Vec<&str>, state: State<'_, Nostr>) -> Re
}
#[tauri::command]
#[specta::specta]
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let client = &state.client;
@@ -218,6 +225,7 @@ pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, St
}
#[tauri::command]
#[specta::specta]
pub async fn create_profile(
name: &str,
display_name: &str,
@@ -228,7 +236,7 @@ pub async fn create_profile(
lud16: &str,
website: &str,
state: State<'_, Nostr>,
) -> Result<EventId, String> {
) -> Result<String, String> {
let client = &state.client;
let mut metadata = Metadata::new()
.name(name)
@@ -250,68 +258,71 @@ pub async fn create_profile(
}
if let Ok(event_id) = client.set_metadata(&metadata).await {
Ok(event_id)
Ok(event_id.to_string())
} else {
Err("Create profile failed".into())
}
}
#[tauri::command]
#[specta::specta]
pub async fn follow(
id: &str,
alias: Option<&str>,
state: State<'_, Nostr>,
) -> Result<EventId, String> {
) -> Result<String, String> {
let client = &state.client;
let public_key = PublicKey::from_str(id).unwrap();
let contact = Contact::new(public_key, None, alias);
let contact = Contact::new(public_key, None, alias); // #TODO: Add relay_url
let contact_list = client.get_contact_list(Some(Duration::from_secs(10))).await;
if let Ok(mut old_list) = contact_list {
old_list.push(contact);
let new_list = old_list.into_iter();
match contact_list {
Ok(mut old_list) => {
old_list.push(contact);
let new_list = old_list.into_iter();
if let Ok(event_id) = client.set_contact_list(new_list).await {
Ok(event_id)
} else {
Err("Follow failed".into())
match client.set_contact_list(new_list).await {
Ok(event_id) => Ok(event_id.to_string()),
Err(err) => Err(err.to_string()),
}
}
} else {
Err("Follow failed".into())
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result<EventId, String> {
#[specta::specta]
pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
let public_key = PublicKey::from_str(id).unwrap();
let contact_list = client.get_contact_list(Some(Duration::from_secs(10))).await;
if let Ok(mut old_list) = contact_list {
let index = old_list
.iter()
.position(|x| x.public_key == public_key)
.unwrap();
old_list.remove(index);
match contact_list {
Ok(mut old_list) => {
let index = old_list
.iter()
.position(|x| x.public_key == public_key)
.unwrap();
old_list.remove(index);
let new_list = old_list.into_iter();
let new_list = old_list.into_iter();
if let Ok(event_id) = client.set_contact_list(new_list).await {
Ok(event_id)
} else {
Err("Follow failed".into())
match client.set_contact_list(new_list).await {
Ok(event_id) => Ok(event_id.to_string()),
Err(err) => Err(err.to_string()),
}
}
} else {
Err("Follow failed".into())
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
#[specta::specta]
pub async fn set_nstore(
key: &str,
content: &str,
state: State<'_, Nostr>,
) -> Result<EventId, String> {
) -> Result<String, String> {
let client = &state.client;
match client.signer().await {
@@ -323,7 +334,7 @@ pub async fn set_nstore(
let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]);
match client.send_event_builder(builder).await {
Ok(event_id) => Ok(event_id),
Ok(event_id) => Ok(event_id.to_string()),
Err(err) => Err(err.to_string()),
}
}
@@ -332,6 +343,7 @@ pub async fn set_nstore(
}
#[tauri::command]
#[specta::specta]
pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result<String, String> {
let client = &state.client;
@@ -366,6 +378,7 @@ pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result<String, St
}
#[tauri::command]
#[specta::specta]
pub async fn set_nwc(uri: &str, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client;
@@ -385,6 +398,7 @@ pub async fn set_nwc(uri: &str, state: State<'_, Nostr>) -> Result<bool, String>
}
#[tauri::command]
#[specta::specta]
pub async fn load_nwc(state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client;
let keyring = Entry::new("Lume Secret Storage", "NWC").unwrap();
@@ -404,7 +418,8 @@ pub async fn load_nwc(state: State<'_, Nostr>) -> Result<bool, String> {
}
#[tauri::command]
pub async fn get_balance() -> Result<u64, String> {
#[specta::specta]
pub async fn get_balance() -> Result<String, String> {
let keyring = Entry::new("Lume Secret Storage", "NWC").unwrap();
match keyring.get_password() {
@@ -412,7 +427,7 @@ pub async fn get_balance() -> Result<u64, String> {
let uri = NostrWalletConnectURI::from_str(&val).unwrap();
if let Ok(nwc) = NWC::new(uri).await {
if let Ok(balance) = nwc.get_balance().await {
Ok(balance)
Ok(balance.to_string())
} else {
Err("Get balance failed".into())
}
@@ -425,9 +440,10 @@ pub async fn get_balance() -> Result<u64, String> {
}
#[tauri::command]
#[specta::specta]
pub async fn zap_profile(
id: &str,
amount: u64,
amount: &str,
message: &str,
state: State<'_, Nostr>,
) -> Result<bool, String> {
@@ -446,8 +462,9 @@ pub async fn zap_profile(
if let Some(recipient) = public_key {
let details = ZapDetails::new(ZapType::Public).message(message);
let num = amount.parse::<u64>().unwrap();
if (client.zap(recipient, amount, Some(details)).await).is_ok() {
if (client.zap(recipient, num, Some(details)).await).is_ok() {
Ok(true)
} else {
Err("Zap profile failed".into())
@@ -458,9 +475,10 @@ pub async fn zap_profile(
}
#[tauri::command]
#[specta::specta]
pub async fn zap_event(
id: &str,
amount: u64,
amount: &str,
message: &str,
state: State<'_, Nostr>,
) -> Result<bool, String> {
@@ -479,8 +497,9 @@ pub async fn zap_event(
if let Some(recipient) = event_id {
let details = ZapDetails::new(ZapType::Public).message(message);
let num = amount.parse::<u64>().unwrap();
if (client.zap(recipient, amount, Some(details)).await).is_ok() {
if (client.zap(recipient, num, Some(details)).await).is_ok() {
Ok(true)
} else {
Err("Zap event failed".into())

View File

@@ -1,8 +1,10 @@
use crate::Nostr;
use nostr_sdk::prelude::*;
use serde::Serialize;
use specta::Type;
use tauri::State;
#[derive(serde::Serialize)]
#[derive(Serialize, Type)]
pub struct Relays {
connected: Vec<String>,
read: Option<Vec<String>>,
@@ -11,6 +13,7 @@ pub struct Relays {
}
#[tauri::command]
#[specta::specta]
pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, ()> {
let client = &state.client;
@@ -73,6 +76,7 @@ pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, ()> {
}
#[tauri::command]
#[specta::specta]
pub async fn connect_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, ()> {
let client = &state.client;
if let Ok(status) = client.add_relay(relay).await {
@@ -89,6 +93,7 @@ pub async fn connect_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool,
}
#[tauri::command]
#[specta::specta]
pub async fn remove_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, ()> {
let client = &state.client;
if let Ok(_) = client.remove_relay(relay).await {