Skip Navigation

Search

Is there a way to start and stop chromedriver/geckodriver with Rust and Selenium (thirtyfour) automatically like in Python?

So, apparently the chrome/geckodriver processes will terminate on their own if the user sends ctrl+c to the console. It will not terminate on its own if the program finishes running naturally.

If you're interested in terminating it on your own, like I also was, here is how I went about it.

``` use std::process::{Child, Command};

fn main() { let mut s = Server::default(); s.start(); s.shutdown(); }

struct Server { child: Option<Child> }

impl Default for Server { fn default() -> Self { Self { child: None } } }

impl Server { fn start(&mut self) { self.child = Some(Command::new("./chromedriver") .spawn() .expect("ls command failed to start")); }

fn shutdown(&mut self) { input(None); // wait for input so you can observe the process self.child.as_mut().unwrap().kill(); self.child.as_mut().unwrap().wait(); println!("shutdown"); } }

pub fn input(prompt: Option<String>) { let mut input = String::new(); match prompt { Some(prompt) => println!("{}", prompt), None => () } io::stdin().read_line(&mut input).expect("Failed to read input"); } ```

1

Rust-analyzer only somewhat working?

The autocompletion works (mostly) but for example Vec::new() doesn't highlight anything at all. I do get errors when not putting a semicolon, but things like passing too many arguments into the println macro doesn't throw an error. Or how shown in this example, it did not autocomplete the clone method, while also just accepting .clo; at the end of a String (it also didn't autocomplete "String"). In the video I show how it also gives me a recommendation for setting vec![] as a type, which doesn't make any sense. It only seems to a very limited selection of methods and some words I already used in the script. Is this how it's supposed to be, or do I have some very old version perhaps?

EDIT: Look in description for the fix

3

Borrow checker woes - lifetime of borrowed var vs closure.

Ed: solved with the help of the async_stream crate.

I'm struggling with the borrow checker!

My problem: I'm using actix-web and rusqlite. I want to return an unlimited number of records from an rusqlite query, and actix provides a Stream trait for that kind of thing. You just impl the trait and return your records from a poll_next() fn.

On the rusqlite side, there's this query_map that returns an iterator of records from a query. All I have to do is smush these two features together.

So the plan is to put the iterator returned by query_map into a struct that impls Stream. Problem is the lifetime of a var used by query_map. How to make the var have the same lifetime as the iterator??

So here's the code:

``` pub struct ZkNoteStream<'a, T> { rec_iter: Box<dyn Iterator<Item = T> + 'a>, }

// impl of Stream just calls next() on the iterator. This compiles fine. impl<'a> Stream for ZkNoteStream<'a, serde_json::Value> { type Item = serde_json::Value;

fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { Poll::Ready(self.rec_iter.next()) } }

// init function to set up the ZkNoteStream. impl<'a> ZkNoteStream<'a, Result<ZkListNote, rusqlite::Error>> { pub fn init( conn: &'a Connection, user: i64, search: &ZkNoteSearch, ) -> Result<Self, Box<dyn Error>> { let (sql, args) = build_sql(&conn, user, search.clone())?;

let sysid = user_id(&conn, "system")?; let mut pstmt = conn.prepare(sql.as_str())?;

// Here's the problem! Borrowing pstmt. let rec_iter = pstmt.query_map(rusqlite::params_from_iter(args.iter()), move |row| { let id = row.get(0)?; let sysids = get_sysids(&conn, sysid, id)?; Ok(ZkListNote { id: id, title: row.get(1)?, is_file: { let wat: Option<i64> = row.get(2)?; wat.is_some() }, user: row.get(3)?, createdate: row.get(4)?, changeddate: row.get(5)?, sysids: sysids, }) })?;

Ok(ZkNoteStream::<Result<ZkListNote, rusqlite::Error>> { rec_iter: Box::new(rec_iter), }) } }

```

And here's the error:

error[E0515]: cannot return value referencing local variable `pstmt` --> server-lib/src/search.rs:170:5 | 153 | let rec_iter = pstmt.query_map(rusqlite::params_from_iter(args.iter()), move |row| { | ----- `pstmt` is borrowed here ... 170 | / Ok(ZkNoteStream::<Result<ZkListNote, rusqlite::Error>> { 171 | | rec_iter: Box::new(rec_iter), 172 | | }) | |______^ returns a value referencing data owned by the current function

So basically it boils down to pstmt getting borrowed in the query_map call. It needs to have the same lifetime as the closure. How do I ensure that?

3