posthog_cli/commands/sourcemap/
upload.rs1use core::str;
2use std::path::PathBuf;
3
4use anyhow::{anyhow, Context, Ok, Result};
5use tracing::info;
6
7use crate::utils::auth::load_token;
8use crate::utils::sourcemaps::{read_pairs, ChunkUpload, SourcePair};
9
10pub fn upload(host: &str, directory: &PathBuf, _build_id: &Option<String>) -> Result<()> {
11 let token = load_token().context("While starting upload command")?;
12
13 let url = format!(
14 "{}/api/projects/{}/error_tracking/symbol_sets",
15 host, token.env_id
16 );
17
18 let pairs = read_pairs(directory)?;
19
20 let uploads = collect_uploads(pairs).context("While preparing files for upload")?;
21 info!("Found {} chunks to upload", uploads.len());
22
23 upload_chunks(&url, &token.token, uploads)?;
24
25 Ok(())
26}
27
28fn collect_uploads(pairs: Vec<SourcePair>) -> Result<Vec<ChunkUpload>> {
29 let uploads: Vec<ChunkUpload> = pairs
30 .into_iter()
31 .map(|pair| pair.into_chunk_upload())
32 .collect::<Result<Vec<ChunkUpload>>>()?;
33 Ok(uploads)
34}
35
36fn upload_chunks(url: &str, token: &str, uploads: Vec<ChunkUpload>) -> Result<()> {
37 let client = reqwest::blocking::Client::new();
38 for upload in uploads {
39 info!("Uploading chunk {}", upload.chunk_id);
40 let res = client
41 .post(url)
42 .header("Authorization", format!("Bearer {}", token))
43 .header("Content-Type", "application/octet-stream")
44 .header("Content-Disposition", "attachment; filename='chunk'")
45 .query(&[("chunk_id", &upload.chunk_id)])
46 .body(upload.data)
47 .send()
48 .context(format!("While uploading chunk to {}", url))?;
49
50 if !res.status().is_success() {
51 return Err(anyhow!("Failed to upload chunk: {:?}", res)
52 .context(format!("Chunk id: {}", upload.chunk_id)));
53 }
54 }
55
56 Ok(())
57}