From a8d01bf85b80c0ef46d33f1e535fbef351b21efd Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 19 Nov 2015 19:00:06 -0800 Subject: [PATCH] http module is fully generic over SemanticEngine The /find_definition and /list_completions handlers now longer assume and create a Racer for every request. A SemanticEngine instance is now passed into http::serve. It is boxed up and attached to each request. --- src/bin/racerd.rs | 23 ++++++++++++++++++----- src/engine/racer.rs | 1 - src/http/completion.rs | 13 ++++++++----- src/http/definition.rs | 13 ++++++++----- src/http/mod.rs | 34 +++++++++++++++++++++++++--------- src/lib.rs | 4 ++++ tests/util/http.rs | 18 ++++++++++++------ 7 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/bin/racerd.rs b/src/bin/racerd.rs index c24ec383..6a943179 100644 --- a/src/bin/racerd.rs +++ b/src/bin/racerd.rs @@ -2,6 +2,9 @@ extern crate docopt; extern crate rustc_serialize; extern crate libracerd; +use libracerd::{Config, engine, http}; +use libracerd::engine::SemanticEngine; + use std::convert::Into; use docopt::Docopt; @@ -11,7 +14,7 @@ const USAGE: &'static str = " racerd - a JSON/HTTP layer on top of racer Usage: - racerd serve --secret-file= [--port=] [-l] [--rustc-src-path=] + racerd serve --secret-file= [--port=] [-l] [--rust-src-path=] racerd (-h | --help) racerd --version @@ -34,9 +37,9 @@ struct Args { cmd_serve: bool } -impl Into for Args { - fn into(self) -> libracerd::Config { - libracerd::Config { +impl Into for Args { + fn into(self) -> Config { + Config { port: self.flag_port as u16, secret_file: self.flag_secret_file, print_http_logs: self.flag_logging, @@ -46,6 +49,7 @@ impl Into for Args { } fn main() { + // Parse arguments let args: Args = Docopt::new(USAGE) .and_then(|d| d.decode()) .unwrap_or_else(|e| e.exit()); @@ -56,5 +60,14 @@ fn main() { ::std::process::exit(0); } - libracerd::http::serve(&args.into()).unwrap(); + // build config object + let config: Config = args.into(); + + // TODO start specified semantic engine. For now, hard coded racer. + let racer = engine::Racer; + racer.initialize(&config).unwrap(); + + // Start serving + let server = http::serve(&config, racer).unwrap(); + println!("racerd listening at {}", server.addr()); } diff --git a/src/engine/racer.rs b/src/engine/racer.rs index 4e568625..77d1997a 100644 --- a/src/engine/racer.rs +++ b/src/engine/racer.rs @@ -1,6 +1,5 @@ //! SemanticEngine implementation for [the racer library](https://github.com/phildawes/racer) //! -use std::path::Path; use engine::{SemanticEngine, Definition, Context, CursorPosition, Completion}; use racer::core::Session; diff --git a/src/http/completion.rs b/src/http/completion.rs index 15615796..666d9fa0 100644 --- a/src/http/completion.rs +++ b/src/http/completion.rs @@ -1,10 +1,11 @@ use iron::prelude::*; use iron::status; +use iron::mime::Mime; -use http::definition; use rustc_serialize::json; -use engine::{SemanticEngine, Racer, Completion, Context, CursorPosition, Buffer}; +use engine::{SemanticEngine, Completion, Context, CursorPosition, Buffer}; +use super::EngineProvider; /// Given a location, return a list of possible completions pub fn list(req: &mut Request) -> IronResult { @@ -23,13 +24,15 @@ pub fn list(req: &mut Request) -> IronResult { } }; - let racer = Racer; - match racer.list_completions(&lcr.context()) { + let mutex = req.get::<::persistent::Write>().unwrap(); + let engine = mutex.lock().unwrap(); + match engine.list_completions(&lcr.context()) { // 200 OK; found the definition Ok(Some(completions)) => { trace!("got a match"); let res = completions.into_iter().map(|c| CompletionResponse::from(c)).collect::>(); - Ok(Response::with((status::Ok, json::encode(&res).unwrap()))) + let content_type = "application/json".parse::().unwrap(); + Ok(Response::with((content_type, status::Ok, json::encode(&res).unwrap()))) }, // 204 No Content; Everything went ok, but the definition was not found. diff --git a/src/http/definition.rs b/src/http/definition.rs index d3715db0..85090cf0 100644 --- a/src/http/definition.rs +++ b/src/http/definition.rs @@ -1,10 +1,12 @@ //! Provider for finding definitions use iron::prelude::*; use iron::status; +use iron::mime::Mime; use rustc_serialize::json; -use engine::{SemanticEngine, Racer, Definition, Context, CursorPosition, Buffer}; +use engine::{SemanticEngine, Definition, Context, CursorPosition, Buffer}; +use super::EngineProvider; /// Given a location, return where the identifier is defined /// @@ -33,14 +35,15 @@ pub fn find(req: &mut Request) -> IronResult { } }; - // Delegate to active semantic engine - let racer = Racer; - match racer.find_definition(&fdr.context()) { + let mutex = req.get::<::persistent::Write>().unwrap(); + let engine = mutex.lock().unwrap(); + match engine.find_definition(&fdr.context()) { // 200 OK; found the definition Ok(Some(definition)) => { trace!("definition::find got a match"); let res = FindDefinitionResponse::from(definition); - Ok(Response::with((status::Ok, json::encode(&res).unwrap()))) + let content_type = "application/json".parse::().unwrap(); + Ok(Response::with((content_type, status::Ok, json::encode(&res).unwrap()))) }, // 204 No Content; Everything went ok, but the definition was not found. diff --git a/src/http/mod.rs b/src/http/mod.rs index 8e46213c..f503f159 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -41,7 +41,7 @@ //! //! ☐ File compilation -use iron::{Iron, Chain}; +use iron::prelude::*; use ::Config; @@ -50,6 +50,10 @@ mod file; mod completion; mod ping; +use ::engine::SemanticEngine; + +use iron::typemap::Key; + /// Errors occurring in the http module #[derive(Debug)] pub enum Error { @@ -67,6 +71,17 @@ impl From<::hyper::Error> for Error { pub type Result = ::std::result::Result; +// ------------------------------------------------------------------------------------------------- +// This is the middleware which attaches a completion engine to a given request +#[derive(Debug, Clone)] +pub struct EngineProvider; + +impl Key for EngineProvider { + type Value = Box; +} + +// ------------------------------------------------------------------------------------------------- + /// Start the http server using the given configuration /// /// `serve` is non-blocking. @@ -78,18 +93,16 @@ pub type Result = ::std::result::Result; /// let mut cfg = Config::new(); /// cfg.port = 3000; /// -/// let mut server = ::libracerd::http::serve(&cfg).unwrap(); +/// let engine = ::libracerd::engine::Racer; +/// +/// let mut server = ::libracerd::http::serve(&cfg, engine).unwrap(); /// // ... later /// server.close().unwrap(); /// ``` /// -pub fn serve(config: &Config) -> Result { - use persistent::Read; +pub fn serve(config: &Config, engine: E) -> Result { + use persistent::{Read, Write}; use logger::Logger; - use ::engine::SemanticEngine; - - let racer = ::engine::Racer; - racer.initialize(config).unwrap(); // TODO pass engine in let mut chain = Chain::new(router!( post "/parse_file" => file::parse, @@ -105,6 +118,8 @@ pub fn serve(config: &Config) -> Result { chain.link_before(log_before); } + chain.link_before(Write::::one(Box::new(engine))); + // Body parser middlerware chain.link_before(Read::<::bodyparser::MaxBodyLength>::one(1024 * 1024 * 10)); @@ -142,7 +157,8 @@ impl Server { /// let mut config = ::libracerd::Config::new(); /// config.port = 3000; /// - /// let server = ::libracerd::http::serve(&config).unwrap(); + /// let engine = ::libracerd::engine::Racer; + /// let server = ::libracerd::http::serve(&config, engine).unwrap(); /// /// assert_eq!(server.addr(), "0.0.0.0:3000"); /// ``` diff --git a/src/lib.rs b/src/lib.rs index 250564c8..43be3fe8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,10 @@ //! Documentation for the HTTP endpoints can be found in the http module header. //! //! This project's source code is [available on GitHub](https://github.com/jwilm/racerd). + +#[deny(dead_code)] +#[deny(unused_variables)] + extern crate rustc_serialize; #[macro_use] diff --git a/tests/util/http.rs b/tests/util/http.rs index 30a17ae7..16a41deb 100644 --- a/tests/util/http.rs +++ b/tests/util/http.rs @@ -1,6 +1,7 @@ use std::ops::Deref; use libracerd::Config; +use libracerd::engine::{Racer, SemanticEngine}; /// Smart pointer for libracerd http server. /// @@ -11,13 +12,18 @@ pub struct TestServer { impl TestServer { pub fn new() -> TestServer { + let engine = Racer; + let config = Config { + port: 0, + secret_file: "/tmp/secret".to_string(), + print_http_logs: true, + rust_src_path: None, + }; + + engine.initialize(&config).unwrap(); + TestServer { - inner: ::libracerd::http::serve(&Config { - port: 0, - secret_file: "/tmp/secret".to_string(), - print_http_logs: true, - rust_src_path: None, - }).unwrap() + inner: ::libracerd::http::serve(&config, engine).unwrap() } } }