chore: setup tauri

This commit is contained in:
reya
2024-07-23 13:33:48 +07:00
parent 8ae1368419
commit 462837565e
10 changed files with 1931 additions and 24 deletions

1656
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,35 @@ edition = "2021"
tauri-build = { version = "2.0.0-beta", features = [] } tauri-build = { version = "2.0.0-beta", features = [] }
[dependencies] [dependencies]
tauri = { version = "2.0.0-beta", features = [] } nostr-sdk = { version = "0.33", features = ["sqlite"] }
tauri = { version = "2.0.0-beta", features = [
"tray-icon",
"macos-private-api",
"protocol-asset",
] }
tauri-plugin-shell = "2.0.0-beta" tauri-plugin-shell = "2.0.0-beta"
tauri-plugin-decorum = "0.1.5"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
keyring = { version = "3", features = [
"apple-native",
"windows-native",
"linux-native",
] }
keyring-search = "1.2.0"
itertools = "0.13.0"
[target.'cfg(target_os = "macos")'.dependencies]
border = { git = "https://github.com/ahkohd/tauri-toolkit", branch = "v2" }
[profile.release]
codegen-units = 1
lto = true
panic = "abort"
incremental = false
opt-level = "z"
strip = true
rpath = false
debug = false
debug-assertions = false
overflow-checks = false

View File

@@ -2,7 +2,9 @@
"$schema": "../gen/schemas/desktop-schema.json", "$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default", "identifier": "default",
"description": "Capability for the main window", "description": "Capability for the main window",
"windows": ["main"], "windows": [
"main"
],
"permissions": [ "permissions": [
"path:default", "path:default",
"event:default", "event:default",
@@ -12,6 +14,14 @@
"resources:default", "resources:default",
"menu:default", "menu:default",
"tray:default", "tray:default",
"shell:allow-open" "shell:allow-open",
"window:allow-close",
"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"
] ]
} }

View File

@@ -0,0 +1,100 @@
use itertools::Itertools;
use keyring::Entry;
use keyring_search::{Limit, List, Search};
use nostr_sdk::prelude::*;
use std::{collections::HashSet, str::FromStr};
use tauri::State;
use crate::Nostr;
#[tauri::command]
pub fn get_accounts() -> Vec<String> {
let search = Search::new().expect("Unexpected.");
let results = search.by_user("nostr_secret");
let list = List::list_credentials(&results, Limit::All);
let accounts: HashSet<String> =
list.split_whitespace().filter(|v| v.starts_with("npub1")).map(String::from).collect();
accounts.into_iter().collect()
}
#[tauri::command]
pub async fn get_profile(id: String, state: State<'_, Nostr>) -> Result<String, ()> {
let client = &state.client;
let public_key = PublicKey::from_str(&id).unwrap();
let filter = Filter::new().author(public_key).kind(Kind::Metadata).limit(1);
let events = client.get_events_of(vec![filter], None).await.unwrap();
if let Some(event) = events.first() {
Ok(Metadata::from_json(&event.content).unwrap().as_json())
} else {
Ok(Metadata::new().as_json())
}
}
#[tauri::command]
pub async fn login(id: String, state: State<'_, Nostr>) -> Result<(), String> {
let client = &state.client;
let keyring = Entry::new(&id, "nostr_secret").expect("Unexpected.");
let password = match keyring.get_password() {
Ok(pw) => pw,
Err(_) => return Err("Cancelled".into()),
};
let keys = Keys::parse(password).expect("Secret Key is modified, please check again.");
let signer = NostrSigner::Keys(keys);
// Set signer
client.set_signer(Some(signer)).await;
let public_key = PublicKey::from_str(&id).unwrap();
let incoming = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
if let Ok(events) = client.get_events_of(vec![inbox], None).await {
if let Some(event) = events.into_iter().next() {
for tag in &event.tags {
if let Some(TagStandard::Relay(url)) = tag.as_standardized() {
let relay = url.to_string();
let _ = client.add_relay(&relay).await;
let _ = client.connect_relay(&relay).await;
println!("Connecting to {} ...", relay);
}
}
}
}
if let Ok(report) = client.reconcile(incoming.clone(), NegentropyOptions::default()).await {
let receives = report.received.clone();
let ids = receives.into_iter().collect::<Vec<_>>();
if let Ok(events) = client.database().query(vec![Filter::new().ids(ids)], Order::Desc).await
{
let pubkeys = events
.into_iter()
.unique_by(|ev| ev.pubkey)
.map(|ev| ev.pubkey)
.collect::<Vec<_>>();
if client
.reconcile(
Filter::new().kind(Kind::GiftWrap).pubkeys(pubkeys),
NegentropyOptions::default(),
)
.await
.is_ok()
{
println!("Sync done.")
}
}
}
if client.subscribe(vec![incoming.limit(0)], None).await.is_ok() {
println!("Waiting for new message...")
}
Ok(())
}

View File

@@ -0,0 +1 @@
pub mod account;

View File

@@ -1,16 +1,66 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!! // Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command use border::WebviewWindowExt as WebviewWindowExtAlt;
#[tauri::command] use commands::account::{get_accounts, get_profile, login};
fn greet(name: &str) -> String { use nostr_sdk::prelude::*;
format!("Hello, {}! You've been greeted from Rust!", name) use serde::Serialize;
use std::{fs, sync::Mutex};
use tauri::Manager;
use tauri_plugin_decorum::WebviewWindowExt;
mod commands;
#[derive(Serialize)]
pub struct Nostr {
#[serde(skip_serializing)]
client: Client,
contact_list: Mutex<Vec<Contact>>,
} }
fn main() { fn main() {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_shell::init()) .setup(|app| {
.invoke_handler(tauri::generate_handler![greet]) #[cfg(not(target_os = "linux"))]
.run(tauri::generate_context!()) let main_window = app.get_webview_window("main").unwrap();
.expect("error while running tauri application");
// Set custom decoration
main_window.create_overlay_titlebar().unwrap();
// Restore native border
#[cfg(target_os = "macos")]
main_window.add_border(None);
tauri::async_runtime::block_on(async move {
// Create data folder if not exist
let dir = app.path().config_dir().expect("Config Directory not found.");
let _ = fs::create_dir_all(dir.join("Coop/"));
// Setup database
let database = SQLiteDatabase::open(dir.join("Coop/coop.db")).await;
// Setup nostr client
let client = match database {
Ok(db) => ClientBuilder::default().database(db).build(),
Err(_) => ClientBuilder::default().build(),
};
// Add bootstrap relay
let _ = client.add_relay("wss://relay.damus.io/").await;
let _ = client.add_relay("wss://relay.nostr.net/").await;
// Connect
client.connect().await;
// Create global state
app.handle().manage(Nostr { client, contact_list: Mutex::new(vec![]) })
});
Ok(())
})
.plugin(tauri_plugin_decorum::init())
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![login, get_accounts, get_profile])
.run(tauri::generate_context!())
.expect("error while running tauri application");
} }

View File

@@ -1,5 +1,5 @@
{ {
"productName": "coop", "productName": "Coop",
"version": "0.0.0", "version": "0.0.0",
"identifier": "com.tauri.dev", "identifier": "com.tauri.dev",
"build": { "build": {
@@ -9,15 +9,27 @@
"frontendDist": "../dist" "frontendDist": "../dist"
}, },
"app": { "app": {
"windows": [ "macOSPrivateApi": true,
{ "withGlobalTauri": true,
"title": "coop",
"width": 800,
"height": 600
}
],
"security": { "security": {
"csp": null "csp": null,
"assetProtocol": {
"enable": true,
"scope": [
"$APPDATA/*",
"$DATA/*",
"$LOCALDATA/*",
"$DESKTOP/*",
"$DOCUMENT/*",
"$DOWNLOAD/*",
"$HOME/*",
"$PICTURE/*",
"$PUBLIC/*",
"$VIDEO/*",
"$APPCONFIG/*",
"$RESOURCE/*"
]
}
} }
}, },
"bundle": { "bundle": {

View File

@@ -0,0 +1,14 @@
{
"app": {
"windows": [
{
"title": "Coop",
"label": "main",
"width": 860,
"height": 650,
"minWidth": 860,
"minHeight": 650
}
]
}
}

View File

@@ -0,0 +1,23 @@
{
"app": {
"windows": [
{
"title": "Coop",
"label": "main",
"width": 860,
"height": 650,
"minWidth": 860,
"minHeight": 650,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"transparent": true,
"windowEffects": {
"state": "followsWindowActiveState",
"effects": [
"underWindowBackground"
]
}
}
]
}
}

View File

@@ -0,0 +1,20 @@
{
"app": {
"windows": [
{
"title": "Coop",
"label": "main",
"width": 860,
"height": 650,
"minWidth": 860,
"minHeight": 650,
"transparent": true,
"windowEffects": {
"effects": [
"mica"
]
}
}
]
}
}