Skip to content
This repository was archived by the owner on Mar 25, 2023. It is now read-only.

Commit 8b821a5

Browse files
wip
1 parent 8db8892 commit 8b821a5

File tree

3 files changed

+174
-83
lines changed

3 files changed

+174
-83
lines changed

src/commands/serve.rs

+104-81
Original file line numberDiff line numberDiff line change
@@ -145,20 +145,31 @@ async fn serve_static(req: actix_web::HttpRequest) -> actix_web::HttpResponse {
145145

146146
#[actix_web::main]
147147
pub async fn serve(port: &str) -> std::io::Result<()> {
148-
// For debugging (will be refactored later)
149-
let use_controller = false;
148+
let use_controller = {
149+
let mut use_controller = false;
150+
if let Ok(val) = std::env::var("CONTROLLER") {
151+
if let Ok(val) = val.parse::<bool>() {
152+
use_controller = val;
153+
}
154+
}
155+
use_controller
156+
};
150157

151158
if use_controller {
152159
// fpm-controller base path and ec2 instance id (hardcoded for now)
153-
let fpm_controller: String = "https:///controller.fifthtry.com".to_string();
154-
let fpm_instance: String = "<some-ec2-instance-id>".to_string();
160+
let fpm_controller: String = std::env::var("FPM_CONTROLLER")
161+
.unwrap_or("https:///controller.fifthtry.com".to_string());
162+
let fpm_instance: String =
163+
std::env::var("FPM_INSTANCE_ID").unwrap_or("<instance_id>".to_string());
155164

156165
match controller::resolve_dependencies(fpm_instance, fpm_controller).await {
157166
Ok(_) => println!("Dependencies resolved"),
158167
Err(_) => panic!("Error resolving dependencies using controller!!"),
159168
}
160169
}
161170

171+
let mut config = fpm::Config::read(None).await.unwrap();
172+
162173
println!("### Server Started ###");
163174
println!("Go to: http://127.0.0.1:{}", port);
164175
actix_web::HttpServer::new(|| {
@@ -199,38 +210,61 @@ mod controller {
199210
let package_response = get_package(fpm_instance.as_str(), fpm_controller.as_str()).await?;
200211
let gp_status = match package_response["success"].as_bool() {
201212
Some(res) => res,
202-
None => panic!("success parameter doesn't exist in Json or isn't valid boolean type"),
213+
None => {
214+
return Err(fpm::Error::UsageError {
215+
message: "success parameter doesn't exist in Json or isn't valid boolean type"
216+
.to_string(),
217+
})
218+
}
203219
};
204220

205-
match gp_status {
206-
true => {
207-
// package name and git repo url
208-
let package_name = match package_response["result"]["package"].as_str() {
209-
Some(valid_name) => valid_name,
210-
None => panic!("received invalid package name from get_package API"),
211-
};
212-
if let Some(git_url) = package_response["result"]["git"].as_str() {
213-
// Clone the git package into the current directory
214-
// Need to execute shell commands from rust
215-
// git_url https format: https://github.com/<user>/<repo>.git
216-
let out = std::process::Command::new("git")
217-
.arg("clone")
218-
.arg(git_url)
219-
.output()
220-
.expect("unable to execute git clone command");
221-
222-
if out.status.success() {
223-
// By this time the cloned repo should be available in the current directory
224-
println!("Git cloning successful for the package {}", package_name);
225-
// Resolve dependencies by reading the FPM.ftd using config.read()
226-
// Assuming package_name and repo name are identical
227-
let _config = fpm::Config::read(Some(package_name.to_string())).await?;
228-
}
229-
} else {
230-
panic!("Invalid git url for the package {}", package_name);
231-
}
232-
},
233-
false => panic!("get-package api success status returned false!!")
221+
if !gp_status {
222+
return Err(fpm::Error::UsageError {
223+
message: "get-package api success status returned false!!".to_string(),
224+
});
225+
}
226+
227+
// package name and git repo url
228+
let package_name = match package_response["result"]["package"].as_str() {
229+
Some(valid_name) => valid_name,
230+
None => {
231+
return Err(fpm::Error::UsageError {
232+
message: "received invalid package name from get_package API".to_string(),
233+
})
234+
}
235+
};
236+
237+
if let Some(git_url) = package_response["result"]["git"].as_str() {
238+
// Clone the git package into the current directory
239+
// Need to execute shell commands from rust
240+
// git_url https format: https://github.com/<user>/<repo>.git
241+
242+
let package = {
243+
let mut package = fpm::Package::new(package_name);
244+
package.zip = Some(git_url.to_string());
245+
package
246+
};
247+
248+
package.unzip_package().await?;
249+
fpm::Config::read(None).await?;
250+
251+
/*let out = std::process::Command::new("git")
252+
.arg("clone")
253+
.arg(git_url)
254+
.output()
255+
.expect("unable to execute git clone command");
256+
257+
if out.status.success() {
258+
// By this time the cloned repo should be available in the current directory
259+
println!("Git cloning successful for the package {}", package_name);
260+
// Resolve dependencies by reading the FPM.ftd using config.read()
261+
// Assuming package_name and repo name are identical
262+
let _config = fpm::Config::read(Some(package_name.to_string())).await?;
263+
}*/
264+
} else {
265+
return Err(fpm::Error::UsageError {
266+
message: "received invalid package name from get_package API".to_string(),
267+
});
234268
}
235269

236270
// Once the dependencies are resolved for the package
@@ -251,72 +285,61 @@ mod controller {
251285
Ok(())
252286
}
253287

254-
async fn make_get_request(url: url::Url) -> fpm::Result<serde_json::Value> {
255-
use fpm::library::http;
256-
let response = match http::_get(url).await {
257-
Ok(some_response) => some_response,
258-
Err(e) => {
259-
panic!("failed to fetch data, error: {}", e.to_string())
260-
}
261-
};
262-
263-
match serde_json::from_str(response.as_str()) {
264-
Ok(v) => Ok(v),
265-
Err(e) => panic!(
266-
"failed parsing json from response text, error: {}",
267-
e.to_string()
268-
),
269-
}
270-
}
271-
288+
/// get-package API
289+
/// input: fpm_instance
290+
/// output: package_name and git repo URL
291+
/// format: {
292+
/// "success": true,
293+
/// "result": {
294+
/// "package": "<package name>"
295+
/// "git": "<git url>"
296+
/// }
297+
/// }
272298
async fn get_package(
273299
fpm_instance: &str,
274300
fpm_controller: &str,
275301
) -> fpm::Result<serde_json::Value> {
276-
// get-package API
277-
// input: fpm_instance
278-
// output: package_name and git repo URL
279-
// format: {
280-
// "success": true,
281-
// "result": {
282-
// "package": "<package name>"
283-
// "git": "<git url>"
284-
// }
285-
// }
286-
287-
let query_string = format!("instance={}", fpm_instance);
288-
let controller_api = format!("{}/get-package?{}", fpm_controller, query_string);
289-
302+
let controller_api = format!("{}/get-package?instance={}", fpm_controller, fpm_instance);
290303
let url = match url::Url::parse(controller_api.as_str()) {
291304
Ok(safe_url) => safe_url,
292-
Err(e) => panic!("Invalid get-package API endpoint, Parse error: {}",e.to_string()),
305+
Err(e) => panic!(
306+
"Invalid get-package API endpoint, Parse error: {}",
307+
e.to_string()
308+
),
293309
};
294310

295-
make_get_request(url).await
311+
let val = fpm::library::http::get(url, "", 0).await?;
312+
Ok(val)
296313
}
297314

315+
/// fpm-ready API
316+
/// input: fpm_instance, *(git commit hash)
317+
/// output: success: true/false
318+
/// format: lang: json
319+
/// {
320+
/// "success": true
321+
/// }
322+
323+
/// Git commit hash needs to be computed before making a call to the fpm_ready API
298324
async fn fpm_ready(fpm_instance: &str, fpm_controller: &str) -> fpm::Result<serde_json::Value> {
299-
// fpm-ready API
300-
// input: fpm_instance, *(git commit hash)
301-
// output: success: true/false
302-
// format: lang: json
303-
// {
304-
// "success": true
305-
// }
306-
307-
// Git commit hash needs to be computed before making a call to the fpm_ready API
308325
let git_commit = "<dummy-git-commit-hash-xxx123>";
309326

310-
let query_string = format!("instance={}&git-commit={}", fpm_instance, git_commit);
311-
let controller_api = format!("{}/fpm-ready?{}", fpm_controller, query_string);
327+
let controller_api = format!(
328+
"{}/fpm-ready?instance={}&git-commit={}",
329+
fpm_controller, fpm_instance, git_commit
330+
);
312331

313332
let url = match url::Url::parse(controller_api.as_str()) {
314333
Ok(safe_url) => safe_url,
315-
Err(e) => panic!("Invalid fpm_ready API endpoint, Parse error: {}",e.to_string()),
334+
Err(e) => panic!(
335+
"Invalid fpm_ready API endpoint, Parse error: {}",
336+
e.to_string()
337+
),
316338
};
317339

318340
// This request should be put request for fpm_ready API to update the instance status to ready
319341
// Using http::_get() function to make request to this API for now
320-
make_get_request(url).await
342+
let val = fpm::library::http::get(url, "", 0).await?;
343+
Ok(val)
321344
}
322345
}

src/dependency.rs

+68
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,74 @@ impl fpm::Package {
311311
}
312312
}
313313

314+
pub(crate) async fn unzip_package(&self) -> fpm::Result<()> {
315+
use std::convert::TryInto;
316+
use std::io::Write;
317+
318+
let download_url = if let Some(ref url) = self.zip {
319+
url
320+
} else {
321+
return Ok(());
322+
};
323+
324+
let path = std::env::temp_dir().join(format!("{}.zip", self.name.replace("/", "__")));
325+
326+
let start = std::time::Instant::now();
327+
print!("Downloading {} ... ", self.name.as_str());
328+
std::io::stdout().flush()?;
329+
// Download the zip folder
330+
{
331+
let mut response = if download_url[1..].contains("://")
332+
|| download_url.starts_with("//")
333+
{
334+
reqwest::get(download_url.as_str())?
335+
} else if let Ok(response) = reqwest::get(format!("https://{}", download_url).as_str())
336+
{
337+
response
338+
} else {
339+
reqwest::get(format!("http://{}", download_url).as_str())?
340+
};
341+
let mut file = std::fs::File::create(&path)?;
342+
// TODO: instead of reading the whole thing in memory use tokio::io::copy() somehow?
343+
let mut buf: Vec<u8> = vec![];
344+
response.copy_to(&mut buf)?;
345+
file.write_all(&buf)?;
346+
// file.write_all(response.text().await?.as_bytes())?;
347+
}
348+
349+
let file = std::fs::File::open(&path)?;
350+
// TODO: switch to async_zip crate
351+
let mut archive = zip::ZipArchive::new(file)?;
352+
for i in 0..archive.len() {
353+
let mut c_file = archive.by_index(i).unwrap();
354+
let out_path = match c_file.enclosed_name() {
355+
Some(path) => path.to_owned(),
356+
None => continue,
357+
};
358+
let out_path_without_folder = out_path.to_str().unwrap().split_once("/").unwrap().1;
359+
let file_extract_path = {
360+
let mut file_extract_path: camino::Utf8PathBuf =
361+
std::env::current_dir()?.canonicalize()?.try_into()?;
362+
file_extract_path = file_extract_path.join(out_path_without_folder);
363+
file_extract_path
364+
};
365+
if (&*c_file.name()).ends_with('/') {
366+
std::fs::create_dir_all(&file_extract_path)?;
367+
} else {
368+
if let Some(p) = file_extract_path.parent() {
369+
if !p.exists() {
370+
std::fs::create_dir_all(p)?;
371+
}
372+
}
373+
// Note: we will be able to use tokio::io::copy() with async_zip
374+
let mut outfile = std::fs::File::create(file_extract_path)?;
375+
std::io::copy(&mut c_file, &mut outfile)?;
376+
}
377+
}
378+
fpm::utils::print_end(format!("Downloaded {}", self.name.as_str()).as_str(), start);
379+
Ok(())
380+
}
381+
314382
/// This function is called by `process()` or recursively called by itself.
315383
/// It checks the `FPM.ftd` file of dependent package and find out all the dependency packages.
316384
/// If dependent package is not available, it calls `process()` to download it inside `.packages` directory

src/library/http.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub async fn processor<'a>(
5353
doc.from_json(&json, section)
5454
}
5555

56-
async fn get(
56+
pub(crate) async fn get(
5757
url: url::Url,
5858
doc_id: &str,
5959
line_number: usize,
@@ -78,7 +78,7 @@ async fn get(
7878
}
7979
}
8080

81-
pub async fn _get(url: url::Url) -> reqwest::Result<String> {
81+
async fn _get(url: url::Url) -> reqwest::Result<String> {
8282
let mut headers = reqwest::header::HeaderMap::new();
8383
headers.insert(
8484
reqwest::header::USER_AGENT,

0 commit comments

Comments
 (0)