chore: update gpui and nostr-sdk
This commit is contained in:
66
Cargo.lock
generated
66
Cargo.lock
generated
@@ -1079,7 +1079,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collections"
|
name = "collections"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
@@ -1412,9 +1412,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crunchy"
|
name = "crunchy"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
@@ -1477,7 +1477,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_refineable"
|
name = "derive_refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2318,7 +2318,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui"
|
name = "gpui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
@@ -2411,7 +2411,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_macros"
|
name = "gpui_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -2634,7 +2634,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "http_client"
|
name = "http_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2651,7 +2651,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "http_client_tls"
|
name = "http_client_tls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-platform-verifier",
|
"rustls-platform-verifier",
|
||||||
@@ -2699,7 +2699,6 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"webpki-roots 1.0.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2940,9 +2939,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.4",
|
"hashbrown 0.15.4",
|
||||||
@@ -3209,9 +3208,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -3386,7 +3385,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "media"
|
name = "media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bindgen 0.71.1",
|
"bindgen 0.71.1",
|
||||||
@@ -3600,8 +3599,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr"
|
name = "nostr"
|
||||||
version = "0.42.1"
|
version = "0.42.1"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -3613,8 +3611,6 @@ dependencies = [
|
|||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
"instant",
|
"instant",
|
||||||
"regex",
|
|
||||||
"reqwest 0.12.20",
|
|
||||||
"scrypt",
|
"scrypt",
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3626,8 +3622,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-connect"
|
name = "nostr-connect"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -3639,8 +3634,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-database"
|
name = "nostr-database"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flatbuffers",
|
"flatbuffers",
|
||||||
"lru",
|
"lru",
|
||||||
@@ -3651,8 +3645,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-lmdb"
|
name = "nostr-lmdb"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"heed",
|
"heed",
|
||||||
@@ -3665,8 +3658,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-relay-pool"
|
name = "nostr-relay-pool"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"async-wsocket",
|
"async-wsocket",
|
||||||
@@ -3682,8 +3674,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-sdk"
|
name = "nostr-sdk"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#ecf711ee9f3bca83c2a31a1de0f2977cd2845af5"
|
source = "git+https://github.com/rust-nostr/nostr#d7b4e225704337be23b54cde8d91458972ac87c8"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -3691,7 +3682,6 @@ dependencies = [
|
|||||||
"nostr-lmdb",
|
"nostr-lmdb",
|
||||||
"nostr-relay-pool",
|
"nostr-relay-pool",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4719,7 +4709,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "refineable"
|
name = "refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_refineable",
|
"derive_refineable",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
@@ -4828,8 +4818,6 @@ dependencies = [
|
|||||||
"native-tls",
|
"native-tls",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn",
|
|
||||||
"rustls",
|
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -4837,7 +4825,6 @@ dependencies = [
|
|||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
"tokio-rustls",
|
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
@@ -4847,13 +4834,12 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasm-streams",
|
"wasm-streams",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots 1.0.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest_client"
|
name = "reqwest_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -5324,7 +5310,7 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "semantic_version"
|
name = "semantic_version"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -5687,7 +5673,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sum_tree"
|
name = "sum_tree"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -6601,7 +6587,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#108162423da6d5d37bd78bffed74e7ebc2e8a83b"
|
source = "git+https://github.com/zed-industries/zed#c3d0230f89ff21257d965d4c410a274e52c4fe35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-fs",
|
"async-fs",
|
||||||
@@ -7108,9 +7094,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-capture"
|
name = "windows-capture"
|
||||||
version = "1.4.4"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "757c9e7b920233fec91cb314ad92b96853ba2907e3482a193d290d33838e3fc5"
|
checksum = "3a4df73e95feddb9ec1a7e9c2ca6323b8c97d5eeeff78d28f1eccdf19c882b24"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
10
Cargo.toml
10
Cargo.toml
@@ -17,11 +17,17 @@ reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
|||||||
|
|
||||||
# Nostr
|
# Nostr
|
||||||
nostr = { git = "https://github.com/rust-nostr/nostr" }
|
nostr = { git = "https://github.com/rust-nostr/nostr" }
|
||||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = ["lmdb", "nip96", "nip59", "nip49", "nip44"] }
|
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = [
|
||||||
|
"lmdb",
|
||||||
|
"nip96",
|
||||||
|
"nip59",
|
||||||
|
"nip49",
|
||||||
|
"nip44",
|
||||||
|
] }
|
||||||
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
reqwest = { version = "0.12", features = ["stream"] }
|
reqwest = { version = "0.12", features = ["multipart", "stream", "json"] }
|
||||||
emojis = "0.6.4"
|
emojis = "0.6.4"
|
||||||
smol = "2"
|
smol = "2"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl Drop for MacOsUnmounter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("Error while trying to unmount disk image: {:?}", error);
|
log::error!("Error while trying to unmount disk image: {error:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ impl AutoUpdater {
|
|||||||
target_file.write_all(&chunk).await?;
|
target_file.write_all(&chunk).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("downloaded update. path:{:?}", downloaded_asset);
|
log::info!("downloaded update. path: {downloaded_asset:?}");
|
||||||
|
|
||||||
Ok((temp_dir, downloaded_asset))
|
Ok((temp_dir, downloaded_asset))
|
||||||
} else {
|
} else {
|
||||||
@@ -271,7 +271,7 @@ impl AutoUpdater {
|
|||||||
let from = extracted.join(&app_folder_name);
|
let from = extracted.join(&app_folder_name);
|
||||||
let mut to = home_dir.join(".local");
|
let mut to = home_dir.join(".local");
|
||||||
|
|
||||||
let expected_suffix = format!("{}/libexec/coop", app_folder_name);
|
let expected_suffix = format!("{app_folder_name}/libexec/coop");
|
||||||
|
|
||||||
if let Some(prefix) = running_app_path
|
if let Some(prefix) = running_app_path
|
||||||
.to_str()
|
.to_str()
|
||||||
|
|||||||
@@ -2,48 +2,17 @@ use std::collections::HashSet;
|
|||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, Error, Result};
|
|
||||||
use gpui::{Image, ImageFormat};
|
use gpui::{Image, ImageFormat};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use qrcode_generator::QrCodeEcc;
|
use qrcode_generator::QrCodeEcc;
|
||||||
use reqwest::Client as ReqClient;
|
|
||||||
|
|
||||||
pub mod debounced_delay;
|
pub mod debounced_delay;
|
||||||
pub mod handle_auth;
|
pub mod handle_auth;
|
||||||
|
pub mod nip05;
|
||||||
|
pub mod nip96;
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
|
|
||||||
pub async fn verify_nip05(public_key: PublicKey, address: &str) -> Result<bool, Error> {
|
|
||||||
let req_client = ReqClient::new();
|
|
||||||
let address = Nip05Address::parse(address)?;
|
|
||||||
let res = req_client.get(address.url().to_string()).send().await?;
|
|
||||||
let json: Value = res.json().await?;
|
|
||||||
let verify = nip05::verify_from_json(&public_key, &address, &json);
|
|
||||||
|
|
||||||
Ok(verify)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn nip05_profile(address: &str) -> Result<Nip05Profile, Error> {
|
|
||||||
let req_client = ReqClient::new();
|
|
||||||
let address = Nip05Address::parse(address)?;
|
|
||||||
let res = req_client.get(address.url().to_string()).send().await?;
|
|
||||||
let json: Value = res.json().await?;
|
|
||||||
|
|
||||||
if let Ok(profile) = Nip05Profile::from_json(&address, &json) {
|
|
||||||
Ok(profile)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("Failed to get NIP-05 profile"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn nip96_upload(client: &Client, server: Url, file: Vec<u8>) -> Result<Url, Error> {
|
|
||||||
let signer = client.signer().await?;
|
|
||||||
let config = nip96::get_server_config(server.to_owned(), None).await?;
|
|
||||||
let url = nip96::upload_data(&signer, &config, file, None, None).await?;
|
|
||||||
|
|
||||||
Ok(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn room_hash(event: &Event) -> u64 {
|
pub fn room_hash(event: &Event) -> u64 {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
let mut pubkeys: Vec<PublicKey> = vec![];
|
let mut pubkeys: Vec<PublicKey> = vec![];
|
||||||
|
|||||||
31
crates/common/src/nip05.rs
Normal file
31
crates/common/src/nip05.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use nostr::prelude::*;
|
||||||
|
use reqwest::Client as ReqClient;
|
||||||
|
|
||||||
|
pub async fn nip05_verify(public_key: PublicKey, address: &str) -> Result<bool, anyhow::Error> {
|
||||||
|
let req_client = ReqClient::new();
|
||||||
|
let address = Nip05Address::parse(address)?;
|
||||||
|
|
||||||
|
// Get NIP-05 response
|
||||||
|
let res = req_client.get(address.url().to_string()).send().await?;
|
||||||
|
let json: Value = res.json().await?;
|
||||||
|
|
||||||
|
let verify = nip05::verify_from_json(&public_key, &address, &json);
|
||||||
|
|
||||||
|
Ok(verify)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn nip05_profile(address: &str) -> Result<Nip05Profile, anyhow::Error> {
|
||||||
|
let req_client = ReqClient::new();
|
||||||
|
let address = Nip05Address::parse(address)?;
|
||||||
|
|
||||||
|
// Get NIP-05 response
|
||||||
|
let res = req_client.get(address.url().to_string()).send().await?;
|
||||||
|
let json: Value = res.json().await?;
|
||||||
|
|
||||||
|
if let Ok(profile) = Nip05Profile::from_json(&address, &json) {
|
||||||
|
Ok(profile)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Failed to get NIP-05 profile"))
|
||||||
|
}
|
||||||
|
}
|
||||||
82
crates/common/src/nip96.rs
Normal file
82
crates/common/src/nip96.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use nostr::hashes::sha256::Hash as Sha256Hash;
|
||||||
|
use nostr::hashes::Hash;
|
||||||
|
use nostr::prelude::*;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use reqwest::multipart;
|
||||||
|
use reqwest::Client as ReqClient;
|
||||||
|
use reqwest::Response;
|
||||||
|
|
||||||
|
pub(crate) fn make_multipart_form(
|
||||||
|
file_data: Vec<u8>,
|
||||||
|
mime_type: Option<&str>,
|
||||||
|
) -> Result<multipart::Form, anyhow::Error> {
|
||||||
|
let form_file_part = multipart::Part::bytes(file_data).file_name("filename");
|
||||||
|
|
||||||
|
// Set the part's MIME type, or leave it as is if mime_type is None
|
||||||
|
|
||||||
|
let part = match mime_type {
|
||||||
|
Some(mime) => form_file_part.mime_str(mime)?,
|
||||||
|
None => form_file_part,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(multipart::Form::new().part("file", part))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn upload<T>(
|
||||||
|
signer: &T,
|
||||||
|
desc: &ServerConfig,
|
||||||
|
file_data: Vec<u8>,
|
||||||
|
mime_type: Option<&str>,
|
||||||
|
) -> Result<Url, anyhow::Error>
|
||||||
|
where
|
||||||
|
T: NostrSigner,
|
||||||
|
{
|
||||||
|
let payload: Sha256Hash = Sha256Hash::hash(&file_data);
|
||||||
|
let data: HttpData = HttpData::new(desc.api_url.clone(), HttpMethod::POST).payload(payload);
|
||||||
|
let nip98_auth: String = data.to_authorization(signer).await?;
|
||||||
|
|
||||||
|
// Make form
|
||||||
|
let form: multipart::Form = make_multipart_form(file_data, mime_type)?;
|
||||||
|
|
||||||
|
// Make req client
|
||||||
|
let req_client = ReqClient::new();
|
||||||
|
|
||||||
|
// Send
|
||||||
|
let response: Response = req_client
|
||||||
|
.post(desc.api_url.clone())
|
||||||
|
.header("Authorization", nip98_auth)
|
||||||
|
.multipart(form)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Parse response
|
||||||
|
let json: Value = response.json().await?;
|
||||||
|
let upload_response = nip96::UploadResponse::from_json(json.to_string())?;
|
||||||
|
|
||||||
|
if upload_response.status == UploadResponseStatus::Error {
|
||||||
|
return Err(anyhow!(upload_response.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(upload_response.download_url()?.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn nip96_upload(
|
||||||
|
client: &Client,
|
||||||
|
server: &Url,
|
||||||
|
file: Vec<u8>,
|
||||||
|
) -> Result<Url, anyhow::Error> {
|
||||||
|
let req_client = ReqClient::new();
|
||||||
|
let config_url = nip96::get_server_config_url(server)?;
|
||||||
|
|
||||||
|
// Get
|
||||||
|
let res = req_client.get(config_url.to_string()).send().await?;
|
||||||
|
let json: Value = res.json().await?;
|
||||||
|
|
||||||
|
let config = nip96::ServerConfig::from_json(json.to_string())?;
|
||||||
|
let signer = client.signer().await?;
|
||||||
|
|
||||||
|
let url = upload(&signer, &config, file, None).await?;
|
||||||
|
|
||||||
|
Ok(url)
|
||||||
|
}
|
||||||
@@ -18,8 +18,7 @@ impl RenderProfile for Profile {
|
|||||||
.map(|picture| {
|
.map(|picture| {
|
||||||
if proxy {
|
if proxy {
|
||||||
format!(
|
format!(
|
||||||
"{}/?url={}&w=100&h=100&fit=cover&mask=circle&default={}&n=-1",
|
"{IMAGE_RESIZE_SERVICE}/?url={picture}&w=100&h=100&fit=cover&mask=circle&default={FALLBACK_IMG}&n=-1"
|
||||||
IMAGE_RESIZE_SERVICE, picture, FALLBACK_IMG
|
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use chats::message::Message;
|
use chats::message::Message;
|
||||||
use chats::room::{Room, RoomKind, SendError};
|
use chats::room::{Room, RoomKind, SendError};
|
||||||
use common::nip96_upload;
|
use common::nip96::nip96_upload;
|
||||||
use common::profile::RenderProfile;
|
use common::profile::RenderProfile;
|
||||||
use global::shared_state;
|
use global::shared_state;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
@@ -390,16 +390,9 @@ impl Chat {
|
|||||||
|
|
||||||
// Spawn task via async utility instead of GPUI context
|
// Spawn task via async utility instead of GPUI context
|
||||||
nostr_sdk::async_utility::task::spawn(async move {
|
nostr_sdk::async_utility::task::spawn(async move {
|
||||||
let url = match nip96_upload(shared_state().client(), nip96, file_data)
|
let url = nip96_upload(shared_state().client(), &nip96, file_data)
|
||||||
.await
|
.await
|
||||||
{
|
.ok();
|
||||||
Ok(url) => Some(url),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Upload error: {e}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = tx.send(url);
|
_ = tx.send(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::time::Duration;
|
|||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use chats::room::{Room, RoomKind};
|
use chats::room::{Room, RoomKind};
|
||||||
use chats::ChatRegistry;
|
use chats::ChatRegistry;
|
||||||
use common::nip05_profile;
|
use common::nip05::nip05_profile;
|
||||||
use common::profile::RenderProfile;
|
use common::profile::RenderProfile;
|
||||||
use global::shared_state;
|
use global::shared_state;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
|
|||||||
@@ -592,8 +592,7 @@ impl Render for Login {
|
|||||||
.text_center()
|
.text_center()
|
||||||
.text_color(cx.theme().text_muted)
|
.text_color(cx.theme().text_muted)
|
||||||
.child(SharedString::from(format!(
|
.child(SharedString::from(format!(
|
||||||
"Approve connection request from your signer in {} seconds",
|
"Approve connection request from your signer in {i} seconds"
|
||||||
i
|
|
||||||
))),
|
))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use common::nip96_upload;
|
use common::nip96::nip96_upload;
|
||||||
use global::shared_state;
|
use global::shared_state;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -158,7 +158,7 @@ impl NewAccount {
|
|||||||
|
|
||||||
nostr_sdk::async_utility::task::spawn(async move {
|
nostr_sdk::async_utility::task::spawn(async move {
|
||||||
if let Ok(url) =
|
if let Ok(url) =
|
||||||
nip96_upload(shared_state().client(), nip96, file_data).await
|
nip96_upload(shared_state().client(), &nip96, file_data).await
|
||||||
{
|
{
|
||||||
_ = tx.send(url);
|
_ = tx.send(url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use common::nip96_upload;
|
use common::nip96::nip96_upload;
|
||||||
use global::shared_state;
|
use global::shared_state;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
@@ -104,7 +104,7 @@ impl Profile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upload(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn upload(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let nip96 = AppSettings::get_global(cx).settings.media_server.clone();
|
let nip96_server = AppSettings::get_global(cx).settings.media_server.clone();
|
||||||
let avatar_input = self.avatar_input.downgrade();
|
let avatar_input = self.avatar_input.downgrade();
|
||||||
let paths = cx.prompt_for_paths(PathPromptOptions {
|
let paths = cx.prompt_for_paths(PathPromptOptions {
|
||||||
files: true,
|
files: true,
|
||||||
@@ -125,7 +125,8 @@ impl Profile {
|
|||||||
|
|
||||||
nostr_sdk::async_utility::task::spawn(async move {
|
nostr_sdk::async_utility::task::spawn(async move {
|
||||||
if let Ok(url) =
|
if let Ok(url) =
|
||||||
nip96_upload(shared_state().client(), nip96, file_data).await
|
nip96_upload(shared_state().client(), &nip96_server, file_data)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
_ = tx.send(url);
|
_ = tx.send(url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ impl Relays {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if let Err(e) = client.send_event_builder(builder).await {
|
if let Err(e) = client.send_event_builder(builder).await {
|
||||||
log::error!("Failed to send relay list event: {}", e);
|
log::error!("Failed to send relay list event: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ impl Relays {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
log::error!("Failed to subscribe to new messages: {}", e);
|
log::error!("Failed to subscribe to new messages: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(output.val)
|
Ok(output.val)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use anyhow::Error;
|
|||||||
use chats::room::{Room, RoomKind};
|
use chats::room::{Room, RoomKind};
|
||||||
use chats::{ChatRegistry, RoomEmitter};
|
use chats::{ChatRegistry, RoomEmitter};
|
||||||
use common::debounced_delay::DebouncedDelay;
|
use common::debounced_delay::DebouncedDelay;
|
||||||
|
use common::nip05::nip05_verify;
|
||||||
use common::profile::RenderProfile;
|
use common::profile::RenderProfile;
|
||||||
use common::verify_nip05;
|
|
||||||
use element::DisplayRoom;
|
use element::DisplayRoom;
|
||||||
use global::constants::{DEFAULT_MODAL_WIDTH, SEARCH_RELAYS};
|
use global::constants::{DEFAULT_MODAL_WIDTH, SEARCH_RELAYS};
|
||||||
use global::shared_state;
|
use global::shared_state;
|
||||||
@@ -185,7 +185,7 @@ impl Sidebar {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !verify_nip05(event.pubkey, target).await.unwrap_or(false) {
|
if !nip05_verify(event.pubkey, target).await.unwrap_or(false) {
|
||||||
// Skip if NIP-05 is not valid or failed to verify
|
// Skip if NIP-05 is not valid or failed to verify
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -218,7 +218,7 @@ impl Sidebar {
|
|||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
if result.is_empty() {
|
if result.is_empty() {
|
||||||
let msg =
|
let msg =
|
||||||
format!("There are no users matching query {}", query_cloned);
|
format!("There are no users matching query {query_cloned}");
|
||||||
window.push_notification(Notification::info(msg), cx);
|
window.push_notification(Notification::info(msg), cx);
|
||||||
this.set_finding(false, cx);
|
this.set_finding(false, cx);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -369,13 +369,13 @@ impl Globals {
|
|||||||
pub(crate) async fn connect(&self) {
|
pub(crate) async fn connect(&self) {
|
||||||
for relay in BOOTSTRAP_RELAYS.into_iter() {
|
for relay in BOOTSTRAP_RELAYS.into_iter() {
|
||||||
if let Err(e) = self.client.add_relay(relay).await {
|
if let Err(e) = self.client.add_relay(relay).await {
|
||||||
log::error!("Failed to add relay {}: {}", relay, e);
|
log::error!("Failed to add relay {relay}: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for relay in SEARCH_RELAYS.into_iter() {
|
for relay in SEARCH_RELAYS.into_iter() {
|
||||||
if let Err(e) = self.client.add_relay(relay).await {
|
if let Err(e) = self.client.add_relay(relay).await {
|
||||||
log::error!("Failed to add relay {}: {}", relay, e);
|
log::error!("Failed to add relay {relay}: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +470,7 @@ impl Globals {
|
|||||||
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
|
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
log::error!("Failed to subscribe for app updates: {}", e);
|
log::error!("Failed to subscribe for app updates: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Subscribed to app updates");
|
log::info!("Subscribed to app updates");
|
||||||
@@ -623,7 +623,7 @@ impl Globals {
|
|||||||
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
|
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
log::error!("Failed to subscribe for file metadata: {}", e);
|
log::error!("Failed to subscribe for file metadata: {e}");
|
||||||
} else {
|
} else {
|
||||||
self.send_signal(NostrSignal::AppUpdate(event.to_owned()))
|
self.send_signal(NostrSignal::AppUpdate(event.to_owned()))
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ impl Identity {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Err(e) = client.send_event_builder(builder).await {
|
if let Err(e) = client.send_event_builder(builder).await {
|
||||||
log::error!("Failed to send relay list event: {}", e);
|
log::error!("Failed to send relay list event: {e}");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create messaging relay list
|
// Create messaging relay list
|
||||||
@@ -423,7 +423,7 @@ impl Identity {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Err(e) = client.send_event_builder(builder).await {
|
if let Err(e) = client.send_event_builder(builder).await {
|
||||||
log::error!("Failed to send messaging relay list event: {}", e);
|
log::error!("Failed to send messaging relay list event: {e}");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subscribe for user's data
|
// Subscribe for user's data
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ impl TabPanel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
Button::new(SharedString::from(format!("toggle-dock:{:?}", placement)))
|
Button::new(SharedString::from(format!("toggle-dock:{placement:?}")))
|
||||||
.icon(icon)
|
.icon(icon)
|
||||||
.small()
|
.small()
|
||||||
.ghost()
|
.ghost()
|
||||||
|
|||||||
@@ -102,11 +102,11 @@ impl RenderOnce for EmojiPicker {
|
|||||||
input.update(cx, |this, cx| {
|
input.update(cx, |this, cx| {
|
||||||
let current = this.value();
|
let current = this.value();
|
||||||
let new_text = if current.is_empty() {
|
let new_text = if current.is_empty() {
|
||||||
format!("{}", item)
|
format!("{item}")
|
||||||
} else if current.ends_with(" ") {
|
} else if current.ends_with(" ") {
|
||||||
format!("{}{}", current, item)
|
format!("{current}{item}")
|
||||||
} else {
|
} else {
|
||||||
format!("{} {}", current, item)
|
format!("{current} {item}")
|
||||||
};
|
};
|
||||||
this.set_value(new_text, window, cx);
|
this.set_value(new_text, window, cx);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ impl MaskPattern {
|
|||||||
if fraction == &Some(0) {
|
if fraction == &Some(0) {
|
||||||
int_with_sep
|
int_with_sep
|
||||||
} else {
|
} else {
|
||||||
format!("{}.{}", int_with_sep, frac)
|
format!("{int_with_sep}.{frac}")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int_with_sep
|
int_with_sep
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ pub trait PopupMenuExt: Styled + Selectable + IntoElement + 'static {
|
|||||||
let style = self.style().clone();
|
let style = self.style().clone();
|
||||||
let element_id = self.element_id();
|
let element_id = self.element_id();
|
||||||
|
|
||||||
Popover::new(SharedString::from(format!("popup-menu:{:?}", element_id)))
|
Popover::new(SharedString::from(format!("popup-menu:{element_id:?}")))
|
||||||
.no_style()
|
.no_style()
|
||||||
.trigger(self)
|
.trigger(self)
|
||||||
.trigger_style(style)
|
.trigger_style(style)
|
||||||
@@ -716,7 +716,7 @@ impl Render for PopupMenu {
|
|||||||
/// Return the Platform specific keybinding string by KeyStroke
|
/// Return the Platform specific keybinding string by KeyStroke
|
||||||
pub fn key_shortcut(key: Keystroke) -> String {
|
pub fn key_shortcut(key: Keystroke) -> String {
|
||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
return format!("{}", key);
|
return format!("{key}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parts = vec![];
|
let mut parts = vec![];
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ pub fn render_plain_text_mut(
|
|||||||
|
|
||||||
// Make it clickable
|
// Make it clickable
|
||||||
link_ranges.push(new_range);
|
link_ranges.push(new_range);
|
||||||
link_urls.push(format!("mention:{}", entity_without_prefix));
|
link_urls.push(format!("mention:{entity_without_prefix}"));
|
||||||
|
|
||||||
// Adjust subsequent ranges if needed
|
// Adjust subsequent ranges if needed
|
||||||
if length_diff != 0 {
|
if length_diff != 0 {
|
||||||
@@ -301,11 +301,11 @@ pub fn render_plain_text_mut(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No profile match or not a profile entity - create njump.me link
|
// No profile match or not a profile entity - create njump.me link
|
||||||
let njump_url = format!("https://njump.me/{}", entity_without_prefix);
|
let njump_url = format!("https://njump.me/{entity_without_prefix}");
|
||||||
|
|
||||||
// Create a shortened display format for the URL
|
// Create a shortened display format for the URL
|
||||||
let shortened_entity = format_shortened_entity(entity_without_prefix);
|
let shortened_entity = format_shortened_entity(entity_without_prefix);
|
||||||
let display_text = format!("https://njump.me/{}", shortened_entity);
|
let display_text = format!("https://njump.me/{shortened_entity}");
|
||||||
|
|
||||||
// Replace the original entity with the shortened display version
|
// Replace the original entity with the shortened display version
|
||||||
text.replace_range(range.clone(), &display_text);
|
text.replace_range(range.clone(), &display_text);
|
||||||
@@ -350,7 +350,7 @@ fn format_shortened_entity(entity: &str) -> String {
|
|||||||
let prefix = &entity[0..=prefix_end]; // Include the '1'
|
let prefix = &entity[0..=prefix_end]; // Include the '1'
|
||||||
let suffix = &entity[entity.len() - 4..]; // Last 4 chars
|
let suffix = &entity[entity.len() - 4..]; // Last 4 chars
|
||||||
|
|
||||||
format!("{}...{}", prefix, suffix)
|
format!("{prefix}...{suffix}")
|
||||||
} else {
|
} else {
|
||||||
entity.to_string()
|
entity.to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
10
rust-toolchain.toml
Normal file
10
rust-toolchain.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.88"
|
||||||
|
profile = "minimal"
|
||||||
|
components = ["rustfmt", "clippy"]
|
||||||
|
targets = [
|
||||||
|
"x86_64-apple-darwin",
|
||||||
|
"aarch64-apple-darwin",
|
||||||
|
"x86_64-unknown-linux-gnu",
|
||||||
|
"x86_64-pc-windows-msvc",
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user