diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index ff8082bcf1f..d9fc51499fb 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -31,6 +31,9 @@ path = "../net_traits" [dependencies.util] path = "../util" +[dependencies.webdriver_server] +path = "../webdriver_server" + [dependencies.devtools_traits] path = "../devtools_traits" diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 9f0e98e2e30..3d098fbe01e 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -32,7 +32,7 @@ use std::collections::HashMap; use std::io::{self, Write}; use std::marker::PhantomData; use std::mem::replace; -use std::sync::mpsc::{Receiver, channel}; +use std::sync::mpsc::{Sender, Receiver, channel}; use url::Url; use util::cursor::Cursor; use util::geometry::PagePx; @@ -383,6 +383,10 @@ impl Constellation { subpage_id, event); } + ConstellationMsg::GetRootPipeline(resp_chan) => { + debug!("constellation got get root pipeline message"); + self.handle_get_root_pipeline(resp_chan); + } } true } @@ -679,6 +683,14 @@ impl Constellation { pipeline.trigger_mozbrowser_event(subpage_id, event); } + fn handle_get_root_pipeline(&mut self, resp_chan: Sender>) { + let pipeline_id = self.root_frame_id.map(|frame_id| { + let frame = self.frames.get(&frame_id).unwrap(); + frame.current + }); + resp_chan.send(pipeline_id).unwrap(); + } + fn add_or_replace_pipeline_in_frame_tree(&mut self, frame_change: FrameChange) { let evicted_frames = match frame_change.old_pipeline_id { Some(old_pipeline_id) => { diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index 23f8f76d0ba..e98f03f4a73 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -27,6 +27,7 @@ extern crate net_traits; #[macro_use] extern crate util; extern crate gleam; +extern crate webdriver_server; extern crate libc; extern crate time; diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index d1d2822e3fc..2097d658b0f 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -218,6 +218,8 @@ pub enum Msg { ChangeRunningAnimationsState(PipelineId, bool), /// Requests that the constellation instruct layout to begin a new tick of the animation. TickAnimation(PipelineId), + // Request that the constellation send the current root pipeline id over a provided channel + GetRootPipeline(Sender>) } // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 15a82748036..602d8af177b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -109,6 +109,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_server 0.0.1", ] [[package]] @@ -1004,7 +1005,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#906806d51783b5caad89432bf8ce008f2f4968fc" +source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1017,6 +1018,11 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ + "msg 0.0.1", + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "util 0.0.1", + "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", ] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 7b4423f608c..1be279d5528 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -104,10 +104,6 @@ impl Browser { devtools::start_server(port) }); - if let Some(port) = opts.webdriver_port { - webdriver_server::start_server(port); - } - // Create the constellation, which maintains the engine // pipelines, including the script and layout threads, as well // as the navigation context. @@ -118,6 +114,10 @@ impl Browser { mem_profiler_chan.clone(), shared_task_pool); + if let Some(port) = opts.webdriver_port { + webdriver_server::start_server(port, constellation_chan.clone()); + }; + // The compositor coordinates with the client window to create the final // rendered page and display it somewhere. let compositor = CompositorTask::create(window, diff --git a/components/webdriver_server/Cargo.toml b/components/webdriver_server/Cargo.toml index ec68305b885..337f8a6498a 100644 --- a/components/webdriver_server/Cargo.toml +++ b/components/webdriver_server/Cargo.toml @@ -7,5 +7,16 @@ authors = ["The Servo Project Developers"] name = "webdriver_server" path = "lib.rs" +[dependencies.msg] +path = "../msg" + +[dependencies.util] +path = "../util" + [dependencies.webdriver] -git = "https://github.com/jgraham/webdriver-rust.git" \ No newline at end of file +git = "https://github.com/jgraham/webdriver-rust.git" + +[dependencies] +rustc-serialize="0.3.4" +url = "0.2.16" +uuid = "0.1.11" \ No newline at end of file diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 5377106654a..e8a1f4771b8 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -6,27 +6,125 @@ #![crate_type = "rlib"] #![feature(net)] +#![feature(rustc_private)] + +#[macro_use] +extern crate log; extern crate webdriver; +extern crate msg; +extern crate url; +extern crate util; +extern crate "rustc-serialize" as rustc_serialize; +extern crate uuid; -use webdriver::command::WebDriverMessage; -use webdriver::error::WebDriverResult; -use webdriver::response::WebDriverResponse; +use msg::constellation_msg::{ConstellationChan, LoadData}; +use msg::constellation_msg::Msg as ConstellationMsg; +use std::sync::mpsc::channel; + +use url::Url; +use webdriver::command::{WebDriverMessage, WebDriverCommand}; +use webdriver::command::GetParameters; +use webdriver::response::{ + WebDriverResponse, NewSessionResponse, ValueResponse}; use webdriver::server::{self, WebDriverHandler, Session}; +use webdriver::error::{WebDriverResult, WebDriverError, ErrorStatus}; +use util::task::spawn_named; +use uuid::Uuid; +use std::borrow::ToOwned; use std::net::IpAddr; +use rustc_serialize::json::{Json, ToJson}; +use std::collections::BTreeMap; -pub fn start_server(port: u16) { - server::start(IpAddr::new_v4(0, 0, 0, 0), port, Handler); +pub fn start_server(port: u16, constellation_chan: ConstellationChan) { + let handler = Handler::new(constellation_chan); + + spawn_named("WebdriverHttpServer".to_owned(), move || { + server::start(IpAddr::new_v4(0, 0, 0, 0), port, handler); + }); } -struct Handler; +struct WebdriverSession { + id: Uuid +} -impl WebDriverHandler for Handler { - fn handle_command(&mut self, _session: &Option, _msg: &WebDriverMessage) -> WebDriverResult { +struct Handler { + session: Option, + constellation_chan: ConstellationChan +} + +impl WebdriverSession { + pub fn new() -> WebdriverSession { + WebdriverSession { + id: Uuid::new_v4() + } + } +} + +impl Handler { + pub fn new(constellation_chan: ConstellationChan) -> Handler { + Handler { + session: None, + constellation_chan: constellation_chan + } + } + + fn handle_new_session(&mut self) -> WebDriverResult { + if self.session.is_none() { + let session = WebdriverSession::new(); + let rv = Ok(WebDriverResponse::NewSession( + NewSessionResponse::new( + session.id.to_string(), + Json::Object(BTreeMap::new())))); + self.session = Some(session); + rv + } else { + Err(WebDriverError::new(ErrorStatus::UnknownError, + "Session already created")) + } + } + + fn handle_get(&self, parameters: &GetParameters) -> WebDriverResult { + let url = match Url::parse(¶meters.url[..]) { + Ok(url) => url, + Err(_) => return Err(WebDriverError::new(ErrorStatus::InvalidArgument, + "Invalid URL")) + }; + + let (sender, reciever) = channel(); + let ConstellationChan(ref const_chan) = self.constellation_chan; + const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap(); + + let pipeline_id = reciever.recv().unwrap().unwrap(); + + let load_data = LoadData::new(url); + const_chan.send(ConstellationMsg::LoadUrl(pipeline_id, load_data)).unwrap(); + //TODO: Now we ought to wait until we get a load event Ok(WebDriverResponse::Void) } - fn delete_session(&mut self, _session: &Option) { + fn handle_get_window_handle(&self) -> WebDriverResult { + // For now we assume there's only one window so just use the session + // id as the window id + let handle = self.session.as_ref().unwrap().id.to_string(); + Ok(WebDriverResponse::Generic(ValueResponse::new(handle.to_json()))) + } +} + +impl WebDriverHandler for Handler { + fn handle_command(&mut self, _session: &Option, msg: &WebDriverMessage) -> WebDriverResult { + + match msg.command { + WebDriverCommand::NewSession => self.handle_new_session(), + WebDriverCommand::Get(ref parameters) => self.handle_get(parameters), + WebDriverCommand::GetWindowHandle => self.handle_get_window_handle(), + _ => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, + "Command not implemented")) + } + } + + fn delete_session(&mut self, _session: &Option) { + self.session = None; } } diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 60ad7527f97..d8a540d7a4c 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -111,6 +111,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_server 0.0.1", ] [[package]] @@ -1007,7 +1008,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#906806d51783b5caad89432bf8ce008f2f4968fc" +source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1020,6 +1021,11 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ + "msg 0.0.1", + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "util 0.0.1", + "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", ] diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 9abf50ea0b3..91ab0d004d0 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -91,6 +91,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_server 0.0.1", ] [[package]] @@ -923,7 +924,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#906806d51783b5caad89432bf8ce008f2f4968fc" +source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -936,6 +937,11 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ + "msg 0.0.1", + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "util 0.0.1", + "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", ]