This commit is contained in:
James Graham 2015-02-23 19:19:49 +00:00
Родитель 1592a91505
Коммит 8bf036c35e
9 изменённых файлов: 120 добавлений и 103 удалений

120
Cargo.lock сгенерированный
Просмотреть файл

@ -2,60 +2,67 @@
name = "webdriver" name = "webdriver"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"hyper 0.1.1 (git+https://github.com/servo/hyper?branch=old_servo_new_cookies)", "hyper 0.2.0 (git+https://github.com/hyperium/hyper)",
"log 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.1.8" version = "0.1.12"
source = "git+https://github.com/servo/cookie-rs?branch=lenientparse_backport#47ffa4d3c6f85d28f222d6e1d54635fff5622ea3" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"openssl 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.1.4" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.1.1" version = "0.2.0"
source = "git+https://github.com/servo/hyper?branch=old_servo_new_cookies#7a346f481d683705709526594aa5f13b5c923bc1" source = "git+https://github.com/hyperium/hyper#0185afea911d3d97191b35dd19b8af262407fab1"
dependencies = [ dependencies = [
"cookie 0.1.8 (git+https://github.com/servo/cookie-rs?branch=lenientparse_backport)", "cookie 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mucell 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unsafe-any 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unsafe-any 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "libc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libressl-pnacl-sys" name = "libressl-pnacl-sys"
version = "2.1.0" version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pnacl-build-helper 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "log" name = "log"
version = "0.1.9" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "matches" name = "matches"
@ -64,86 +71,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.0.6" version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"log 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "mucell"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.2.15" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"openssl-sys 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.2.15" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libressl-pnacl-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libressl-pnacl-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.1.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "pnacl-build-helper" name = "pnacl-build-helper"
version = "1.0.0" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "0.1.10" version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustc-serialize" name = "rustc-serialize"
version = "0.2.7" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.12" version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "0.0.2" version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unsafe-any" name = "unsafe-any"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "url" name = "url"
version = "0.2.16" version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.1.7" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"rustc-serialize 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

Просмотреть файл

@ -5,10 +5,11 @@ version = "0.0.1"
authors = ["James Graham <james@hoppipolla.co.uk>"] authors = ["James Graham <james@hoppipolla.co.uk>"]
[dependencies] [dependencies]
log = "0.1.9" log = "0.2.4"
rustc-serialize = "0.2.7" regex = "0.1.15"
uuid = "0.1.7" rustc-serialize = "0.2.15"
uuid = "0.1.10"
[dependencies.hyper] [dependencies.hyper]
git = "https://github.com/servo/hyper" git = "https://github.com/hyperium/hyper"
branch = "old_servo_new_cookies" branch = "master"

Просмотреть файл

@ -81,7 +81,7 @@ impl WebDriverMessage {
} }
}, },
Err(_) => return Err(WebDriverError::new(ErrorStatus::InvalidArgument, Err(_) => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
format!("Failed to decode request body as json: {}", body).as_slice())) &format!("Failed to decode request body as json: {}", body)[..]))
} }
} else { } else {
Json::Null Json::Null

Просмотреть файл

@ -1,14 +1,14 @@
use core::num::ToPrimitive; use rustc_serialize::json::{Json, ToJson};
use rustc_serialize::json::{Json, ToJson, ParserError};
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::error::{Error, FromError}; use std::error::{Error, FromError};
use std::num::ToPrimitive;
use error::{WebDriverResult, WebDriverError, ErrorStatus}; use error::{WebDriverResult, WebDriverError, ErrorStatus};
static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf"; static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";
#[derive(RustcEncodable, PartialEq, Show)] #[derive(RustcEncodable, PartialEq, Debug)]
pub struct Date(u64); pub struct Date(u64);
impl Date { impl Date {
@ -24,7 +24,7 @@ impl ToJson for Date {
} }
} }
#[derive(PartialEq, Clone, Show)] #[derive(PartialEq, Clone, Debug)]
pub enum Nullable<T: ToJson> { pub enum Nullable<T: ToJson> {
Value(T), Value(T),
Null Null

Просмотреть файл

@ -1,8 +1,9 @@
use rustc_serialize::json::{Json, ToJson, ParserError}; use rustc_serialize::json::{Json, ToJson, ParserError};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::error::{Error, FromError}; use std::error::{Error, FromError};
use std::fmt;
#[derive(PartialEq, Show)] #[derive(PartialEq, Debug)]
pub enum ErrorStatus { pub enum ErrorStatus {
ElementNotSelectable, ElementNotSelectable,
ElementNotVisible, ElementNotVisible,
@ -32,12 +33,18 @@ pub enum ErrorStatus {
pub type WebDriverResult<T> = Result<T, WebDriverError>; pub type WebDriverResult<T> = Result<T, WebDriverError>;
#[derive(Show)] #[derive(Debug)]
pub struct WebDriverError { pub struct WebDriverError {
pub status: ErrorStatus, pub status: ErrorStatus,
pub message: String pub message: String
} }
impl fmt::Display for WebDriverError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.message.fmt(f)
}
}
impl WebDriverError { impl WebDriverError {
pub fn new(status: ErrorStatus, message: &str) -> WebDriverError { pub fn new(status: ErrorStatus, message: &str) -> WebDriverError {
WebDriverError { WebDriverError {
@ -123,10 +130,6 @@ impl Error for WebDriverError {
self.status_code() self.status_code()
} }
fn detail(&self) -> Option<String> {
Some(self.message.clone())
}
fn cause(&self) -> Option<&Error> { fn cause(&self) -> Option<&Error> {
None None
} }
@ -135,6 +138,6 @@ impl Error for WebDriverError {
impl FromError<ParserError> for WebDriverError { impl FromError<ParserError> for WebDriverError {
fn from_error(err: ParserError) -> WebDriverError { fn from_error(err: ParserError) -> WebDriverError {
let msg = format!("{:?}", err); let msg = format!("{:?}", err);
WebDriverError::new(ErrorStatus::UnknownError, msg.as_slice()) WebDriverError::new(ErrorStatus::UnknownError, &msg[..])
} }
} }

Просмотреть файл

@ -6,7 +6,7 @@ use hyper::method::Method::{Get, Post, Delete};
use command::{WebDriverMessage}; use command::{WebDriverMessage};
use error::{WebDriverResult, WebDriverError, ErrorStatus}; use error::{WebDriverResult, WebDriverError, ErrorStatus};
static routes: [(Method, &'static str, Route); 41] = [ static ROUTES: [(Method, &'static str, Route); 41] = [
(Post, "/session", Route::NewSession), (Post, "/session", Route::NewSession),
(Delete, "/session/{sessionId}", Route::DeleteSession), (Delete, "/session/{sessionId}", Route::DeleteSession),
(Post, "/session/{sessionId}/url", Route::Get), (Post, "/session/{sessionId}/url", Route::Get),
@ -122,22 +122,22 @@ impl RequestMatcher {
fn compile_path(path: &str) -> Regex { fn compile_path(path: &str) -> Regex {
let mut rv = String::new(); let mut rv = String::new();
rv.push_str("^"); rv.push_str("^");
let mut components = path.split('/'); let components = path.split('/');
for component in components { for component in components {
if component.starts_with("{") { if component.starts_with("{") {
if !component.ends_with("}") { if !component.ends_with("}") {
panic!("Invalid url pattern") panic!("Invalid url pattern")
} }
rv.push_str(format!("(?P<{}>[^/]+)/", &component[1..component.len()-1]).as_slice()); rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
} else { } else {
rv.push_str(format!("{}/", component).as_slice()); rv.push_str(&format!("{}/", component)[..]);
} }
} }
//Remove the trailing / //Remove the trailing /
rv.pop(); rv.pop();
rv.push_str("$"); rv.push_str("$");
//This will fail at runtime if the regexp is invalid //This will fail at runtime if the regexp is invalid
Regex::new(rv.as_slice()).unwrap() Regex::new(&rv[..]).unwrap()
} }
} }
@ -151,7 +151,7 @@ impl WebDriverHttpApi {
routes: vec![] routes: vec![]
}; };
debug!("Creating routes"); debug!("Creating routes");
for &(ref method, ref url, ref match_type) in routes.iter() { for &(ref method, ref url, ref match_type) in ROUTES.iter() {
rv.add(method.clone(), *url, *match_type); rv.add(method.clone(), *url, *match_type);
}; };
rv rv
@ -180,6 +180,6 @@ impl WebDriverHttpApi {
} }
} }
Err(WebDriverError::new(error, Err(WebDriverError::new(error,
format!("{} {} did not match a known command", method, path).as_slice())) &format!("{} {} did not match a known command", method, path)[..]))
} }
} }

Просмотреть файл

@ -1,10 +1,10 @@
//Until it's clear what the unstable things are replaced by #![feature(old_io)]
#![allow(unstable)] #![feature(core)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[macro_use] extern crate log; #[macro_use]
extern crate log;
extern crate "rustc-serialize" as rustc_serialize; extern crate "rustc-serialize" as rustc_serialize;
extern crate core;
extern crate hyper; extern crate hyper;
extern crate regex; extern crate regex;

Просмотреть файл

@ -1,9 +1,8 @@
use rustc_serialize::json; use rustc_serialize::json;
use rustc_serialize::json::ToJson;
use common::{Nullable, Date}; use common::{Nullable, Date};
#[derive(Show)] #[derive(Debug)]
pub enum WebDriverResponse { pub enum WebDriverResponse {
NewSession(NewSessionResponse), NewSession(NewSessionResponse),
DeleteSession, DeleteSession,
@ -16,19 +15,19 @@ pub enum WebDriverResponse {
impl WebDriverResponse { impl WebDriverResponse {
pub fn to_json_string(self) -> String { pub fn to_json_string(self) -> String {
match self { (match self {
WebDriverResponse::NewSession(x) => json::encode(&x), WebDriverResponse::NewSession(x) => json::encode(&x),
WebDriverResponse::DeleteSession => "{}".to_string(), WebDriverResponse::DeleteSession => Ok("{}".to_string()),
WebDriverResponse::WindowSize(x) => json::encode(&x), WebDriverResponse::WindowSize(x) => json::encode(&x),
WebDriverResponse::ElementRect(x) => json::encode(&x), WebDriverResponse::ElementRect(x) => json::encode(&x),
WebDriverResponse::Cookie(x) => json::encode(&x), WebDriverResponse::Cookie(x) => json::encode(&x),
WebDriverResponse::Generic(x) => json::encode(&x), WebDriverResponse::Generic(x) => json::encode(&x),
WebDriverResponse::Void => "{}".to_string() WebDriverResponse::Void => Ok("{}".to_string())
} }).unwrap()
} }
} }
#[derive(RustcEncodable, Show)] #[derive(RustcEncodable, Debug)]
pub struct NewSessionResponse { pub struct NewSessionResponse {
pub sessionId: String, pub sessionId: String,
pub value: json::Json pub value: json::Json
@ -43,7 +42,7 @@ impl NewSessionResponse {
} }
} }
#[derive(RustcEncodable, Show)] #[derive(RustcEncodable, Debug)]
pub struct ValueResponse { pub struct ValueResponse {
value: json::Json value: json::Json
} }
@ -56,7 +55,7 @@ impl ValueResponse {
} }
} }
#[derive(RustcEncodable, Show)] #[derive(RustcEncodable, Debug)]
pub struct WindowSizeResponse { pub struct WindowSizeResponse {
width: u64, width: u64,
height: u64 height: u64
@ -71,7 +70,7 @@ impl WindowSizeResponse {
} }
} }
#[derive(RustcEncodable, Show)] #[derive(RustcEncodable, Debug)]
pub struct ElementRectResponse { pub struct ElementRectResponse {
x: u64, x: u64,
y: u64, y: u64,
@ -91,7 +90,7 @@ impl ElementRectResponse {
} }
//TODO: some of these fields are probably supposed to be optional //TODO: some of these fields are probably supposed to be optional
#[derive(RustcEncodable, PartialEq, Show)] #[derive(RustcEncodable, PartialEq, Debug)]
pub struct Cookie { pub struct Cookie {
name: String, name: String,
value: String, value: String,
@ -119,7 +118,7 @@ impl Cookie {
} }
} }
#[derive(RustcEncodable, Show)] #[derive(RustcEncodable, Debug)]
pub struct CookieResponse { pub struct CookieResponse {
value: Vec<Cookie> value: Vec<Cookie>
} }

Просмотреть файл

@ -1,10 +1,10 @@
use std::io::net::ip::IpAddr; use std::old_io::net::ip::IpAddr;
use std::num::FromPrimitive; use std::num::FromPrimitive;
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::Thread; use std::thread;
use hyper::header::common::ContentLength; use hyper::header::ContentLength;
use hyper::method::Method; use hyper::method::Method;
use hyper::server::{Server, Handler, Request, Response}; use hyper::server::{Server, Handler, Request, Response};
use hyper::uri::RequestUri::AbsolutePath; use hyper::uri::RequestUri::AbsolutePath;
@ -91,9 +91,9 @@ impl<T: WebDriverHandler> Dispatcher<T> {
if existing_session.id != *msg_session_id { if existing_session.id != *msg_session_id {
Err(WebDriverError::new( Err(WebDriverError::new(
ErrorStatus::InvalidSessionId, ErrorStatus::InvalidSessionId,
format!("Got unexpected session id {} expected {}", &format!("Got unexpected session id {} expected {}",
msg_session_id, msg_session_id,
existing_session.id).as_slice())) existing_session.id)[..]))
} else { } else {
Ok(()) Ok(())
} }
@ -165,7 +165,7 @@ impl Handler for HttpHandler {
// matter as long as we are only handling one request at a time. // matter as long as we are only handling one request at a time.
match self.api.lock() { match self.api.lock() {
Ok(ref api) => { Ok(ref api) => {
api.decode_request(req.method, path.as_slice(), body.as_slice()) api.decode_request(req.method, &path[..], &body[..])
}, },
Err(_) => return Err(_) => return
} }
@ -215,7 +215,7 @@ impl Handler for HttpHandler {
} }
res.headers_mut().set(ContentLength(resp_body.len() as u64)); res.headers_mut().set(ContentLength(resp_body.len() as u64));
let mut stream = res.start(); let mut stream = res.start();
stream.write_str(resp_body.as_slice()).unwrap(); stream.write_str(&resp_body[..]).unwrap();
stream.unwrap().end().unwrap(); stream.unwrap().end().unwrap();
}, },
_ => {} _ => {}
@ -223,12 +223,12 @@ impl Handler for HttpHandler {
} }
} }
pub fn start<T: WebDriverHandler>(ip_address: IpAddr, port: u16, handler: T) { pub fn start<T: 'static+WebDriverHandler>(ip_address: IpAddr, port: u16, handler: T) {
let server = Server::http(ip_address, port); let server = Server::http(ip_address, port);
let (msg_send, msg_recv) = channel(); let (msg_send, msg_recv) = channel();
Thread::spawn(move || { thread::spawn(move || {
let mut dispatcher = Dispatcher::new(handler); let mut dispatcher = Dispatcher::new(handler);
dispatcher.run(msg_recv) dispatcher.run(msg_recv)
}); });