update issue template and clippy for hbb_common

This commit is contained in:
rustdesk 2023-02-08 17:26:44 +08:00
parent 4539ad53e1
commit 7c13be5876
10 changed files with 103 additions and 98 deletions

View File

@ -30,13 +30,22 @@ body:
description: A clear and concise description of what you expected to happen description: A clear and concise description of what you expected to happen
validations: validations:
required: true required: true
- type: input
id: os
attributes:
label: Operating system(s) on local side and remote side
description: What operating system(s) do you see this bug on? local side -> remote side.
placeholder: |
Windows 10 -> osx
validations:
required: true
- type: input - type: input
id: version id: version
attributes: attributes:
label: Operating System(s) and RustDesk Version(s) on local side and remote side label: RustDesk Version(s) on local side and remote side
description: What Operatiing System(s) and version(s) of RustDesk do you see this bug on? local side / remote side. description: What RustDesk version(s) do you see this bug on? local side -> remote side.
placeholder: | placeholder: |
Windows 10, 1.1.9 / osx 13.1, 1.1.8 1.1.9 -> 1.1.8
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@ -2,11 +2,11 @@ fn main() {
let out_dir = format!("{}/protos", std::env::var("OUT_DIR").unwrap()); let out_dir = format!("{}/protos", std::env::var("OUT_DIR").unwrap());
std::fs::create_dir_all(&out_dir).unwrap(); std::fs::create_dir_all(&out_dir).unwrap();
protobuf_codegen::Codegen::new() protobuf_codegen::Codegen::new()
.pure() .pure()
.out_dir(out_dir) .out_dir(out_dir)
.inputs(&["protos/rendezvous.proto", "protos/message.proto"]) .inputs(["protos/rendezvous.proto", "protos/message.proto"])
.include("protos") .include("protos")
.customize(protobuf_codegen::Customize::default().tokio_bytes(true)) .customize(protobuf_codegen::Customize::default().tokio_bytes(true))
.run() .run()

View File

@ -143,32 +143,32 @@ mod tests {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
bytes.resize(0x3F, 1); bytes.resize(0x3F, 1);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
let buf_saved = buf.clone(); let buf_saved = buf.clone();
assert_eq!(buf.len(), 0x3F + 1); assert_eq!(buf.len(), 0x3F + 1);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3F); assert_eq!(res.len(), 0x3F);
assert_eq!(res[0], 1); assert_eq!(res[0], 1);
} else { } else {
assert!(false); panic!();
} }
let mut codec2 = BytesCodec::new(); let mut codec2 = BytesCodec::new();
let mut buf2 = BytesMut::new(); let mut buf2 = BytesMut::new();
if let Ok(None) = codec2.decode(&mut buf2) { if let Ok(None) = codec2.decode(&mut buf2) {
} else { } else {
assert!(false); panic!();
} }
buf2.extend(&buf_saved[0..1]); buf2.extend(&buf_saved[0..1]);
if let Ok(None) = codec2.decode(&mut buf2) { if let Ok(None) = codec2.decode(&mut buf2) {
} else { } else {
assert!(false); panic!();
} }
buf2.extend(&buf_saved[1..]); buf2.extend(&buf_saved[1..]);
if let Ok(Some(res)) = codec2.decode(&mut buf2) { if let Ok(Some(res)) = codec2.decode(&mut buf2) {
assert_eq!(res.len(), 0x3F); assert_eq!(res.len(), 0x3F);
assert_eq!(res[0], 1); assert_eq!(res[0], 1);
} else { } else {
assert!(false); panic!();
} }
} }
@ -177,21 +177,21 @@ mod tests {
let mut codec = BytesCodec::new(); let mut codec = BytesCodec::new();
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
assert!(!codec.encode("".into(), &mut buf).is_err()); assert!(codec.encode("".into(), &mut buf).is_ok());
assert_eq!(buf.len(), 1); assert_eq!(buf.len(), 1);
bytes.resize(0x3F + 1, 2); bytes.resize(0x3F + 1, 2);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
assert_eq!(buf.len(), 0x3F + 2 + 2); assert_eq!(buf.len(), 0x3F + 2 + 2);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0); assert_eq!(res.len(), 0);
} else { } else {
assert!(false); panic!();
} }
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3F + 1); assert_eq!(res.len(), 0x3F + 1);
assert_eq!(res[0], 2); assert_eq!(res[0], 2);
} else { } else {
assert!(false); panic!();
} }
} }
@ -201,13 +201,13 @@ mod tests {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
bytes.resize(0x3F - 1, 3); bytes.resize(0x3F - 1, 3);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
assert_eq!(buf.len(), 0x3F + 1 - 1); assert_eq!(buf.len(), 0x3F + 1 - 1);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3F - 1); assert_eq!(res.len(), 0x3F - 1);
assert_eq!(res[0], 3); assert_eq!(res[0], 3);
} else { } else {
assert!(false); panic!();
} }
} }
#[test] #[test]
@ -216,13 +216,13 @@ mod tests {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
bytes.resize(0x3FFF, 4); bytes.resize(0x3FFF, 4);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
assert_eq!(buf.len(), 0x3FFF + 2); assert_eq!(buf.len(), 0x3FFF + 2);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3FFF); assert_eq!(res.len(), 0x3FFF);
assert_eq!(res[0], 4); assert_eq!(res[0], 4);
} else { } else {
assert!(false); panic!();
} }
} }
@ -232,13 +232,13 @@ mod tests {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
bytes.resize(0x3FFFFF, 5); bytes.resize(0x3FFFFF, 5);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
assert_eq!(buf.len(), 0x3FFFFF + 3); assert_eq!(buf.len(), 0x3FFFFF + 3);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3FFFFF); assert_eq!(res.len(), 0x3FFFFF);
assert_eq!(res[0], 5); assert_eq!(res[0], 5);
} else { } else {
assert!(false); panic!();
} }
} }
@ -248,33 +248,33 @@ mod tests {
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
bytes.resize(0x3FFFFF + 1, 6); bytes.resize(0x3FFFFF + 1, 6);
assert!(!codec.encode(bytes.into(), &mut buf).is_err()); assert!(codec.encode(bytes.into(), &mut buf).is_ok());
let buf_saved = buf.clone(); let buf_saved = buf.clone();
assert_eq!(buf.len(), 0x3FFFFF + 4 + 1); assert_eq!(buf.len(), 0x3FFFFF + 4 + 1);
if let Ok(Some(res)) = codec.decode(&mut buf) { if let Ok(Some(res)) = codec.decode(&mut buf) {
assert_eq!(res.len(), 0x3FFFFF + 1); assert_eq!(res.len(), 0x3FFFFF + 1);
assert_eq!(res[0], 6); assert_eq!(res[0], 6);
} else { } else {
assert!(false); panic!();
} }
let mut codec2 = BytesCodec::new(); let mut codec2 = BytesCodec::new();
let mut buf2 = BytesMut::new(); let mut buf2 = BytesMut::new();
buf2.extend(&buf_saved[0..1]); buf2.extend(&buf_saved[0..1]);
if let Ok(None) = codec2.decode(&mut buf2) { if let Ok(None) = codec2.decode(&mut buf2) {
} else { } else {
assert!(false); panic!();
} }
buf2.extend(&buf_saved[1..6]); buf2.extend(&buf_saved[1..6]);
if let Ok(None) = codec2.decode(&mut buf2) { if let Ok(None) = codec2.decode(&mut buf2) {
} else { } else {
assert!(false); panic!();
} }
buf2.extend(&buf_saved[6..]); buf2.extend(&buf_saved[6..]);
if let Ok(Some(res)) = codec2.decode(&mut buf2) { if let Ok(Some(res)) = codec2.decode(&mut buf2) {
assert_eq!(res.len(), 0x3FFFFF + 1); assert_eq!(res.len(), 0x3FFFFF + 1);
assert_eq!(res[0], 6); assert_eq!(res[0], 6);
} else { } else {
assert!(false); panic!();
} }
} }
} }

View File

@ -288,7 +288,7 @@ fn patch(path: PathBuf) -> PathBuf {
.trim() .trim()
.to_owned(); .to_owned();
if user != "root" { if user != "root" {
return format!("/home/{}", user).into(); return format!("/home/{user}").into();
} }
} }
} }
@ -525,7 +525,7 @@ impl Config {
let mut path: PathBuf = format!("/tmp/{}", *APP_NAME.read().unwrap()).into(); let mut path: PathBuf = format!("/tmp/{}", *APP_NAME.read().unwrap()).into();
fs::create_dir(&path).ok(); fs::create_dir(&path).ok();
fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok();
path.push(format!("ipc{}", postfix)); path.push(format!("ipc{postfix}"));
path.to_str().unwrap_or("").to_owned() path.to_str().unwrap_or("").to_owned()
} }
} }
@ -562,7 +562,7 @@ impl Config {
.unwrap_or_default(); .unwrap_or_default();
} }
if !rendezvous_server.contains(':') { if !rendezvous_server.contains(':') {
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT); rendezvous_server = format!("{rendezvous_server}:{RENDEZVOUS_PORT}");
} }
rendezvous_server rendezvous_server
} }

View File

@ -211,11 +211,7 @@ pub fn gen_version() {
// generate build date // generate build date
let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M")); let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
file.write_all( file.write_all(
format!( format!("#[allow(dead_code)]\npub const BUILD_DATE: &str = \"{build_date}\";\n").as_bytes(),
"#[allow(dead_code)]\npub const BUILD_DATE: &str = \"{}\";",
build_date
)
.as_bytes(),
) )
.ok(); .ok();
file.sync_all().ok(); file.sync_all().ok();
@ -342,39 +338,39 @@ mod test {
#[test] #[test]
fn test_ipv6() { fn test_ipv6() {
assert_eq!(is_ipv6_str("1:2:3"), true); assert!(is_ipv6_str("1:2:3"));
assert_eq!(is_ipv6_str("[ab:2:3]:12"), true); assert!(is_ipv6_str("[ab:2:3]:12"));
assert_eq!(is_ipv6_str("[ABEF:2a:3]:12"), true); assert!(is_ipv6_str("[ABEF:2a:3]:12"));
assert_eq!(is_ipv6_str("[ABEG:2a:3]:12"), false); assert!(!is_ipv6_str("[ABEG:2a:3]:12"));
assert_eq!(is_ipv6_str("1[ab:2:3]:12"), false); assert!(!is_ipv6_str("1[ab:2:3]:12"));
assert_eq!(is_ipv6_str("1.1.1.1"), false); assert!(!is_ipv6_str("1.1.1.1"));
assert_eq!(is_ip_str("1.1.1.1"), true); assert!(is_ip_str("1.1.1.1"));
assert_eq!(is_ipv6_str("1:2:"), false); assert!(!is_ipv6_str("1:2:"));
assert_eq!(is_ipv6_str("1:2::0"), true); assert!(is_ipv6_str("1:2::0"));
assert_eq!(is_ipv6_str("[1:2::0]:1"), true); assert!(is_ipv6_str("[1:2::0]:1"));
assert_eq!(is_ipv6_str("[1:2::0]:"), false); assert!(!is_ipv6_str("[1:2::0]:"));
assert_eq!(is_ipv6_str("1:2::0]:1"), false); assert!(!is_ipv6_str("1:2::0]:1"));
} }
#[test] #[test]
fn test_hostname_port() { fn test_hostname_port() {
assert_eq!(is_domain_port_str("a:12"), false); assert!(!is_domain_port_str("a:12"));
assert_eq!(is_domain_port_str("a.b.c:12"), false); assert!(!is_domain_port_str("a.b.c:12"));
assert_eq!(is_domain_port_str("test.com:12"), true); assert!(is_domain_port_str("test.com:12"));
assert_eq!(is_domain_port_str("test-UPPER.com:12"), true); assert!(is_domain_port_str("test-UPPER.com:12"));
assert_eq!(is_domain_port_str("some-other.domain.com:12"), true); assert!(is_domain_port_str("some-other.domain.com:12"));
assert_eq!(is_domain_port_str("under_score:12"), false); assert!(!is_domain_port_str("under_score:12"));
assert_eq!(is_domain_port_str("a@bc:12"), false); assert!(!is_domain_port_str("a@bc:12"));
assert_eq!(is_domain_port_str("1.1.1.1:12"), false); assert!(!is_domain_port_str("1.1.1.1:12"));
assert_eq!(is_domain_port_str("1.2.3:12"), false); assert!(!is_domain_port_str("1.2.3:12"));
assert_eq!(is_domain_port_str("1.2.3.45:12"), false); assert!(!is_domain_port_str("1.2.3.45:12"));
assert_eq!(is_domain_port_str("a.b.c:123456"), false); assert!(!is_domain_port_str("a.b.c:123456"));
assert_eq!(is_domain_port_str("---:12"), false); assert!(!is_domain_port_str("---:12"));
assert_eq!(is_domain_port_str(".:12"), false); assert!(!is_domain_port_str(".:12"));
// todo: should we also check for these edge cases? // todo: should we also check for these edge cases?
// out-of-range port // out-of-range port
assert_eq!(is_domain_port_str("test.com:0"), true); assert!(is_domain_port_str("test.com:0"));
assert_eq!(is_domain_port_str("test.com:98989"), true); assert!(is_domain_port_str("test.com:98989"));
} }
#[test] #[test]

View File

@ -192,51 +192,51 @@ mod test {
let data = "Hello World"; let data = "Hello World";
let encrypted = encrypt_str_or_original(data, version); let encrypted = encrypt_str_or_original(data, version);
let (decrypted, succ, store) = decrypt_str_or_original(&encrypted, version); let (decrypted, succ, store) = decrypt_str_or_original(&encrypted, version);
println!("data: {}", data); println!("data: {data}");
println!("encrypted: {}", encrypted); println!("encrypted: {encrypted}");
println!("decrypted: {}", decrypted); println!("decrypted: {decrypted}");
assert_eq!(data, decrypted); assert_eq!(data, decrypted);
assert_eq!(version, &encrypted[..2]); assert_eq!(version, &encrypted[..2]);
assert_eq!(succ, true); assert!(succ);
assert_eq!(store, false); assert!(!store);
let (_, _, store) = decrypt_str_or_original(&encrypted, "99"); let (_, _, store) = decrypt_str_or_original(&encrypted, "99");
assert_eq!(store, true); assert!(store);
assert_eq!(decrypt_str_or_original(&decrypted, version).1, false); assert!(!decrypt_str_or_original(&decrypted, version).1);
assert_eq!(encrypt_str_or_original(&encrypted, version), encrypted); assert_eq!(encrypt_str_or_original(&encrypted, version), encrypted);
println!("test vec"); println!("test vec");
let data: Vec<u8> = vec![1, 2, 3, 4, 5, 6]; let data: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let encrypted = encrypt_vec_or_original(&data, version); let encrypted = encrypt_vec_or_original(&data, version);
let (decrypted, succ, store) = decrypt_vec_or_original(&encrypted, version); let (decrypted, succ, store) = decrypt_vec_or_original(&encrypted, version);
println!("data: {:?}", data); println!("data: {data:?}");
println!("encrypted: {:?}", encrypted); println!("encrypted: {encrypted:?}");
println!("decrypted: {:?}", decrypted); println!("decrypted: {decrypted:?}");
assert_eq!(data, decrypted); assert_eq!(data, decrypted);
assert_eq!(version.as_bytes(), &encrypted[..2]); assert_eq!(version.as_bytes(), &encrypted[..2]);
assert_eq!(store, false); assert!(!store);
assert_eq!(succ, true); assert!(succ);
let (_, _, store) = decrypt_vec_or_original(&encrypted, "99"); let (_, _, store) = decrypt_vec_or_original(&encrypted, "99");
assert_eq!(store, true); assert!(store);
assert_eq!(decrypt_vec_or_original(&decrypted, version).1, false); assert!(!decrypt_vec_or_original(&decrypted, version).1);
assert_eq!(encrypt_vec_or_original(&encrypted, version), encrypted); assert_eq!(encrypt_vec_or_original(&encrypted, version), encrypted);
println!("test original"); println!("test original");
let data = version.to_string() + "Hello World"; let data = version.to_string() + "Hello World";
let (decrypted, succ, store) = decrypt_str_or_original(&data, version); let (decrypted, succ, store) = decrypt_str_or_original(&data, version);
assert_eq!(data, decrypted); assert_eq!(data, decrypted);
assert_eq!(store, true); assert!(store);
assert_eq!(succ, false); assert!(!succ);
let verbytes = version.as_bytes(); let verbytes = version.as_bytes();
let data: Vec<u8> = vec![verbytes[0] as u8, verbytes[1] as u8, 1, 2, 3, 4, 5, 6]; let data: Vec<u8> = vec![verbytes[0], verbytes[1], 1, 2, 3, 4, 5, 6];
let (decrypted, succ, store) = decrypt_vec_or_original(&data, version); let (decrypted, succ, store) = decrypt_vec_or_original(&data, version);
assert_eq!(data, decrypted); assert_eq!(data, decrypted);
assert_eq!(store, true); assert!(store);
assert_eq!(succ, false); assert!(!succ);
let (_, succ, store) = decrypt_str_or_original("", version); let (_, succ, store) = decrypt_str_or_original("", version);
assert_eq!(store, false); assert!(!store);
assert_eq!(succ, false); assert!(!succ);
let (_, succ, store) = decrypt_vec_or_original(&vec![], version); let (_, succ, store) = decrypt_vec_or_original(&[], version);
assert_eq!(store, false); assert!(!store);
assert_eq!(succ, false); assert!(!succ);
} }
} }

View File

@ -60,7 +60,7 @@ fn get_display_server_of_session(session: &str) -> String {
.replace("TTY=", "") .replace("TTY=", "")
.trim_end() .trim_end()
.into(); .into();
if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{}.\\\\+Xorg\"", tty)) if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{tty}.\\\\+Xorg\""))
// And check if Xorg is running on that tty // And check if Xorg is running on that tty
{ {
if xorg_results.trim_end() != "" { if xorg_results.trim_end() != "" {

View File

@ -1 +1 @@
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs")); include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));

View File

@ -13,22 +13,22 @@ use tokio_socks::{IntoTargetAddr, TargetAddr};
pub fn check_port<T: std::string::ToString>(host: T, port: i32) -> String { pub fn check_port<T: std::string::ToString>(host: T, port: i32) -> String {
let host = host.to_string(); let host = host.to_string();
if crate::is_ipv6_str(&host) { if crate::is_ipv6_str(&host) {
if host.starts_with("[") { if host.starts_with('[') {
return host; return host;
} }
return format!("[{}]:{}", host, port); return format!("[{host}]:{port}");
} }
if !host.contains(":") { if !host.contains(':') {
return format!("{}:{}", host, port); return format!("{host}:{port}");
} }
return host; host
} }
#[inline] #[inline]
pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String { pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String {
let host = host.to_string(); let host = host.to_string();
if crate::is_ipv6_str(&host) { if crate::is_ipv6_str(&host) {
if host.starts_with("[") { if host.starts_with('[') {
let tmp: Vec<&str> = host.split("]:").collect(); let tmp: Vec<&str> = host.split("]:").collect();
if tmp.len() == 2 { if tmp.len() == 2 {
let port: i32 = tmp[1].parse().unwrap_or(0); let port: i32 = tmp[1].parse().unwrap_or(0);
@ -37,8 +37,8 @@ pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String {
} }
} }
} }
} else if host.contains(":") { } else if host.contains(':') {
let tmp: Vec<&str> = host.split(":").collect(); let tmp: Vec<&str> = host.split(':').collect();
if tmp.len() == 2 { if tmp.len() == 2 {
let port: i32 = tmp[1].parse().unwrap_or(0); let port: i32 = tmp[1].parse().unwrap_or(0);
if port > 0 { if port > 0 {
@ -46,7 +46,7 @@ pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String {
} }
} }
} }
return host; host
} }
pub fn test_if_valid_server(host: &str) -> String { pub fn test_if_valid_server(host: &str) -> String {
@ -148,7 +148,7 @@ pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String { pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
if !ipv4 && crate::is_ipv4_str(&addr) { if !ipv4 && crate::is_ipv4_str(&addr) {
if let Some(ip) = addr.split(':').next() { if let Some(ip) = addr.split(':').next() {
return addr.replace(ip, &format!("{}.nip.io", ip)); return addr.replace(ip, &format!("{ip}.nip.io"));
} }
} }
addr addr
@ -163,7 +163,7 @@ async fn test_target(target: &str) -> ResultType<SocketAddr> {
tokio::net::lookup_host(target) tokio::net::lookup_host(target)
.await? .await?
.next() .next()
.context(format!("Failed to look up host for {}", target)) .context(format!("Failed to look up host for {target}"))
} }
#[inline] #[inline]

View File

@ -100,7 +100,7 @@ impl FramedStream {
} }
} }
} }
bail!(format!("Failed to connect to {}", remote_addr)); bail!(format!("Failed to connect to {remote_addr}"));
} }
pub async fn connect<'a, 't, P, T>( pub async fn connect<'a, 't, P, T>(