Parse http response into tuple vector of (chrono::DateTime, f32) - rust

I send an http get request to a server and receive a response:
let resp = reqwest::blocking::get(req)?.text()?;
resp holds a String like this:
<?xml version=\"1.0\" encoding=\"UTF-8\">\n<Document xmlns=...
<datetime>202207102300</datetime>\n\t\t\t\t\t\t<value>320.08</value>\n\t\t\t\t\t<datetime>202207110000</datetime>\n\t\t\t\t\t\t<value>278.00</value>
...</Document>
What is the best way to get this text parsed into a vector containing tuple elements, as follows:
let mut tuple_items: (chrono::DateTime, f32)

This is my code that I created with the quickxml crate:
use chrono::NaiveDateTime;
use quick_xml::events::Event;
use quick_xml::Reader;
pub struct DatetimeValue {
pub dt: NaiveDateTime,
pub val: f32,
}
pub fn parse_xml_string(&self, xml_string: String) -> Vec<DatetimeValue> {
let mut response_vector: Vec<DatetimeValue> = vec![];
let mut reader = Reader::from_str(&xml_string[..]);
reader.trim_text(true);
let mut val_flag = false;
let mut dt_flag = false;
let mut buf = Vec::new();
let mut count = 0;
let mut actual_dt: NaiveDateTime;
loop {
match reader.read_event(&mut buf) {
Ok(Event::Start(ref e)) => {
if let b"value" = e.name() { val_flag = true }
else if let b"datetime" = e.name() { dt_flag = true }
}
Ok(Event::Text(e)) => {
if dt_flag {
actual_dt = NaiveDateTime::parse_from_str(e
.unescape_and_decode(&reader)
.unwrap(), "%Y%m%d%H%M").unwrap();
dt_flag = false;
}
else if val_flag {
response_vector.push(DatetimeValue {
dt: actual_dt,
val: e
.unescape_and_decode(&reader)
.unwrap()
.parse::<f32>()
.unwrap(),
});
val_flag = false;
}
}
Ok(Event::Eof) => break,
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
_ => (),
}
buf.clear();
}
response_vector
}

Related

What's wrong with tokio unix socket server/client?

I have a server that broadcast messages to connected client, though the messages doesn't get delivered and my tests fails.
I'm using the following
use anyhow::Result;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::Arc;
use tokio::io::AsyncWriteExt;
use tokio::net::{UnixListener, UnixStream};
use tokio::sync::broadcast::*;
use tokio::sync::Notify;
use tokio::task::JoinHandle;
This is how I start and setup my server
pub struct Server {
#[allow(dead_code)]
tx: Sender<String>,
rx: Receiver<String>,
address: Arc<PathBuf>,
handle: Option<JoinHandle<Result<()>>>,
abort: Arc<Notify>,
}
impl Server {
pub fn new<P: AsRef<Path>>(address: P) -> Self {
let (tx, rx) = channel::<String>(400);
let address = Arc::new(address.as_ref().to_path_buf());
Self {
address,
handle: None,
tx,
rx,
abort: Arc::new(Notify::new()),
}
}
}
/// Start Server
pub async fn start(server: &mut Server) -> Result<()> {
tokio::fs::remove_file(server.address.as_path()).await.ok();
let listener = UnixListener::bind(server.address.as_path())?;
println!("[Server] Started");
let tx = server.tx.clone();
let abort = server.abort.clone();
server.handle = Some(tokio::spawn(async move {
loop {
let tx = tx.clone();
let abort1 = abort.clone();
tokio::select! {
_ = abort.notified() => break,
Ok((client, _)) = listener.accept() => {
tokio::spawn(async move { handle(client, tx, abort1).await });
}
}
}
println!("[Server] Aborted!");
Ok(())
}));
Ok(())
}
my handle function
/// Handle stream
async fn handle(mut stream: UnixStream, tx: Sender<String>, abort: Arc<Notify>) {
loop {
let mut rx = tx.subscribe();
let abort = abort.clone();
tokio::select! {
_ = abort.notified() => break,
result = rx.recv() => match result {
Ok(output) => {
stream.write_all(output.as_bytes()).await.unwrap();
stream.write(b"\n").await.unwrap();
continue;
}
Err(e) => {
println!("[Server] {e}");
break;
}
}
}
}
stream.write(b"").await.unwrap();
stream.flush().await.unwrap();
}
my connect function
/// Connect to server
async fn connect(address: Arc<PathBuf>, name: String) -> Vec<String> {
use tokio::io::{AsyncBufReadExt, BufReader};
let mut outputs = vec![];
let stream = UnixStream::connect(&*address).await.unwrap();
let mut breader = BufReader::new(stream);
let mut buf = vec![];
loop {
if let Ok(len) = breader.read_until(b'\n', &mut buf).await {
if len == 0 {
break;
} else {
let value = String::from_utf8(buf.clone()).unwrap();
print!("[{name}] {value}");
outputs.push(value)
};
buf.clear();
}
}
println!("[{name}] ENDED");
outputs
}
This what I feed to the channel and want to have broadcasted to all clients
/// Feed data
pub fn feed(tx: Sender<String>, abort: Arc<Notify>) -> Result<JoinHandle<Result<()>>> {
use tokio::io::*;
use tokio::process::Command;
Ok(tokio::spawn(async move {
let mut child = Command::new("echo")
.args(&["1\n", "2\n", "3\n", "4\n"])
.stdout(Stdio::piped())
.stderr(Stdio::null())
.stdin(Stdio::null())
.spawn()?;
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
loop {
let sender = tx.clone();
tokio::select! {
result = stdout.next_line() => match result {
Err(e) => {
println!("[Server] FAILED to send an output to channel: {e}");
},
Ok(None) => break,
Ok(Some(output)) => {
let output = output.trim().to_string();
println!("[Server] {output}");
if !output.is_empty() {
if let Err(e) = sender.send(output) {
println!("[Server] FAILED to send an output to channel: {e}");
}
}
}
}
}
}
println!("[Server] Process Completed");
abort.notify_waiters();
Ok(())
}))
}
my failing test
#[tokio::test]
async fn test_server() -> Result<()> {
let mut server = Server::new("/tmp/testsock.socket");
start(&mut server).await?;
feed(server.tx.clone(), server.abort.clone()).unwrap();
let address = server.address.clone();
let client1 = connect(address.clone(), "Alpha".into());
let client2 = connect(address.clone(), "Beta".into());
let client3 = connect(address.clone(), "Delta".into());
let client4 = connect(address.clone(), "Gamma".into());
let (c1, c2, c3, c4) = tokio::join!(client1, client2, client3, client4,);
server.handle.unwrap().abort();
assert_eq!(c1.len(), 4, "Alpha");
assert_eq!(c2.len(), 4, "Beta");
assert_eq!(c3.len(), 4, "Delta");
assert_eq!(c4.len(), 4, "Gamma");
println!("ENDED");
Ok(())
}
Logs:
[Server] Started
[Server] 1
[Server] 2
[Server] 3
[Server] 4
[Server]
[Delta] 1
[Gamma] 1
[Alpha] 1
[Beta] 1
[Server] Process Completed
[Server] Aborted!
[Gamma] ENDED
[Alpha] ENDED
[Beta] ENDED
[Delta] ENDED
well, not an answer but I just want to suggest to use task::spawn to generate a JoinHandle from a function, then, say your handle could be:
fn handle(mut stream: UnixStream, tx: Sender<String>, abort: Arc<Notify>) -> JoinHandle {
let mut rx = tx.subscribe();
let abort = abort.clone();
task::spawn( async move {
loop {
tokio::select! {
_ = abort.notified() => break,
result = rx.recv() => match result {
Ok(output) => {
stream.write_all(output.as_bytes()).await.unwrap();
stream.write(b"\n").await.unwrap();
continue;
}
Err(e) => {
println!("[Server] {e}");
break;
}
}
}
}
stream.write(b"").await.unwrap();
stream.flush().await.unwrap();
})
}
I mean, I did not tested this, but I see a sort of duplication in the code above, like 2 loop, 2 select! and twice the abort check

How to extract the argument of actix_web HttpServer::new(..) into a separte function?

I am trying to extract the factory closures into it's own function.
So instead of this
let server = HttpServer::new(|| App::new().wrap(Logger::default()))
.bind("127.0.0.1:8080")?
.run();
I'd like to move App::new()... into a new function called new_app()
let server = HttpServer::new(|| new_app())
.bind("127.0.0.1:8080")?.run();
// todo
fn new_app() { todo!() }
I was unable to use Clion IDE or VSCode do it automatically as they are unable to figure out the return type of App::new().wrap()..
However I figured the return type is something like this
pub fn new_app() -> App<
impl ServiceFactory<
ServiceRequest,
Config = (),
Response = ServiceResponse<
actix_web::middleware::logger::StreamLog<actix_web::body::AnyBody>,
>,
Error = Error,
InitError = (),
>,
actix_web::middleware::logger::StreamLog<actix_web::body::AnyBody>,
> {
App::new().wrap(Logger::default())
}
However this can not be right because the module actix_web::middleware::logger is private.
So I tried with a more "generic" type of the generic type parameters,
pub fn new_app() -> App<
impl ServiceFactory<ServiceRequest>,
impl MessageBody,
> {
App::new().wrap(Logger::default())
}
However this also doesn't compile with this error
error[E0277]: the trait bound `App<impl ServiceFactory<ServiceRequest>, impl MessageBody>: actix_service::IntoServiceFactory<_, Request>` is not satisfied
--> src/app.rs:79:78
|
79 | let server = HttpServer::new(|| new_app_2()).bind("127.0.0.1:8080")?.run();
| ^^^ the trait `actix_service::IntoServiceFactory<_, Request>` is not implemented for `App<impl ServiceFactory<ServiceRequest>, impl MessageBody>`
|
= help: the following implementations were found:
<App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>, Request>>
It seems like a trivial work to extract some code into a function but I am not sure how to fix this. Would you help me?
I solved similar issue by implementing custom logging middleware.
Then we can use actix_web::dev::Body instead of actix_web::middleware::logger::StreamLog<actix_web::body::AnyBody>.
use actix_service::ServiceFactory;
fn app() -> App<
impl ServiceFactory<
Request = actix_web::dev::ServiceRequest,
Config = (),
Response = actix_web::dev::ServiceResponse,
Error = actix_web::Error,
InitError = (),
>,
actix_web::dev::Body, // <- This
> {
App::new()
.wrap(middlewares::logging::Logging)
.service(index)
}
As a side note,
You can implement middleware referring official examples https://github.com/actix/examples/tree/master/basics/middleware/src or my code below that includes request & response log.
#![allow(unused_imports)]
use std::pin::Pin;
use std::task::{Context, Poll};
use std::rc::Rc;
use std::cell::RefCell;
use futures::{future::{ok, Future, Ready}, stream::StreamExt};
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use actix_service::{Service, Transform};
use actix_web::{
dev::{ServiceRequest, ServiceResponse},
web::{Bytes, BytesMut},
web,
body::{Body, BodySize, MessageBody, ResponseBody},
http::Version,
Error, HttpMessage,
};
use actix_http::h1::{Payload};
use chrono::{Utc, DateTime, Date, NaiveDateTime};
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
pub struct Logging;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S, B> Transform<S> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: MessageBody + Unpin + 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware {
service: Rc::new(RefCell::new(service))
})
}
}
pub struct LoggingMiddleware<S> {
service: Rc<RefCell<S>>,
}
impl<S, B> Service for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: MessageBody + Unpin + 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone();
Box::pin(async move {
let begin = Utc::now();
let path = req.path().to_string();
let method = req.method().as_str().to_string();
let queries = req.query_string().to_string();
let ip = req.head().peer_addr;
let protocol = match req.version() {
Version::HTTP_09 => "http/0.9",
Version::HTTP_10 => "http/1.0",
Version::HTTP_11 => "http/1.1",
Version::HTTP_2 => "http/2.0",
Version::HTTP_3 => "http/3.0",
_ => "UNKNOWN",
};
// Request headers
let mut domain = String::new();
let mut user_agent = String::new();
let mut headers: HashMap<&str, &str> = HashMap::new();
for (k, v) in req.headers().iter() {
if let Ok(inner) = v.to_str() {
let key = k.as_str();
headers.insert(key, inner);
match key {
"host" => { domain = inner.to_string() },
"user-agent" => { user_agent = inner.to_string() },
_ => {},
}
}
}
let req_headers = json!(headers).to_string();
let req_body = get_request_body(&mut req).await;
let mut parsed = parse_body(req_body.unwrap());
let req_body: Option<String> = if ! parsed.is_object() {
None
} else {
/*
// my code
// Mask some words for security, like `password`
for k in vec!["password"] {
let obj = parsed.as_object_mut().unwrap();
if let Some(p) = obj.get_mut(k) {
*p = json!("MASKED_FOR_SECURITY");
}
}
*/
Some(parsed.to_string())
};
// DbPool
/*
// my code
let pool = req.app_data::<web::Data<DbPool>>().map(|p| p.clone());
*/
// Exec main function and wait response generated
let mut res = svc.call(req).await?;
let duration = (Utc::now() - begin).num_microseconds();
let status_code = res.status();
// Response headers
let mut headers: HashMap<&str, &str> = HashMap::new();
for (k, v) in res.headers().iter() {
if let Ok(inner) = v.to_str() {
headers.insert(k.as_str(), inner);
}
}
let res_headers = json!(headers).to_string();
// Get response body
let mut res_body = BytesMut::new();
let mut stream = res.take_body();
while let Some(chunk) = stream.next().await {
res_body.extend_from_slice(&chunk?);
}
// Logging
println!("req.domain : {:?}", domain);
println!("req.user_agent : {:?}", user_agent);
println!("req.ip : {:?}", ip);
println!("req.path : {:?}", path);
println!("req.method : {:?}", method);
println!("req.headers: {:?}", req_headers);
println!("req.query : {:?}", queries);
println!("req.body : {:?}", req_body);
println!("duration : {:?}", duration);
println!("res.status : {:?}", status_code);
println!("res.headers: {:?}", res_headers);
println!("res.body : {:?}", res_body);
/*
// my code
let a = AccessLog {
id: None,
protocol: Some(protocol.to_string()).into_iter().find(|v| v != ""),
domain: Some(domain).into_iter().find(|v| v != ""),
ip: ip.map(|inner| inner.to_string()).into_iter().find(|v| v != ""),
method: Some(method).into_iter().find(|v| v != ""),
path: Some(path.to_string()).into_iter().find(|v| v != ""),
query: Some(queries).into_iter().find(|v| v != ""),
user_agent: Some(user_agent),
req_headers: Some(req_headers).into_iter().find(|v| v != ""),
req_body: req_body,
duration: duration.map(|inner| inner as i32),
status_code: Some(status_code.as_u16() as i32),
res_headers: Some(res_headers).into_iter().find(|v| v != ""),
res_body: String::from_utf8(res_body.clone().to_vec()).into_iter().find(|v| v != ""),
others: None,
requested_at: Some(begin.with_timezone(&*TIMEZONE).naive_local()),
created_at: None,
};
if let Some(pool) = pool {
if let Ok(conn) = pool.get() {
if let Err(e) = a.create(&conn) {
eprintln!("database err: {:?}", e);
};
}
}
*/
// return original response body
Ok(res.map_body(|_, _b| ResponseBody::Other(Body::from(res_body))))
})
}
}
#[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> {
#[pin]
body: ResponseBody<B>,
body_accum: BytesMut,
}
#[pin_project::pinned_drop]
impl<B> PinnedDrop for BodyLogger<B> {
fn drop(self: Pin<&mut Self>) {
println!("response body: {:?}", self.body_accum);
}
}
impl<B: MessageBody> MessageBody for BodyLogger<B> {
fn size(&self) -> BodySize {
self.body.size()
}
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
let this = self.project();
match this.body.poll_next(cx) {
Poll::Ready(Some(Ok(chunk))) => {
this.body_accum.extend_from_slice(&chunk);
Poll::Ready(Some(Ok(chunk)))
}
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}
async fn get_request_body(req: &mut ServiceRequest) -> Result<BytesMut, Error> {
// Get body as bytes
let mut bytes: BytesMut = BytesMut::new();
let mut body = req.take_payload();
while let Some(chunk) = body.next().await {
bytes.extend_from_slice(&chunk?);
}
// Set body again
let (_, mut payload) = Payload::create(true);
payload.unread_data(web::Bytes::from(bytes.clone()));
req.set_payload(payload.into());
Ok(bytes)
}
#[derive(Debug, Deserialize, Serialize)]
struct Password {
password: String,
}
fn parse_body(body: BytesMut) -> Value {
let json_parsed = serde_json::from_slice::<Value>(&body);
if let Ok(b) = json_parsed {
return b
}
// let query_parsed = serde_qs::from_bytes::<Password>(&body);
json!(null)
}

Get a raw vec with field names of any struct with a custom derive macro in Rust

I am trying to write some code that could be able to write a method that returns me a Vec with the names of the fields of a struct.
Code snippet below:
# Don't forget about dependencies if you try to reproduce this on local
use proc_macro2::{Span, Ident};
use quote::quote;
use syn::{
punctuated::Punctuated, token::Comma, Attribute, DeriveInput, Fields, Meta, NestedMeta,
Variant, Visibility,
};
#[proc_macro_derive(StructFieldNames, attributes(struct_field_names))]
pub fn derive_field_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();
let (vis, ty, generics) = (&ast.vis, &ast.ident, &ast.generics);
let names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site());
let fields = filter_fields(match ast.data {
syn::Data::Struct(ref s) => &s.fields,
_ => panic!("FieldNames can only be derived for structs"),
});
let names_struct_fields = fields.iter().map(|(vis, ident)| {
quote! {
#vis #ident: &'static str
}
});
let mut vec_fields: Vec<String> = Vec::new();
let names_const_fields = fields.iter().map(|(_vis, ident)| {
let ident_name = ident.to_string();
vec_fields.push(ident_name);
quote! {
#vis #ident: -
}
});
let names_const_fields_as_vec = fields.iter().map(|(_vis, ident)| {
let ident_name = ident.to_string();
// vec_fields.push(ident_name)
});
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let tokens = quote! {
#[derive(Debug)]
#vis struct #names_struct_ident {
#(#names_struct_fields),*
}
impl #impl_generics #ty #ty_generics
#where_clause
{
#vis fn get_field_names() -> &'static str {
// stringify!(
[ #(#vec_fields),* ]
.map( |s| s.to_string())
.collect()
// )
}
}
};
tokens.into()
}
fn filter_fields(fields: &Fields) -> Vec<(Visibility, Ident)> {
fields
.iter()
.filter_map(|field| {
if field
.attrs
.iter()
.find(|attr| has_skip_attr(attr, "struct_field_names"))
.is_none()
&& field.ident.is_some()
{
let field_vis = field.vis.clone();
let field_ident = field.ident.as_ref().unwrap().clone();
Some((field_vis, field_ident))
} else {
None
}
})
.collect::<Vec<_>>()
}
const ATTR_META_SKIP: &'static str = "skip";
fn has_skip_attr(attr: &Attribute, path: &'static str) -> bool {
if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
if meta_list.path.is_ident(path) {
for nested_item in meta_list.nested.iter() {
if let NestedMeta::Meta(Meta::Path(path)) = nested_item {
if path.is_ident(ATTR_META_SKIP) {
return true;
}
}
}
}
}
false
}
The code it's taken from here. Basically I just want to get those values as a String, and not to access them via Foo::FIELD_NAMES.some_random_field, because I need them for another process.
How can I achieve that?
Thanks

refcell rc<refcell<>> doesn't change

Here is my simplified code. I need to change the pdp_state in a function. but the state remain 'a'. I don't figure out why cloning Rc does not work. I also checked this cloning out side a structure an it worked.
#[derive(Clone,Copy)]
enum PDPStatus{
a,
b
}
struct network{
pdp_state:Rc<RefCell<PDPStatus>>,
}
impl network{
fn set(&mut self){
let mut t = *self.pdp_state.clone().borrow_mut();
match t {
a => {let m1 = self.pdp_state.clone();
let mut a = (*m1).borrow_mut() ;
*a = PDPStatus::b;
println!("a");},
b=> {let m1 = self.pdp_state.clone();m1.replace( PDPStatus::a);
println!("b");},
};
}
}
fn main() {
let mut network1 = network::new();
network1.set();
network1.set();
network1.set();
network1.set();
}
Update:
My set function would look like this. I need two closure that have access to pdp_state. I pass these closures as callbacks. I am sure the these closure wouldn't call together.
fn set(&mut self){
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut state = self.pdp_state.clone();
let mut closuree = || state = Rc::new(RefCell::new(PDPStatus::b));
let mut state1 = self.pdp_state.clone();
let mut closuree1 = || state1 = Rc::new(RefCell::new(PDPStatus::b));
closuree();
closuree1();
println!("a");
},
PDPStatus::b => {
let mut closuree = || self.pdp_state = Rc::new(RefCell::new(PDPStatus::a));
closuree();
println!("b");
},
};
}
In the set method, you need to borrow self.pdp_state and then clone() it in a variable, and then match the variable where you cloned it.
Replace the set method with this:
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
self.pdp_state = Rc::new(RefCell::new(PDPStatus::b));
println!("a");
},
PDPStatus::b => {
self.pdp_state = Rc::new(RefCell::new(PDPStatus::a));
println!("b");
},
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=426d4cb7db9a92ee4ddcd4f36dbc12f7
This answer was posted after the question was updated:
EDIT
You can use the replace() method from RefCell
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut closuree = || {
self.pdp_state.replace(PDPStatus::b);
};
let mut closuree1 = || {
self.pdp_state.replace(PDPStatus::b);
};
closuree();
closuree1();
println!("a");
}
PDPStatus::b => {
let mut closuree = || {
self.pdp_state.replace(PDPStatus::a);
};
closuree();
println!("b");
}
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=4af02228d58b2f2c865a525e3f70d6a0
OLD
You could just make the closures take &mut self.pdp_state as an argument, and then update it.
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut closuree = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::b))
};
let mut closuree1 = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::b))
};
closuree(&mut self.pdp_state);
closuree1(&mut self.pdp_state);
println!("a");
}
PDPStatus::b => {
let mut closuree = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::a))
};
closuree(&mut self.pdp_state);
println!("b");
}
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=4af96385b0446082afdb7d615bb8eecb

Rust Command Line History In Reverse Shell

I have this code to listen on a port and get a reverse shell
fn pipe_thread<R, W>(mut r: R, mut w: W) -> std::thread::JoinHandle<()>
where
R: std::io::Read + Send + 'static,
W: std::io::Write + Send + 'static,
{
std::thread::spawn(move || {
let mut buffer = [0; 1024];
loop {
let len = r.read(&mut buffer).unwrap();
if len == 0 {
println!("Connection lost");
std::process::exit(0x0100);
}
w.write(&buffer[..len]).unwrap();
w.flush().unwrap();
}
})
}
fn listen() -> std::io::Result<()> {
let listener = std::net::TcpListener::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
println!("Started listener");
let (stream, _) = listener.accept()?;
let t1 = pipe_thread(std::io::stdin(), stream.try_clone()?);
println!("Connection recieved");
let t2 = pipe_thread(stream, std::io::stdout());
t1.join().unwrap();
t2.join().unwrap();
return Ok(());
}
How would I implement rustyline in this code so if I press the up arrow inside the shell it will put the recent command as input
Basically like if I would run the program with rlwrap but have it built in inside the application
Try this:
Include this in your Cargo.toml
[dependencies]
rustyline = "8.2.0"
Main.rs
use rustyline::error::ReadlineError;
use rustyline::Cmd;
use rustyline::Editor;
use rustyline::KeyEvent;
use std::io::Write;
fn pipe_thread<R, W>(mut r: R, mut w: W) -> std::thread::JoinHandle<()>
where
R: std::io::Read + Send + 'static,
W: std::io::Write + Send + 'static,
{
std::thread::spawn(move || {
let mut buffer = [0; 1024];
loop {
let len = r.read(&mut buffer).unwrap();
if len == 0 {
println!("Connection lost");
std::process::exit(0x0100);
}
w.write(&buffer[..len]).unwrap();
w.flush().unwrap();
}
})
}
fn main() -> std::io::Result<()> {
let listener = std::net::TcpListener::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
println!("Started listener");
let (mut stream, _) = listener.accept()?;
println!("Connection recieved");
let t = pipe_thread(stream.try_clone().unwrap(), std::io::stdout());
let mut rl = Editor::<()>::new();
rl.bind_sequence(KeyEvent::ctrl('R'), Cmd::HistorySearchBackward);
loop {
let readline = rl.readline(">> ");
match readline {
Ok(command) => {
rl.add_history_entry(command.as_str());
println!("{}", command);
// Clone command to increase its lifetime
let command = command.clone() + "\n";
// Send a TCP message
stream
.write(command.as_bytes())
.expect("Faild to send TCP.");
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break;
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
return Ok(());
}

Resources