rp_cli/
handler.rs

1use crate::api::{APIClient, API, BASE_URL};
2use crate::api_types::{compile, download, execute, fmt, share};
3use crate::input;
4use crate::printer::Printer;
5use std::collections::HashMap;
6use url::{ParseError, Url};
7
8pub struct Handler {
9    // TODO: mockable for test
10    api_cli: APIClient,
11    printer: Printer,
12}
13
14impl Handler {
15    pub fn new() -> Handler {
16        Handler {
17            api_cli: APIClient::new(),
18            printer: Printer::new(),
19        }
20    }
21
22    pub fn run(&mut self, input: input::RunInput) -> Result<(), Box<dyn std::error::Error>> {
23        let code = input::code_from_path(&input.file_path)?;
24
25        // TODO: refactor for run_type
26        let request = execute::Request {
27            crate_type: "bin".to_string(),
28            tests: false,
29            mode: input.mode,
30            channel: input.channel,
31            edition: input.edition,
32            backtrace: input.backtrace,
33            code: code,
34        };
35
36        let resp = self.api_cli.execute(request)?;
37
38        // TODO: handle following pattern.
39        // error
40        // Response { success: false, stdout: "", stderr: "", error: "Unable to deserialize request: Expected request with `Content-Type: application/json`" }
41        //
42        // error stdrtt
43        // Response { success: false, stdout: "", stderr: "   Compiling playground v0.0.1 (/playground)\nerror: expected item, found `[`\n --> src/main.rs:1:1\n  |\n1 | [package]\n  | ^ expected item\n\nerror: could not compile `playground` due to previous error\n", error: "" }
44        //
45        // success
46        // Response { success: true, stdout: "Client of The Rust Playground!\n", stderr: "   Compiling playground v0.0.1 (/playground)\n    Finished dev [unoptimized + debuginfo] target(s) in 2.66s\n     Running `target/debug/playground`\n", error: "" }
47        //
48
49        self.printer.print_run(resp)?;
50
51        Ok(())
52    }
53
54    pub fn fmt(&mut self, input: input::FmtInput) -> Result<(), Box<dyn std::error::Error>> {
55        let code = input::code_from_path(&input.file_path)?;
56
57        let request = fmt::Request {
58            edition: input.edition,
59            code: code,
60        };
61
62        let resp = self.api_cli.fmt(request)?;
63
64        self.printer.print_fmt(resp)?;
65
66        Ok(())
67    }
68
69    pub fn share(&mut self, input: input::ShareInput) -> Result<(), Box<dyn std::error::Error>> {
70        let code = input::code_from_path(&input.file_path)?;
71
72        let request = share::Request { code: code };
73
74        let resp = self.api_cli.share(request)?;
75
76        self.printer.print_share(resp)?;
77
78        Ok(())
79    }
80
81    pub fn download(
82        &mut self,
83        input: input::DownloadInput,
84    ) -> Result<(), Box<dyn std::error::Error>> {
85        let id = pick_id_from(input.id_or_url)?;
86
87        let request = download::Request { id: id };
88
89        let resp = self.api_cli.download(request)?;
90
91        self.printer.print_download(resp)?;
92
93        Ok(())
94    }
95}
96
97// TODO: error handling
98fn pick_id_from(id_or_url: String) -> Result<String, Box<std::error::Error>> {
99    if id_or_url.starts_with(BASE_URL) {
100        // parse url
101        // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7b61a4b7baf87fb4b5feb8668721ff8b
102        let url = Url::parse(&id_or_url);
103        if let Ok(url) = url {
104            let hash_query: HashMap<_, _> = url.query_pairs().into_owned().collect();
105
106            match hash_query.get("gist") {
107                Some(id) => return Ok(id.to_string()),
108                None => return Ok("".to_string()),
109            };
110        } else {
111            return Ok("".to_string());
112        }
113    } else {
114        // maybe id
115        Ok(id_or_url)
116    }
117}