-
Notifications
You must be signed in to change notification settings - Fork 704
[CLI] StructOpt added, code reorganized #618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
134bb45
stashing all refs on cmd
damirka 8b0e3f5
added build and deploy commands, cleanup, synths and logger moved
damirka 63c0198
fixes anyhow version
damirka 27b7a08
added prove,run,setup,test,watch
c257b02
Only update and debug left
damirka e0fe32f
fixed add command behavior and err print
damirka 747fbe7
wrapping up - most of the jobs are done
damirka 48811e0
almost there - update left
damirka 10a3234
added api
damirka 6e4b06d
cosmetics
damirka 20679be
added login <token> feature
damirka a4b492c
more cleanups
damirka 768320c
Merge branch 'master' into leo-ref
damirka 1ccd9e8
merged master, updated licenses
damirka 0fccb19
fixes Pedersen hash example
damirka b82767f
more anyhow in results, started tests
damirka d17f4f0
added tests for build/run/setup and login
damirka cf6910e
adds leo package group of commands
damirka f269912
cleanup and few improvements
damirka 13256bf
finished with update and update automatic
damirka 7426a15
fixes CI - added subcommand
damirka 195765c
clippy fix
damirka edb2325
Update .rustfmt.toml
howardwu cdba80e
removed leo-package, cmd to Command
damirka 8ca17dd
Merge branch 'leo-ref' of github.com:damirka/leo into leo-ref
damirka cb245f0
Merge branch 'master' into leo-ref
damirka 56ec74d
implements #277
damirka 5a031d1
few minor patches
damirka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| // Copyright (C) 2019-2021 Aleo Systems Inc. | ||
| // This file is part of the Leo library. | ||
|
|
||
| // The Leo library is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // The Leo library is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with the Leo library. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| use serde::Serialize; | ||
|
|
||
| use anyhow::{anyhow, Error, Result}; | ||
| use reqwest::{ | ||
| blocking::{Client, Response}, | ||
| Method, | ||
| StatusCode, | ||
| }; | ||
|
|
||
| /// Trait describes API Routes and Request bodies, struct which implements | ||
| /// 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 | ||
| const AUTH: bool; | ||
|
|
||
| /// HTTP method to use when requesting | ||
| const METHOD: Method; | ||
|
|
||
| /// URL path without first forward slash (e.g. v1/package/fetch) | ||
| const PATH: &'static str; | ||
|
|
||
| /// Output type for this route. For login it is simple - String | ||
| /// But for other routes may be more complex. | ||
| type Output; | ||
|
|
||
| /// Process reqwest Response and turn it into Output | ||
| fn process(&self, res: Response) -> Result<Self::Output>; | ||
|
|
||
| /// Transform specific status codes into correct errors for this route. | ||
| /// For example 404 on package fetch should mean that 'Package is not found' | ||
| fn status_to_err(&self, _status: StatusCode) -> Error { | ||
| anyhow!("Unidentified API error") | ||
| } | ||
| } | ||
|
|
||
| /// REST API handler with reqwest::blocking inside | ||
| #[derive(Clone, Debug)] | ||
| pub struct Api { | ||
| host: String, | ||
| client: Client, | ||
| /// Authorization token for API requests | ||
| auth_token: Option<String>, | ||
| } | ||
|
|
||
| impl Api { | ||
| /// Create new instance of API, set host and Client is going to be | ||
| /// created and set automatically | ||
| pub fn new(host: String, auth_token: Option<String>) -> Api { | ||
| Api { | ||
| client: Client::new(), | ||
| auth_token, | ||
| host, | ||
| } | ||
| } | ||
|
|
||
| /// Get token for bearer auth, should be passed into Api through Context | ||
| pub fn auth_token(&self) -> Option<String> { | ||
| self.auth_token.clone() | ||
| } | ||
|
|
||
| /// Set 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 | ||
| pub fn run_route<T>(&self, route: T) -> Result<T::Output> | ||
| where | ||
| T: Route, | ||
| T: Serialize, | ||
| { | ||
| let mut res = self.client.request(T::METHOD, &format!("{}{}", self.host, T::PATH)); | ||
|
|
||
| // add body for POST and PUT requests | ||
| if T::METHOD == Method::POST || T::METHOD == Method::PUT { | ||
| res = res.json(&route); | ||
| }; | ||
|
|
||
| // if Route::Auth is true and token is present - pass it | ||
| if T::AUTH && self.auth_token().is_some() { | ||
| res = res.bearer_auth(&self.auth_token().unwrap()); | ||
| }; | ||
|
|
||
| // only one error is possible here | ||
| let res = res.send().map_err(|_| anyhow!("Unable to connect to Aleo PM"))?; | ||
|
|
||
| // where magic begins | ||
| route.process(res) | ||
| } | ||
| } | ||
|
|
||
| // -------------------------------------------------- | ||
| // | Defining routes | | ||
| // -------------------------------------------------- | ||
|
|
||
| /// Handler for 'fetch' route - fetch packages from Aleo PM | ||
| /// Route: POST /v1/package/fetch | ||
| #[derive(Serialize, Debug)] | ||
| pub struct Fetch { | ||
| pub author: String, | ||
| pub package_name: String, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub version: Option<String>, | ||
| } | ||
|
|
||
| impl Route for Fetch { | ||
| type Output = Response; | ||
|
|
||
| const AUTH: bool = true; | ||
| const METHOD: Method = Method::POST; | ||
| const PATH: &'static str = "api/package/fetch"; | ||
|
|
||
| fn process(&self, res: Response) -> Result<Self::Output> { | ||
| // check status code first | ||
| if res.status() != 200 { | ||
| return Err(self.status_to_err(res.status())); | ||
| }; | ||
|
|
||
| Ok(res) | ||
| } | ||
|
|
||
| fn status_to_err(&self, status: StatusCode) -> Error { | ||
| match status { | ||
| StatusCode::BAD_REQUEST => anyhow!("Package is not found - check author and/or package name"), | ||
| // 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"), | ||
| _ => anyhow!("Unknown API error: {}", status), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Handler for 'login' route - send username and password and receive JWT | ||
| /// Route: POST /v1/account/authenticate | ||
| #[derive(Serialize)] | ||
| pub struct Login { | ||
| pub email_username: String, | ||
| pub password: String, | ||
| } | ||
|
|
||
| impl Route for Login { | ||
| type Output = Response; | ||
|
|
||
| const AUTH: bool = false; | ||
| const METHOD: Method = Method::POST; | ||
| const PATH: &'static str = "api/account/authenticate"; | ||
|
|
||
| fn process(&self, res: Response) -> Result<Self::Output> { | ||
| if res.status() != 200 { | ||
| return Err(self.status_to_err(res.status())); | ||
| } | ||
|
|
||
| Ok(res) | ||
| } | ||
|
|
||
| fn status_to_err(&self, status: StatusCode) -> Error { | ||
| match status { | ||
| StatusCode::BAD_REQUEST => anyhow!("This username is not yet registered or the password is incorrect"), | ||
| // TODO: NOT_FOUND here should be replaced, this error code has no relation to what this route is doing | ||
| StatusCode::NOT_FOUND => anyhow!("Incorrect password"), | ||
| _ => anyhow!("Unknown API error: {}", status), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// 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 | ||
| /// is treated as Unauthorized | ||
| #[derive(Serialize)] | ||
| pub struct Profile {} | ||
|
|
||
| impl Route for Profile { | ||
| type Output = bool; | ||
|
|
||
| const AUTH: bool = true; | ||
| const METHOD: Method = Method::GET; | ||
| const PATH: &'static str = "api/account/my_profile"; | ||
|
|
||
| fn process(&self, res: Response) -> Result<Self::Output> { | ||
| // this may be extended for more precise error handling | ||
| Ok(res.status() == 200) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.