diff --git a/leo/api.rs b/leo/api.rs index 311c1da53b..4763c7a27d 100644 --- a/leo/api.rs +++ b/leo/api.rs @@ -22,25 +22,24 @@ use reqwest::{ }; use serde::{Deserialize, Serialize}; -/// Trait describes API Routes and Request bodies, struct which implements -/// Route MUST also support Serialize to be usable in Api::run_route(r: Route) +/// API Routes and Request bodies. +/// Structs that implement Route MUST also support Serialize to be usable in Api::run_route(r: Route) pub trait Route { - /// Whether to use bearer auth or not. Some routes may have additional - /// features for logged-in users, so authorization token should be sent - /// if it is created of course + /// [`true`] if a route supports bearer authentication. + /// For example, the login route. const AUTH: bool; - /// HTTP method to use when requesting + /// The HTTP method to use when requesting. const METHOD: Method; - /// URL path without first forward slash (e.g. v1/package/fetch) + /// The URL path without the first forward slash (e.g. v1/package/fetch) const PATH: &'static str; - /// Output type for this route. For login it is simple - String + /// The output type for this route. For example, the login route output is [`String`]. /// But for other routes may be more complex. type Output; - /// Process reqwest Response and turn it into Output + /// Process the reqwest Response and turn it into an Output. fn process(&self, res: Response) -> Result; /// Transform specific status codes into correct errors for this route. @@ -50,18 +49,18 @@ pub trait Route { } } -/// REST API handler with reqwest::blocking inside +/// REST API handler with reqwest::blocking inside. #[derive(Clone, Debug)] pub struct Api { host: String, client: Client, - /// Authorization token for API requests + /// Authorization token for API requests. auth_token: Option, } impl Api { - /// Create new instance of API, set host and Client is going to be - /// created and set automatically + /// Returns a new instance of API. + /// The set host and Client are created automatically. pub fn new(host: String, auth_token: Option) -> Api { Api { client: Client::new(), @@ -70,18 +69,23 @@ impl Api { } } - /// Get token for bearer auth, should be passed into Api through Context + pub fn host(&self) -> &str { + &*self.host + } + + /// Returns the token for bearer auth, otherwise None. + /// The [`auth_token`] should be passed into the Api through Context. pub fn auth_token(&self) -> Option { self.auth_token.clone() } - /// Set authorization token for future requests + /// Set the authorization token for future requests. pub fn set_auth_token(&mut self, token: String) { self.auth_token = Some(token); } /// Run specific route struct. Turn struct into request body - /// and use type constants and Route implementation to get request params + /// and use type constants and Route implementation to get request params. pub fn run_route(&self, route: T) -> Result where T: Route, @@ -100,7 +104,9 @@ impl Api { }; // only one error is possible here - let res = res.send().map_err(|_| anyhow!("Unable to connect to Aleo PM"))?; + let res = res.send().map_err(|_| { + anyhow!("Unable to connect to Aleo PM. If you specified custom API endpoint, then check the URL for errors") + })?; // where magic begins route.process(res) @@ -143,7 +149,7 @@ impl Route for Fetch { // TODO: we should return 404 on not found author/package // and return BAD_REQUEST if data format is incorrect or some of the arguments // were not passed - StatusCode::NOT_FOUND => anyhow!("Package is hidden"), + StatusCode::NOT_FOUND => anyhow!("Package not found"), _ => anyhow!("Unknown API error: {}", status), } } @@ -183,7 +189,7 @@ impl Route for Login { } /// Handler for 'my_profile' route. Meant to be used to get profile details but -/// in current application is used to check if user is logged in. Any non-200 response +/// in the current application it is used to check if the user is logged in. Any non-200 response /// is treated as Unauthorized. #[derive(Serialize)] pub struct Profile {} diff --git a/leo/commands/package/publish.rs b/leo/commands/package/publish.rs index acfe69912f..cf0971283f 100644 --- a/leo/commands/package/publish.rs +++ b/leo/commands/package/publish.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use super::build::Build; -use crate::{ - commands::Command, - context::{Context, PACKAGE_MANAGER_URL}, -}; +use crate::{commands::Command, context::Context}; use leo_package::{ outputs::OutputsDirectory, root::{ZipFile, AUTHOR_PLACEHOLDER}, @@ -118,7 +115,7 @@ impl Command for Publish { // Make a request to publish a package let response = client - .post(format!("{}{}", PACKAGE_MANAGER_URL, PUBLISH_URL).as_str()) + .post(format!("{}{}", context.api.host(), PUBLISH_URL).as_str()) .headers(headers) .multipart(form_data) .send(); diff --git a/leo/context.rs b/leo/context.rs index bddd54e5f2..0fb96f0a11 100644 --- a/leo/context.rs +++ b/leo/context.rs @@ -48,19 +48,19 @@ impl Context { } /// Create a new context for the current directory. -pub fn create_context(path: PathBuf) -> Result { +pub fn create_context(path: PathBuf, api_url: Option) -> Result { let token = config::read_token().ok(); - let api = Api::new(PACKAGE_MANAGER_URL.to_string(), token); + let api = Api::new(api_url.unwrap_or_else(|| PACKAGE_MANAGER_URL.to_string()), token); Ok(Context { api, path: Some(path) }) } /// Returns project context. -pub fn get_context() -> Result { +pub fn get_context(api_url: Option) -> Result { let token = config::read_token().ok(); - let api = Api::new(PACKAGE_MANAGER_URL.to_string(), token); + let api = Api::new(api_url.unwrap_or_else(|| PACKAGE_MANAGER_URL.to_string()), token); Ok(Context { api, path: None }) } diff --git a/leo/main.rs b/leo/main.rs index a0784f70fe..73589df29d 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -55,6 +55,9 @@ struct Opt { #[structopt(subcommand)] command: CommandOpts, + #[structopt(help = "Custom Aleo PM backend URL", env = "APM_URL")] + api: Option, + #[structopt( long, global = true, @@ -192,8 +195,8 @@ fn main() { // Get custom root folder and create context for it. // If not specified, default context will be created in cwd. let context = handle_error(match opt.path { - Some(path) => context::create_context(path), - None => context::get_context(), + Some(path) => context::create_context(path, opt.api), + None => context::get_context(opt.api), }); handle_error(match opt.command { diff --git a/leo/tests/mod.rs b/leo/tests/mod.rs index 7bc611f49d..27d310d8ae 100644 --- a/leo/tests/mod.rs +++ b/leo/tests/mod.rs @@ -152,7 +152,7 @@ pub fn leo_update_and_update_automatic() -> Result<()> { /// Create context for Pedersen Hash example fn context() -> Result { let path = PathBuf::from(&PEDERSEN_HASH_PATH); - let context = create_context(path)?; + let context = create_context(path, None)?; Ok(context) }