The disappearance of a variable if it is not displayed Rust - rust

Please help me to understand why i need to display variable. I use ssh2 crate to create ssh connect.
My code is here:
use ssh2::Session;
use std::io::prelude::*;
use std::net::{TcpStream};
fn main() {
// Connect to the SSH server
let tcp = TcpStream::connect("192.168.1.251:22").unwrap();
let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("root", "password").unwrap();
let mut s = String::new();
let last_stat = String::from("unknown");
loop {
let mut channel = sess.channel_session().unwrap();
channel.exec("systemctl is-active firewalld").unwrap();
channel.read_to_string(&mut s).unwrap();
if &s.to_string().trim() == &last_stat {
print!("stopped");
} else {
print!("{}",&s);
}
&s.clear();
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
If the firewallв is stopped, nothing is displayed. But if I show the variable in the output, then the code works and display "unknown".
use ssh2::Session;
use std::io::prelude::*;
use std::net::{TcpStream};
fn main() {
// Connect to the SSH server
let tcp = TcpStream::connect("192.168.1.251:22").unwrap();
let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("root", "password").unwrap();
let mut s = String::new();
let last_stat = String::from("unknown");
loop {
let mut channel = sess.channel_session().unwrap();
channel.exec("systemctl is-active firewalld").unwrap();
channel.read_to_string(&mut s).unwrap();
if &s.to_string().trim() == &last_stat {
print!("{}",&s);
} else {
print!("{}",&s);
}
&s.clear();
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
Why i must display variable &s to code works?
many thanks.

Related

Rust TcpStream doesn't send data to TcpListener until program is stopped

I'm making a simple chat using Tokio for learning. I've made a server with TcpListener that works fine when I use telnets conexions. For example, if I open 2 terminals with telnet and send data, the server receives the conexion and send the data to the address that is not the sender.
The problem I have is with the TcpStream. For some reason (I think is some type of blocking problem) the stream is not sending the data until I stop the app.
I'd tried multiple configurations, but I think that the simple requiered that is close to "work" is the next one.
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
println!("INFO: Socket Address: {:?}", stream.local_addr().unwrap());
let (read, mut writer) = stream.split();
let (sender, receiver) = channel();
thread::spawn(move || loop {
let mut line_buf = String::new();
stdin().read_line(&mut line_buf);
let line = line_buf.trim_end().to_string();
if line.len() > 0 {
sender.send(line_buf.trim_end().to_string()).unwrap();
}
});
loop {
let line = receiver.recv().unwrap();
println!("DEBUG User Input {line}");
writer.write_all(line.as_bytes()).await?;
}
P.D: this code doesn't have anything for receive the messages sended by the server. For manage that, I had something like:
tokio::spawn(async move {
let (read, mut writer) = socket.split();
let mut reader = BufReader::new(read);
let mut line = String::new();
loop {
tokio::select! {
result = reader.read_line(&mut line) => {
if result.unwrap() == 0 {
break;
}
print!("DEBUG: Message Received: {line}");
tx.send((line.clone(), addr)).unwrap();
line.clear();
}
result = rx.recv() => {
let (msg, other_addr) = result.unwrap();
println!("INFO: Message Address: {addr}\n\n");
if addr != other_addr {
writer.write_all(msg.as_bytes()).await.unwrap();
}
}
}
}
});

Can't connect to a rust tcp server that is running on replit.com

I want to make a chat server between my computer and a server that is running on replit but I can't connect to the replit server (it works when I run the server on my device so the code seems to work)
Here is the server-side code that runs on replit:
use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::str;
use std::thread;
fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {
let mut data = [0; 4096];
loop {
let len = stream.read(&mut data)?;
let text = str::from_utf8(&data[..len]).unwrap();
println!("Received: {}", text);
println!("What do you want to send: ");
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
stream.write_all(input.as_bytes())?;
}
}
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("0.0.0.0:6969")?;
for stream in listener.incoming() {
let stream = stream?;
println!("New connection: {}", stream.peer_addr()?);
thread::spawn(move || handle_client(stream));
}
Ok(())
}
And here is the client-side code:
use std::io::{self, Read, Write};
use std::net::TcpStream;
use std::str;
fn main() -> std::io::Result<()> {
let mut stream = TcpStream::connect("IncompleteHelpfulServer.smartflow.repl.co:6969")?;
loop {
println!("What do you want to send: ");
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
stream.write_all(input.as_bytes())?;
let mut data = [0; 4096];
let len = stream.read(&mut data)?;
let text = str::from_utf8(&data[..len]).unwrap();
println!("Recieved: {}", text);
}
}
When the server is running on replit and I try to connect to it I get this error:
Error: Custom { kind: Uncategorized, error: "Failed to lookup address information: Temporary failure in name resolution" }
I tried to change the address from IncompleteHelpfulServer.smartflow.repl.co:6969 to:
IncompleteHelpfulServer.smartflow.repl.co
https://IncompleteHelpfulServer.smartflow.repl.co:6969
http://IncompleteHelpfulServer.smartflow.repl.co:6969
https://IncompleteHelpfulServer.smartflow.repl.co
http://IncompleteHelpfulServer.smartflow.repl.co
But neither of them worked
I searched if it was even possible and it was also if I try to connect to the address with my browser the replit server gets some info about my browser so I think there is a problem in the client-side code
Can somebody help me fix this?
Thanks for reading
Managed to do it with hyper and native-tls with https
S.O to #Locke in the comments

How to stop my tokio thread from blocking

I am writing a client for a Unix Domain Socket, which should listen for messages from a server, I got it to work after hours of researching (it shows 1-2 messages), but after that tokio crashes with the error: Error: Kind(WouldBlock), here is my code:
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let stream = UnixStream::connect(socket_path).await?;
loop {
stream.readable().await?;
let mut buf = [0; 4096];
stream.try_read(&mut buf)?;
io::stdout().lock().write_all(&buf)?;
}
}
Could someone please help me?
I fully agree with #Caesar's comment.
don't use try_read, use read instead
slice the buffer to the correct size after reading
check for 0 bytes read, which indicates that the end of the stream was reached
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::io::AsyncReadExt;
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let mut stream = UnixStream::connect(socket_path).await?;
let mut buf = [0; 4096];
loop {
let num_read = stream.read(&mut buf).await?;
if num_read == 0 {
break;
}
let buf = &buf[..num_read];
io::stdout().lock().write_all(buf)?;
}
Ok(())
}
Disclaimer: I didn't test the code because I don't have the required socket file. It compiles, though.

How do I send and receive vectors in my tcp server/client setup?

I ahve a really simple tcp client/server setup that I found somewhere online.
use std::net::{Shutdown,TcpListener, TcpStream};
use std::thread;
use std::io::{Read,Write,Error};
fn handle_client(mut stream: TcpStream)-> Result<(), Error> {
println!("incoming connection from: {}", stream.peer_addr()?);
let mut buf = [0;512];
loop {
let bytes_read = stream.read(&mut buf)?;
if bytes_read == 0 {return Ok(())}
let tmp = format!("{}", String::from_utf8_lossy(&buf).trim());
eprintln!("getting {}",tmp);
stream.write(&vec![1,2,3,4])?;
}
}
fn main() {
let listener = TcpListener::bind("0.0.0.0:8888").expect("Could not bind");
let mut i = 0;
for stream in listener.incoming() {
match stream {
Err(e)=> {eprintln!("failed: {}", e)}
Ok(stream) => {
thread::spawn(move || {
handle_client(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
});
}
}
}
}
and the client looks like so:
use std::net::TcpStream;
use std::str;
use std::io::{self,BufRead,BufReader,Write};
fn main() {
let mut stream = TcpStream::connect("0.0.0.0:8888").expect("could not connect");
loop {
let mut input = String::new();
let mut buffer : Vec<u8> = Vec::new();
io::stdin().read_line(&mut input).expect("failed to read stdin");
stream.write(input.as_bytes()).expect("Failed to write to server");
let mut reader = BufReader::new(&stream);
reader.read_until(b'\n', &mut buffer).expect("Could not read into buffer");
println!("{}", str::from_utf8(&buffer).expect("msg: &str"))
}
println!("Hello, world!");
}
(actually vs code tells me that the code inside the loop here is unreachable, which is false)
But this basically just lets the client send a message to the server, that the server sends back.
I would actually like to send vectors back and forth, which actually seems like a simpler task.
So, I change the line in the server that writes to the stream to this:
stream.write(&vec![1,2,3,4])?;
and now, in the client that prints the message it gets from the serve to:
println!("{:?}", &buffer)
But when I do this, nothing happens on the clientside, nothing is printed, and it seems like the loop is just stuck somewhere.
I gugess it has something to do with this line:
reader.read_until(b'\n', &mut buffer).expect("Could not read into buffer");
and I read some other way of reading in. I tried using a function from tcpstream called "read_vectored", but I can't use it at all for the stream object I have.

How can I use threads to run this code simultaneously in rust?

I have a rust program that creates temporary email addresses using the mail.tm API, and I want to use threads to create emails simultaneously, to increase the speed. However, what I have tried, only results in printing "Getting email.." x amount of times, and exiting. I am unsure what to do about this. Any help or suggestions are appreciated.
use json;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use reqwest;
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE};
use std::{collections::HashMap, io, iter, vec::Vec};
use std::thread;
fn gen_address() -> Vec<String> {
let mut rng = thread_rng();
let address: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(10)
.collect();
let password: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(5)
.collect();
let body = reqwest::blocking::get("https://api.mail.tm/domains")
.unwrap()
.text()
.unwrap();
let domains = json::parse(&body).expect("Failed to parse domain json.");
let domain = domains["hydra:member"][0]["domain"].to_string();
let email = format!("{}#{}", &address, &domain);
vec![email, password]
}
fn gen_email() -> Vec<String> {
let client = reqwest::blocking::Client::new();
let address_info = gen_address();
let address = &address_info[0];
let password = &address_info[1];
let mut data = HashMap::new();
data.insert("address", &address);
data.insert("password", &password);
let mut headers = HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/ld+json"));
headers.insert(
CONTENT_TYPE,
HeaderValue::from_static("application/ld+json"),
);
let res = client
.post("https://api.mail.tm/accounts")
.headers(headers)
.json(&data)
.send()
.unwrap();
vec![
res.status().to_string(),
address.to_string(),
password.to_string(),
]
}
fn main() {
fn get_amount() -> i32 {
let mut amount = String::new();
loop {
println!("How many emails do you want?");
io::stdin()
.read_line(&mut amount)
.expect("Failed to read line.");
let _amount: i32 = match amount.trim().parse() {
Ok(num) => return num,
Err(_) => {
println!("Please enter a number.");
continue;
}
};
}
}
let amount = get_amount();
let handle = thread::spawn(move || {
for _gen in 0..amount {
let handle = thread::spawn(|| {
println!("Getting email...");
let maildata = gen_email();
println!(
"Status: {}, Address: {}, Password: {}",
maildata[0], maildata[1], maildata[2]);
});
}
});
handle.join().unwrap();
}
Rust Playground example
I see a number of sub-threads being spawned from an outer thread. I think you might want to keep those handles and join them. Unless you join those sub threads the outer thread will exit early. I set up a Rust Playground to demonstrate ^^.
In the playground example, first run the code as-is and note the output of the code - the function it's running is not_joining_subthreads(). Note that it terminates rather abruptly. Then modify the code to call joining_subthreads(). You should then see the subthreads printing out their stdout messages.
let handle = thread::spawn(move || {
let mut handles = vec![];
for _gen in 0..amount {
let handle = thread::spawn(|| {
println!("Getting email...");
let maildata = gen_email();
println!(
"Status: {}, Address: {}, Password: {}",
maildata[0], maildata[1], maildata[2]);
});
handles.push(handle);
}
handles.into_iter().for_each(|h| h.join().unwrap());
});
handle.join().unwrap();

Resources