Skip to content

Commit

Permalink
Auto merge of #5610 - jgraham:jgraham/webdriver-get, r=jdm
Browse files Browse the repository at this point in the history
This is incomplete in several ways:

* It assumes that there's only one constellation (i.e. top level browsing context), ever.
* The session support is very basic indeed (no capabilities)
* Passing channels over channels may not sit well with IPC
* The error handling is mostly missing

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5610)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Apr 16, 2015
2 parents 0307caa + 009e2ba commit af2f46b
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 17 deletions.
3 changes: 3 additions & 0 deletions components/compositing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ path = "../net_traits"
[dependencies.util]
path = "../util"

[dependencies.webdriver_server]
path = "../webdriver_server"

[dependencies.devtools_traits]
path = "../devtools_traits"

Expand Down
14 changes: 13 additions & 1 deletion components/compositing/constellation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -383,6 +383,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
subpage_id,
event);
}
ConstellationMsg::GetRootPipeline(resp_chan) => {
debug!("constellation got get root pipeline message");
self.handle_get_root_pipeline(resp_chan);
}
}
true
}
Expand Down Expand Up @@ -679,6 +683,14 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipeline.trigger_mozbrowser_event(subpage_id, event);
}

fn handle_get_root_pipeline(&mut self, resp_chan: Sender<Option<PipelineId>>) {
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) => {
Expand Down
1 change: 1 addition & 0 deletions components/compositing/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions components/msg/constellation_msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<PipelineId>>)
}

// https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events
Expand Down
8 changes: 7 additions & 1 deletion components/servo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions components/servo/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand Down
13 changes: 12 additions & 1 deletion components/webdriver_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
git = "https://github.com/jgraham/webdriver-rust.git"

[dependencies]
rustc-serialize="0.3.4"
url = "0.2.16"
uuid = "0.1.11"
114 changes: 106 additions & 8 deletions components/webdriver_server/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 msg::constellation_msg::{ConstellationChan, LoadData};
use msg::constellation_msg::Msg as ConstellationMsg;
use std::sync::mpsc::channel;

use webdriver::command::WebDriverMessage;
use webdriver::error::WebDriverResult;
use webdriver::response::WebDriverResponse;
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, constellation_chan: ConstellationChan) {
let handler = Handler::new(constellation_chan);

pub fn start_server(port: u16) {
server::start(IpAddr::new_v4(0, 0, 0, 0), port, Handler);
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<Session>, _msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse> {
struct Handler {
session: Option<WebdriverSession>,
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<WebDriverResponse> {
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<WebDriverResponse> {
let url = match Url::parse(&parameters.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 handle_get_window_handle(&self) -> WebDriverResult<WebDriverResponse> {
// 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<Session>, msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse> {

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<Session>) {
self.session = None;
}
}
8 changes: 7 additions & 1 deletion ports/cef/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion ports/gonk/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit af2f46b

Please sign in to comment.