1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Support for the Firefox browser.

use super::*;

use std::process::{Command, Child, Stdio};
use std::thread;
use std::time::Duration;
use std::ffi::OsString;

use super::util;

pub struct GeckoDriverBuilder {
    driver_binary: OsString,
    port: Option<u16>,
    ff_binary: String,
    kill_on_drop: bool,
}

impl GeckoDriverBuilder {
    pub fn new() -> Self {
        GeckoDriverBuilder {
            driver_binary: "geckodriver".into(),
            port: None,
            ff_binary: "firefox".to_owned(),
            kill_on_drop: true,
        }
    }
    pub fn driver_path<S: Into<OsString>>(mut self, path: S) -> Self {
        self.driver_binary = path.into();
        self
    }
    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }
    pub fn firefox_binary(mut self, binary: &str) -> Self {
        self.ff_binary = binary.to_owned();
        self
    }
    pub fn kill_on_drop(mut self, kill: bool) -> Self {
        self.kill_on_drop = kill;
        self
    }
    pub fn spawn(self) -> Result<GeckoDriver, Error> {
        let port = util::check_tcp_port(self.port)?;

        let child = Command::new(self.driver_binary)
            .arg("-b")
            .arg(self.ff_binary)
            .arg("--port")
            .arg(format!("{}", port))
            .stdin(Stdio::null())
            .stderr(Stdio::null())
            .stdout(Stdio::null())
            .spawn()?;

        // TODO: parameterize this
        thread::sleep(Duration::new(1, 500));
        Ok(GeckoDriver {
            child: child,
            url: format!("http://localhost:{}", port),
            kill_on_drop: self.kill_on_drop,
        })
    }
}


/// A geckodriver process
pub struct GeckoDriver {
    child: Child,
    url: String,
    kill_on_drop: bool,
}

impl GeckoDriver {
    pub fn spawn() -> Result<Self, Error> {
        GeckoDriverBuilder::new().spawn()
    }
    pub fn build() -> GeckoDriverBuilder {
        GeckoDriverBuilder::new()
    }
}

impl Drop for GeckoDriver {
    fn drop(&mut self) {
        if self.kill_on_drop {
            let _ = self.child.kill();
        }
    }
}

impl Driver for GeckoDriver {
    fn url(&self) -> &str {
        &self.url
    }
}