fix: async mutex lock forever

This commit is contained in:
2024-10-14 14:59:42 +07:00
parent cb6006f596
commit 62bd689031
7 changed files with 115 additions and 126 deletions

View File

@@ -285,7 +285,7 @@ pub async fn login(
// NIP-03: Get user's contact list // NIP-03: Get user's contact list
let contact_list = { let contact_list = {
if let Ok(contacts) = client.get_contact_list(Some(Duration::from_secs(5))).await { if let Ok(contacts) = client.get_contact_list(Some(Duration::from_secs(5))).await {
state.contact_list.lock().await.clone_from(&contacts); state.contact_list.lock().unwrap().clone_from(&contacts);
contacts contacts
} else { } else {
Vec::new() Vec::new()
@@ -375,7 +375,7 @@ pub async fn login(
.collect(); .collect();
// Update app's state // Update app's state
state.trusted_list.lock().await.clone_from(&trusted_list); state.trusted_list.lock().unwrap().clone_from(&trusted_list);
let trusted_users: Vec<PublicKey> = trusted_list.into_iter().collect(); let trusted_users: Vec<PublicKey> = trusted_list.into_iter().collect();
println!("Total trusted users: {}", trusted_users.len()); println!("Total trusted users: {}", trusted_users.len());

View File

@@ -73,71 +73,35 @@ pub async fn get_event(id: String, state: State<'_, Nostr>) -> Result<RichEvent,
#[specta::specta] #[specta::specta]
pub async fn get_event_from( pub async fn get_event_from(
id: String, id: String,
relay_hint: String, _relay_hint: String,
state: State<'_, Nostr>, state: State<'_, Nostr>,
) -> Result<RichEvent, String> { ) -> Result<RichEvent, String> {
let client = &state.client; let client = &state.client;
let settings = state.settings.lock().await;
let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; let event_id = EventId::parse(&id).map_err(|err| err.to_string())?;
let filter = Filter::new().id(event_id); let filter = Filter::new().id(event_id);
if !settings.use_relay_hint { match client
match client .get_events_of(
.get_events_of( vec![filter],
vec![filter], EventSource::both(Some(Duration::from_secs(5))),
EventSource::both(Some(Duration::from_secs(5))), )
) .await
.await {
{ Ok(events) => {
Ok(events) => { if let Some(event) = events.first() {
if let Some(event) = events.first() { let raw = event.as_json();
let raw = event.as_json(); let parsed = if event.kind == Kind::TextNote {
let parsed = if event.kind == Kind::TextNote { Some(parse_event(&event.content).await)
Some(parse_event(&event.content).await)
} else {
None
};
Ok(RichEvent { raw, parsed })
} else { } else {
Err("Cannot found this event with current relay list".into()) None
} };
Ok(RichEvent { raw, parsed })
} else {
Err("Cannot found this event with current relay list".into())
} }
Err(err) => Err(err.to_string()),
}
} else {
// Add relay hint to relay pool
if let Err(e) = client.add_relay(&relay_hint).await {
return Err(e.to_string());
}
if let Err(e) = client.connect_relay(&relay_hint).await {
return Err(e.to_string());
}
match client
.get_events_of(
vec![Filter::new().id(event_id)],
EventSource::both(Some(Duration::from_secs(5))),
)
.await
{
Ok(events) => {
if let Some(event) = events.first() {
let raw = event.as_json();
let parsed = if event.kind == Kind::TextNote {
Some(parse_event(&event.content).await)
} else {
None
};
Ok(RichEvent { raw, parsed })
} else {
Err("Cannot found this event with current relay list".into())
}
}
Err(err) => Err(err.to_string()),
} }
Err(err) => Err(err.to_string()),
} }
} }

View File

@@ -107,8 +107,8 @@ pub async fn set_contact_list(
#[tauri::command] #[tauri::command]
#[specta::specta] #[specta::specta]
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, String> { pub fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let contact_list = state.contact_list.lock().await.clone(); let contact_list = state.contact_list.lock().unwrap().clone();
let vec: Vec<String> = contact_list let vec: Vec<String> = contact_list
.into_iter() .into_iter()
.map(|f| f.public_key.to_hex()) .map(|f| f.public_key.to_hex())
@@ -152,8 +152,8 @@ pub async fn set_profile(profile: Profile, state: State<'_, Nostr>) -> Result<St
#[tauri::command] #[tauri::command]
#[specta::specta] #[specta::specta]
pub async fn check_contact(id: String, state: State<'_, Nostr>) -> Result<bool, String> { pub fn check_contact(id: String, state: State<'_, Nostr>) -> Result<bool, String> {
let contact_list = &state.contact_list.lock().await; let contact_list = &state.contact_list.lock().unwrap();
let public_key = PublicKey::from_str(&id).map_err(|e| e.to_string())?; let public_key = PublicKey::from_str(&id).map_err(|e| e.to_string())?;
match contact_list.iter().position(|x| x.public_key == public_key) { match contact_list.iter().position(|x| x.public_key == public_key) {
@@ -577,8 +577,8 @@ pub async fn get_notifications(state: State<'_, Nostr>) -> Result<Vec<String>, S
#[tauri::command] #[tauri::command]
#[specta::specta] #[specta::specta]
pub async fn get_user_settings(state: State<'_, Nostr>) -> Result<Settings, ()> { pub fn get_user_settings(state: State<'_, Nostr>) -> Result<Settings, String> {
Ok(state.settings.lock().await.clone()) Ok(state.settings.lock().unwrap().clone())
} }
#[tauri::command] #[tauri::command]
@@ -597,7 +597,7 @@ pub async fn set_user_settings(
let parsed: Settings = serde_json::from_str(&settings).map_err(|e| e.to_string())?; let parsed: Settings = serde_json::from_str(&settings).map_err(|e| e.to_string())?;
// Update state // Update state
state.settings.lock().await.clone_from(&parsed); state.settings.lock().unwrap().clone_from(&parsed);
// Emit new changes to frontend // Emit new changes to frontend
NewSettings(parsed).emit(&handle).unwrap(); NewSettings(parsed).emit(&handle).unwrap();
@@ -622,8 +622,8 @@ pub async fn verify_nip05(id: String, nip05: &str) -> Result<bool, String> {
#[tauri::command] #[tauri::command]
#[specta::specta] #[specta::specta]
pub async fn is_trusted_user(id: String, state: State<'_, Nostr>) -> Result<bool, String> { pub fn is_trusted_user(id: String, state: State<'_, Nostr>) -> Result<bool, String> {
let trusted_list = &state.trusted_list.lock().await; let trusted_list = &state.trusted_list.lock().unwrap();
let public_key = PublicKey::from_str(&id).map_err(|e| e.to_string())?; let public_key = PublicKey::from_str(&id).map_err(|e| e.to_string())?;
Ok(trusted_list.contains(&public_key)) Ok(trusted_list.contains(&public_key))

View File

@@ -16,13 +16,13 @@ use std::{
fs, fs,
io::{self, BufRead}, io::{self, BufRead},
str::FromStr, str::FromStr,
sync::Mutex,
time::Duration, time::Duration,
}; };
use tauri::{path::BaseDirectory, Emitter, EventTarget, Manager}; use tauri::{path::BaseDirectory, Emitter, EventTarget, Manager};
use tauri_plugin_decorum::WebviewWindowExt; use tauri_plugin_decorum::WebviewWindowExt;
use tauri_plugin_notification::{NotificationExt, PermissionState}; use tauri_plugin_notification::{NotificationExt, PermissionState};
use tauri_specta::{collect_commands, collect_events, Builder, Event as TauriEvent}; use tauri_specta::{collect_commands, collect_events, Builder, Event as TauriEvent};
use tokio::sync::Mutex;
pub mod commands; pub mod commands;
pub mod common; pub mod common;
@@ -317,11 +317,7 @@ fn main() {
} }
} }
None => { None => {
let contact_list = client let contact_list = state.contact_list.lock().unwrap().clone();
.get_contact_list(Some(Duration::from_secs(5)))
.await
.unwrap();
if !contact_list.is_empty() { if !contact_list.is_empty() {
let authors: Vec<PublicKey> = let authors: Vec<PublicKey> =
contact_list.iter().map(|f| f.public_key).collect(); contact_list.iter().map(|f| f.public_key).collect();

View File

@@ -270,7 +270,7 @@ async getNotifications() : Promise<Result<string[], string>> {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getUserSettings() : Promise<Result<Settings, null>> { async getUserSettings() : Promise<Result<Settings, string>> {
try { try {
return { status: "ok", data: await TAURI_INVOKE("get_user_settings") }; return { status: "ok", data: await TAURI_INVOKE("get_user_settings") };
} catch (e) { } catch (e) {

View File

@@ -98,33 +98,47 @@ function Content({ text, className }: { text: string; className?: string }) {
)); ));
for (const word of nostr) { for (const word of nostr) {
const bech32 = word.replace("nostr:", ""); const bech32 = word.replace("nostr:", "").replace(/[^\w\s]/gi, "");
const data = nip19.decode(bech32); try {
const data = nip19.decode(bech32);
switch (data.type) { switch (data.type) {
case "npub": case "npub":
replacedText = reactStringReplace(replacedText, word, (match, i) => ( replacedText = reactStringReplace(
<MentionUser key={match + i} pubkey={data.data} /> replacedText,
)); word,
break; (match, i) => <MentionUser key={match + i} pubkey={data.data} />,
case "nprofile": );
replacedText = reactStringReplace(replacedText, word, (match, i) => ( break;
<MentionUser key={match + i} pubkey={data.data.pubkey} /> case "nprofile":
)); replacedText = reactStringReplace(
break; replacedText,
default: word,
replacedText = reactStringReplace(replacedText, word, (match, i) => ( (match, i) => (
<a <MentionUser key={match + i} pubkey={data.data.pubkey} />
key={match + i} ),
href={`https://njump.me/${bech32}`} );
target="_blank" break;
rel="noreferrer" default:
className="text-blue-600 dark:text-blue-400 !underline" replacedText = reactStringReplace(
> replacedText,
{match} word,
</a> (match, i) => (
)); <a
break; key={match + i}
href={`https://njump.me/${bech32}`}
target="_blank"
rel="noreferrer"
className="text-blue-600 dark:text-blue-400 !underline"
>
{match}
</a>
),
);
break;
}
} catch {
console.log(word);
} }
} }

View File

@@ -188,33 +188,48 @@ function Content({ text, className }: { text: string; className?: string }) {
)); ));
for (const word of nostr) { for (const word of nostr) {
const bech32 = word.replace("nostr:", ""); const bech32 = word.replace("nostr:", "").replace(/[^\w\s]/gi, "");
const data = nip19.decode(bech32);
switch (data.type) { try {
case "npub": const data = nip19.decode(bech32);
replacedText = reactStringReplace(replacedText, word, (match, i) => (
<MentionUser key={match + i} pubkey={data.data} /> switch (data.type) {
)); case "npub":
break; replacedText = reactStringReplace(
case "nprofile": replacedText,
replacedText = reactStringReplace(replacedText, word, (match, i) => ( word,
<MentionUser key={match + i} pubkey={data.data.pubkey} /> (match, i) => <MentionUser key={match + i} pubkey={data.data} />,
)); );
break; break;
default: case "nprofile":
replacedText = reactStringReplace(replacedText, word, (match, i) => ( replacedText = reactStringReplace(
<a replacedText,
key={match + i} word,
href={`https://njump.me/${bech32}`} (match, i) => (
target="_blank" <MentionUser key={match + i} pubkey={data.data.pubkey} />
rel="noreferrer" ),
className="text-blue-600 dark:text-blue-400 !underline" );
> break;
{match} default:
</a> replacedText = reactStringReplace(
)); replacedText,
break; word,
(match, i) => (
<a
key={match + i}
href={`https://njump.me/${bech32}`}
target="_blank"
rel="noreferrer"
className="text-blue-600 dark:text-blue-400 !underline"
>
{match}
</a>
),
);
break;
}
} catch {
console.log(word);
} }
} }