Skip to content

Commit fee8f92

Browse files
authored
Merge pull request #125 from filecoin-project/feat/create-or-update-allocator
allocator create logic
2 parents e016617 + 467beeb commit fee8f92

File tree

6 files changed

+135
-30
lines changed

6 files changed

+135
-30
lines changed

fplus-http-server/src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use actix_web::{App, HttpServer};
55
use env_logger;
66
use log::info;
77
use fplus_database;
8-
98
pub(crate) mod router;
109

1110
#[tokio::main]
@@ -44,9 +43,9 @@ async fn main() -> std::io::Result<()> {
4443
.service(router::blockchain::verified_clients)
4544
.service(router::verifier::verifiers)
4645
.service(router::allocator::allocators)
47-
.service(router::allocator::create_or_update)
4846
.service(router::allocator::allocator)
4947
.service(router::allocator::delete)
48+
.service(router::allocator::create_from_json)
5049
})
5150
.bind(("0.0.0.0", 8080))?
5251
.run()

fplus-http-server/src/router/allocator.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use actix_web::{get, post, put, delete, web, HttpResponse, Responder};
22
use fplus_database::database;
3-
use fplus_lib::core::{Allocator, AllocatorUpdateInfo};
3+
use fplus_lib::core::{allocator::process_allocator_file, AllocatorUpdateInfo, ChangedAllocator};
44

55
/**
66
* Get all allocators
@@ -19,35 +19,47 @@ pub async fn allocators() -> impl Responder {
1919
},
2020
}
2121
}
22-
2322
/**
24-
* Create a new allocator
23+
* Creates new Allocator in the db from a JSON file in the repository
2524
*
2625
* # Arguments
27-
* @param info: web::Json<Allocator> - The allocator information
26+
* @param files: web::Json<ChangedAllocators> - The list of changed JSON file names
2827
*
2928
* # Returns
3029
* @return HttpResponse - The result of the operation
3130
*/
32-
#[post("/allocator")]
33-
pub async fn create_or_update(info: web::Json<Allocator>) -> impl Responder {
34-
match database::create_or_update_allocator(
35-
info.owner.clone(),
36-
info.repo.clone(),
37-
info.installation_id,
38-
info.multisig_address.clone(),
39-
info.verifiers_gh_handles.clone(),
40-
).await {
41-
Ok(allocator_model) => HttpResponse::Ok().json(allocator_model),
42-
Err(e) => {
43-
if e.to_string().contains("Allocator already exists") {
44-
return HttpResponse::BadRequest().body(e.to_string());
31+
#[post("/allocator/create")]
32+
pub async fn create_from_json(file: web::Json<ChangedAllocator>) -> actix_web::Result<impl Responder> {
33+
let file_name = &file.file_changed;
34+
log::info!("Starting allocator creation on: {}", file_name);
35+
36+
match process_allocator_file(file_name).await {
37+
Ok(model) => {
38+
if model.multisig_address.is_empty() {
39+
return Ok(HttpResponse::BadRequest().body("Missing or invalid multisig_address"));
4540
}
46-
return HttpResponse::InternalServerError().body(e.to_string());
47-
}
41+
let verifiers_gh_handles = if model.application.verifiers_gh_handles.is_empty() {
42+
None
43+
} else {
44+
Some(model.application.verifiers_gh_handles.join(", ")) // Join verifiers in a string if exists
45+
};
46+
47+
match database::create_or_update_allocator(
48+
model.owner,
49+
model.repo,
50+
Some(model.installation_id as i64),
51+
Some(model.multisig_address),
52+
verifiers_gh_handles,
53+
).await {
54+
Ok(allocator_model) => Ok(HttpResponse::Ok().json(allocator_model)),
55+
Err(e) => Ok(HttpResponse::BadRequest().body(e.to_string())),
56+
}
57+
},
58+
Err(e) => Ok(HttpResponse::BadRequest().body(e.to_string())),
4859
}
4960
}
5061

62+
5163
/**
5264
* Update an allocator
5365
*

fplus-lib/src/base64.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
1-
use std::io::Cursor;
2-
1+
use base64::read::DecoderReader;
2+
use serde_json::from_reader;
33
use base64;
44

5-
use crate::core::application::file::ApplicationFile;
5+
use crate::core::{allocator::file::AllocatorModel, application::file::ApplicationFile};
66

7-
pub fn decode(i: &str) -> Option<ApplicationFile> {
7+
pub fn decode_application_file(i: &str) -> Option<ApplicationFile> {
88
let mut binding = Cursor::new(i);
9-
let decoder = base64::read::DecoderReader::new(&mut binding, base64::STANDARD);
9+
let decoder = DecoderReader::new(&mut binding, base64::STANDARD);
1010
let app_file: ApplicationFile = match serde_json::from_reader(decoder) {
1111
Ok(f) => f,
1212
Err(_) => return None,
1313
};
1414
Some(app_file)
1515
}
16+
17+
use std::io::Cursor;
18+
19+
20+
pub fn decode_allocator_model(encoded_str: &str) -> Option<AllocatorModel> {
21+
let mut binding = Cursor::new(encoded_str);
22+
let decoder = DecoderReader::new(&mut binding, base64::STANDARD);
23+
24+
match from_reader(decoder) {
25+
Ok(model) => Some(model),
26+
Err(_) => None,
27+
}
28+
}

fplus-lib/src/core/allocator/file.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use serde::{Serialize, Deserialize};
2+
3+
#[derive(Serialize, Deserialize, Debug)]
4+
pub struct AllocatorModel {
5+
#[serde(rename = "slug")]
6+
pub repo: String,
7+
#[serde(rename = "organization")]
8+
pub owner: String,
9+
#[serde(rename = "address")]
10+
pub multisig_address: String,
11+
pub application: Application,
12+
#[serde(rename = "common_ui_install_id")]
13+
pub installation_id: u64,
14+
}
15+
16+
#[derive(Serialize, Deserialize, Debug)]
17+
pub struct Application {
18+
#[serde(rename = "github_handles")]
19+
pub verifiers_gh_handles: Vec<String>
20+
}

fplus-lib/src/core/allocator/mod.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use octocrab::models::repos::ContentItems;
2+
3+
use crate::{base64::decode_allocator_model, error::LDNError, external_services::github::GithubWrapper};
4+
5+
use self::file::AllocatorModel;
6+
7+
pub mod file;
8+
9+
pub async fn process_allocator_file(file_name: &str) -> Result<AllocatorModel, LDNError> {
10+
11+
let owner = std::env::var("ALLOCATOR_GOVERNANCE_OWNER").unwrap_or_else(|_| {
12+
log::warn!("ALLOCATOR_GOVERNANCE_OWNER not found in .env file");
13+
"Allocator-Governance-Staging".to_string()
14+
});
15+
let repo = std::env::var("ALLOCATOR_GOVERNANCE_REPO").unwrap_or_else(|_| {
16+
log::warn!("ALLOCATOR_GOVERNANCE_REPO not found in .env file");
17+
"fidlabs".to_string()
18+
});
19+
let branch = "main";
20+
let path = file_name.to_string();
21+
22+
let gh = GithubWrapper::new(owner.to_string(), repo.to_string());
23+
let content_items = gh.get_file(&path, branch).await.map_err(|e| LDNError::Load(e.to_string()))?;
24+
let model = content_items_to_allocator_model(content_items).map_err(|e| LDNError::Load(e.to_string()))?;
25+
26+
Ok(model)
27+
}
28+
29+
30+
fn content_items_to_allocator_model(file: ContentItems) -> Result<AllocatorModel, LDNError> {
31+
let encoded_content = match file.items.get(0).and_then(|f| f.content.clone()) {
32+
Some(content) => {
33+
log::info!("Fetched content: {:?}", content);
34+
content
35+
},
36+
None => {
37+
log::error!("Allocator file is corrupted or empty");
38+
return Err(LDNError::Load("Allocator file is corrupted".to_string()));
39+
}
40+
};
41+
42+
let cleaned_content = encoded_content.replace("\n", "");
43+
log::info!("Cleaned content: {:?}", cleaned_content);
44+
45+
match decode_allocator_model(&cleaned_content) {
46+
Some(model) => {
47+
log::info!("Parsed allocator model successfully");
48+
Ok(model)
49+
},
50+
None => {
51+
log::error!("Failed to parse allocator model");
52+
Err(LDNError::Load("Failed to parse allocator model".to_string()))
53+
}
54+
}
55+
}

fplus-lib/src/core/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use reqwest::Response;
99
use serde::{Deserialize, Serialize};
1010

1111
use crate::{
12-
base64,
12+
base64::{self},
1313
config::get_env_var_or_default,
1414
error::LDNError,
1515
external_services::github::{
@@ -20,13 +20,13 @@ use crate::{
2020
use fplus_database::database;
2121

2222
use self::application::file::{
23-
AllocationRequest, AllocationRequestType, AppState, ApplicationFile, VerifierInput,
24-
ValidVerifierList,
23+
AllocationRequest, AllocationRequestType, AppState, ApplicationFile, ValidVerifierList, VerifierInput
2524
};
2625
use rayon::prelude::*;
2726
use crate::core::application::file::Allocation;
2827

2928
pub mod application;
29+
pub mod allocator;
3030

3131
#[derive(Deserialize)]
3232
pub struct CreateApplicationInfo {
@@ -98,6 +98,12 @@ pub struct Allocator {
9898
pub installation_id: Option<i64>,
9999
pub multisig_address: Option<String>,
100100
pub verifiers_gh_handles: Option<String>,
101+
102+
103+
}
104+
#[derive(Deserialize)]
105+
pub struct ChangedAllocator {
106+
pub file_changed: String
101107
}
102108

103109
#[derive(Deserialize)]
@@ -584,7 +590,7 @@ impl LDNApplication {
584590
.take_items()
585591
.get(0)
586592
.and_then(|f| f.content.clone())
587-
.and_then(|f| base64::decode(&f.replace("\n", "")))
593+
.and_then(|f| base64::decode_application_file(&f.replace("\n", "")))
588594
.ok_or(LDNError::Load(format!("Application file is corrupted",)))?;
589595
return Ok(ApplicationFile::from(f.clone()));
590596
}

0 commit comments

Comments
 (0)