S6TFYMRGWC4PSRLQ4OAKE2Z3JFEVGF3RZ5Z3MEN5XSA4INPQILOAC HOAKL56VHB543H2MWVHLBI3R7NPW3LLVJ5X5LZ4DVXIYGIMFOXJQC 3E77DEMDLYBFJEGS2SLQKLQJQIXG2Y4TBDHAG3UKFLMKQ53CFOKQC W3M3C7CCWHJWRWHULDWO45D3OFD4NL3V4OTJVIJCYRQG57Z2JTWQC FS2NWBVN2SZB2FFPB3JSYT5URTVZEAZWMQ7QW4JUYPNJVDVAJTTQC DSWQKJRHGLKXUDXKMRXCIQZKEGXYV3H5LPUMGSV4HQ4HYPTI47GQC WSHUT37CPBBR5JHWAHR27BKOADUWPUHYBWBJPNI6TEQ47TDWTL7QC W2ZEVC64ORZWKRPSQ3JFLIV54FYOTHIK2VW7H7HASO3Z6RC66LSQC 5UNA2DEALCSRBINR27KSA6OMD6GQAXHYZ35ICQ7NB62G2XP4FT5QC TWIZ7QV4GCTQK743IKZSOJCIAEX62GZHFIYGOIFCFGIBOGPSY2WAC KULVODXDL6KFQDLXYAAM3YPYNUMTRWV3LP6NRTYUHU7XBM2OKYZAC use crate::database::Database;use crate::models::projects;use crate::repoman::RepoMan;use rocket::{Route, State};channel: String, // TODO check if this breaks non-UTF-8 channelsid: Option<String>,) -> Option<String> {let p = match projects::find(db, org_path, proj_path).await {Some(p) => p,None => return None,};match p.repository(&repoman.storage_root) {Ok(r) => r.channel_remote_id(channel, id),Err(e) => {println!("{}", e);None}}}async fn changelist(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,) -> Option<String> {Err(e) => {None}}}pub fn routes() -> Vec<Route> {}routes![remote_id, changelist, apply, identities, change]// TODO pijul: When this endpoint returns a 4XX or 5XX status code, it thinks the push still// succeeded.#[post("/<org_path>/<proj_path>/.pijul?<apply>", data = "<patch>")]async fn apply(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,apply: String,mut patch: TempFile<'_>,) -> rocket::http::Status {let p = if let Some(p) = projects::find(db, org_path, proj_path).await {p} else {return rocket::http::Status::NotFound;};}}#[derive(FromForm)]identities: Vec<String>,}use rocket::serde::{json::Json, Serialize};id: Vec<String>,rev: u64,}// TODO figure out what I'm supposed to send here?}let hash = crate::models::pijul::changestores::Changestore::hash_from_string(change)?;let repo = p.repository(&repoman.storage_root).ok()?;let path = repo.changestore().change_file(hash);NamedFile::open(path).await.ok()#[get("/<org_path>/<proj_path>/.pijul?<identities>", rank = 4)]fn identities(org_path: String, proj_path: String, identities: Identities) -> Json<IdentitieRes> {Json(IdentitieRes { id: vec![], rev: 0 })}#[get("/<org_path>/<proj_path>/.pijul?<change>", rank = 3)]async fn change(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,change: String,) -> Option<NamedFile> {let p = projects::find(db, org_path, proj_path).await?;#[derive(Serialize, FromForm)]struct IdentitieRes {struct Identities {if !repo.valid_change(hash) {// TODO clean upprintln!("Not valid as object");return rocket::http::Status::InternalServerError;}if repo.apply_change_to_channel("main", hash).is_ok() {return rocket::http::Status::Accepted;};rocket::http::Status::InternalServerErrorif patch.persist_to(&patch_path).await.is_err() {return rocket::http::Status::InternalServerError;let repo = p.repository(&repoman.storage_root).unwrap();let hash =if let Some(h) = crate::models::pijul::changestores::Changestore::hash_from_string(apply) {h} else {return rocket::http::Status::InternalServerError;};let patch_path = repo.changestore().change_file(hash);repo.changestore().ensure_parent_dirs(hash);use rocket::fs::TempFile;println!("error getting changelist: {}", e);match p.repository(&repoman.storage_root).unwrap().changelist(channel, changelist){Ok(out) => Some(out),let p = projects::find(db, org_path, proj_path).await?;channel: String, // TODO check if this breaks non-UTF-8 channelschangelist: u64,#[get("/<org_path>/<proj_path>/.pijul?<changelist>&<channel>")]/// Because of the overlap with other routes in parameters, this route has/// rank 2. This way the changelist matches first, and if it doesn't, this route/// will respond. Note that in the push flow this order is reversed.#[get("/<org_path>/<proj_path>/.pijul?<channel>&<id>", rank = 2)]async fn remote_id(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,use rocket::fs::NamedFile;
use crate::database::Database;use crate::models::projects;use crate::repoman::RepoMan;use rocket::fs::NamedFile;use rocket::{Route, State};/// Because of the overlap with other routes in parameters, this route has/// rank 2. This way the changelist matches first, and if it doesn't, this route/// will respond. Note that in the push flow this order is reversed.#[get("/<org_path>/<proj_path>/.pijul?<channel>&<id>", rank = 2)]async fn remote_id(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,channel: String, // TODO check if this breaks non-UTF-8 channelsid: Option<String>,) -> Option<String> {let p = match projects::find(db, org_path, proj_path).await {Some(p) => p,None => return None,};match p.repository(&repoman.storage_root) {Ok(r) => r.channel_remote_id(channel, id),Err(e) => {println!("{}", e);None}}}#[get("/<org_path>/<proj_path>/.pijul?<changelist>&<channel>")]async fn changelist(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,channel: String, // TODO check if this breaks non-UTF-8 channelschangelist: u64,) -> Option<String> {let p = projects::find(db, org_path, proj_path).await?;match p.repository(&repoman.storage_root).unwrap().changelist(channel, changelist){Ok(out) => Some(out),Err(e) => {println!("error getting changelist: {}", e);None}}}use rocket::fs::TempFile;// TODO pijul: When this endpoint returns a 4XX or 5XX status code, it thinks the push still// succeeded.#[post("/<org_path>/<proj_path>/.pijul?<apply>", data = "<patch>")]async fn apply(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,apply: String,mut patch: TempFile<'_>,) -> rocket::http::Status {let p = if let Some(p) = projects::find(db, org_path, proj_path).await {p} else {return rocket::http::Status::NotFound;};let repo = p.repository(&repoman.storage_root).unwrap();let hash =if let Some(h) = crate::models::pijul::changestores::Changestore::hash_from_string(apply) {h} else {return rocket::http::Status::InternalServerError;};let patch_path = repo.changestore().change_file(hash);repo.changestore().ensure_parent_dirs(hash);if patch.persist_to(&patch_path).await.is_err() {return rocket::http::Status::InternalServerError;}if !repo.valid_change(hash) {// TODO clean upprintln!("Not valid as object");return rocket::http::Status::InternalServerError;}if repo.apply_change_to_channel("main", hash).is_ok() {return rocket::http::Status::Accepted;};rocket::http::Status::InternalServerError}#[derive(FromForm)]struct Identities {identities: Vec<String>,}use rocket::serde::{json::Json, Serialize};#[derive(Serialize, FromForm)]struct IdentitieRes {id: Vec<String>,rev: u64,}// TODO figure out what I'm supposed to send here?#[get("/<org_path>/<proj_path>/.pijul?<identities>", rank = 4)]fn identities(org_path: String, proj_path: String, identities: Identities) -> Json<IdentitieRes> {Json(IdentitieRes { id: vec![], rev: 0 })}#[get("/<org_path>/<proj_path>/.pijul?<change>", rank = 3)]async fn change(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,change: String,) -> Option<NamedFile> {let p = projects::find(db, org_path, proj_path).await?;let hash = crate::models::pijul::changestores::Changestore::hash_from_string(change)?;let repo = p.repository(&repoman.storage_root).ok()?;let path = repo.changestore().change_file(hash);NamedFile::open(path).await.ok()}pub fn routes() -> Vec<Route> {routes![remote_id, changelist, apply, identities, change]}