Finalize a streamed upload into a published mod: complete the temp object, derive the mod id (`slug(name)-version`, version defaulting to the content hash), move the temp object into place, and write `mod.json`.
(
&self,
upload: ArtifactUpload,
meta: ModUploadMeta,
)
| 268 | if self.get_mod(&slug).await?.is_some() { |
| 269 | bail!("mod id '{slug}' already exists"); |
| 270 | } |
| 271 | |
| 272 | let digest = Sha256::digest(&input.file); |
| 273 | let sha256 = hex(&digest); |
| 274 | let version = match input.version.as_deref() { |
| 275 | Some(value) => sanitize_version(value) |
| 276 | .ok_or_else(|| anyhow::anyhow!("invalid version '{value}'"))?, |
| 277 | None => content_hash8(&input.file), |
| 278 | }; |
| 279 | let size_bytes = input.file.len() as u64; |
| 280 | let entry = ModCatalogEntry { |
| 281 | mod_id: slug.clone(), |
| 282 | app_name: input.app_name.clone(), |
| 283 | actver: input.actver, |
| 284 | version_tag: input.version_tag.clone(), |
| 285 | compatible: false, |
| 286 | name: input.name.clone(), |
| 287 | version, |
| 288 | package_revision: 1, |
| 289 | sha256: Some(sha256), |
| 290 | published_unix_ms: Some(now_unix_millis()), |
| 291 | folder_name: None, |
| 292 | description: input.description.clone().unwrap_or_default(), |
| 293 | authors: input.authors.clone(), |
| 294 | homepage_url: input.homepage_url.clone(), |
| 295 | download_url: Some(format!("/v1/mods/{slug}/revisions/1/download")), |
| 296 | size_bytes: Some(size_bytes), |
| 297 | }; |
| 298 | self.write_new_revision(&entry, Bytes::from(input.file.clone())) |
| 299 | .await?; |
| 300 | self.create_current(&slug, 1).await?; |
| 301 | Ok(entry) |
| 302 | } |
| 303 | |
| 304 | async fn write_new_revision(&self, entry: &ModCatalogEntry, artifact: Bytes) -> Result<()> { |
| 305 | let artifact_path = self.store_path(Self::revision_artifact_path( |
| 306 | &entry.mod_id, |
| 307 | entry.package_revision, |
| 308 | )); |
| 309 | self.store |
| 310 | .put_opts(&artifact_path, artifact.into(), PutMode::Create.into()) |
| 311 | .await |
| 312 | .with_context(|| { |
| 313 | format!( |
| 314 | "reserving revision {} for {}", |
| 315 | entry.package_revision, entry.mod_id |
| 316 | ) |
| 317 | })?; |
| 318 | let metadata_path = self.store_path(Self::revision_metadata_path( |
| 319 | &entry.mod_id, |
| 320 | entry.package_revision, |
| 321 | )); |
| 322 | let json = serde_json::to_vec_pretty(entry)?; |
| 323 | if let Err(error) = self |
| 324 | .store |
| 325 | .put_opts( |
| 326 | &metadata_path, |
| 327 | Bytes::from(json).into(), |
no test coverage detected