Skip to content

Commit cb371bb

Browse files
committed
Start on ipfs-cart
1 parent d3e5e82 commit cb371bb

File tree

22 files changed

+715
-37
lines changed

22 files changed

+715
-37
lines changed

bun.lockb

7.98 KB
Binary file not shown.

bunshot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bunshot",
3-
"version": "1.0.0",
3+
"version": "0.0.1",
44
"description": "A Bun service that takes screenshots of websites using Puppeteer and uploads them to S3",
55
"main": "src/index.ts",
66
"type": "module",

engine/.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ S3_PREVIEWS_BUCKET_NAME=screenshots
1515
S3_PREVIEWS_ACCESS_KEY=minioadmin
1616
S3_PREVIEWS_SECRET_KEY=minioadmin
1717

18+
# S3 Car (Defaults)
19+
S3_CAR_ENDPOINT_URL=http://localhost:9000
20+
S3_CAR_REGION=us-east-1
21+
S3_CAR_BUCKET_NAME=car
22+
S3_CAR_ACCESS_KEY=minioadmin
23+
S3_CAR_SECRET_KEY=minioadmin
24+
1825
GITHUB_APP_CLIENT_ID=*******************
1926
GITHUB_APP_CLIENT_SECRET=*******************************
2027
# RUST_LOG=info,sqlx=trace

engine/compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ services:
3232
mc alias set minio http://127.0.0.1:9000 minioadmin minioadmin # setup Minio client
3333
mc mb minio/edgeserver || true # create a test bucket
3434
mc mb minio/screenshots || true # create a test bucket
35+
mc mb minio/car || true # create a test bucket
3536
mc anonymous set public minio/edgeserver # make the test bucket public
3637
mc anonymous set public minio/screenshots # make the test bucket public
3738
kill -s INT $(cat /tmp/minio.pid) && rm /tmp/minio.pid # stop Minio

engine/src/ipfs/mod.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
use crate::{models::deployment::{DeploymentFile, DeploymentFileEntry}, state::State};
22
use serde::{Deserialize, Serialize};
33

4-
#[derive(Debug, Serialize, Deserialize)]
5-
pub struct CarRequest {
6-
pub deployment_id: String,
7-
pub files: Vec<DeploymentFileEntry>,
8-
}
94

105
pub struct IPFSCluster {
116
pub cluster_url: String,
@@ -16,17 +11,6 @@ impl IPFSCluster {
1611
Self { cluster_url }
1712
}
1813

19-
pub async fn pin_deployment(&self, deployment_id: String, state: &State) -> Result<String, Box<dyn std::error::Error>> {
20-
let deployment_files = DeploymentFile::get_deployment_files(&state.database, &deployment_id).await?;
21-
22-
let car_request = CarRequest {
23-
deployment_id,
24-
files: deployment_files,
25-
};
26-
27-
todo!()
28-
}
29-
3014
// pub async fn add_car(&self, car_path: &str) -> Result<String, Box<dyn std::error::Error>> {
3115
// let client = reqwest::Client::new();
3216
// let response = client.post(&format!("{}/add", self.cluster_url))

engine/src/models/deployment/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,14 @@ impl Deployment {
8484
// }
8585

8686
#[tracing::instrument(name = "upload_files", skip(self, state, file))]
87-
pub async fn upload_files(&self, state: &State, file: Upload) -> Result<(), sqlx::Error> {
87+
pub async fn upload_files(&self, state: &State, file: Vec<u8>) -> Result<(), sqlx::Error> {
8888
let span = info_span!("Deployment::upload_files");
8989
span.set_parent(Context::current());
9090
let _guard = span.enter();
9191

92-
let file_stream = file.into_vec().await.unwrap();
93-
9492
// TODO: Read file stream, extract zip file (contains multiple files), upload each file to s3 at the correct relevant path relative to deployment.deployment_id + '/'
9593

96-
let zip = ZipFileReader::new(file_stream).await.unwrap();
94+
let zip = ZipFileReader::new(file).await.unwrap();
9795

9896
for index in 0..zip.file().entries().len() {
9997
let file = zip.file().entries().get(index).unwrap();

engine/src/rabbit.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct TaskRabbit {
1313
channel: Channel,
1414

1515
previews_queue_key: String,
16+
car_queue_key: String,
1617
}
1718

1819
#[derive(Debug, Serialize, Deserialize)]
@@ -22,6 +23,12 @@ pub struct BunshotPayload {
2223
pub domain: String,
2324
}
2425

26+
#[derive(Debug, Serialize, Deserialize)]
27+
pub struct CarRequest {
28+
pub deployment_id: String,
29+
pub file_path: String,
30+
}
31+
2532
impl TaskRabbit {
2633
pub async fn init(config: &AMQPConfig) -> TaskRabbit {
2734
let connection = Connection::connect(config.addr.as_str(), ConnectionProperties::default())
@@ -53,10 +60,26 @@ impl TaskRabbit {
5360

5461
info!("Bunshot queue declared");
5562

63+
let car_channel = connection.create_channel().await.unwrap();
64+
65+
let car_queue_key = config.car_queue.as_deref().unwrap_or("car").to_string();
66+
67+
car_channel
68+
.queue_declare(
69+
&car_queue_key,
70+
QueueDeclareOptions {
71+
durable: true,
72+
..QueueDeclareOptions::default()
73+
},
74+
FieldTable::default(),
75+
)
76+
.await
77+
.unwrap();
5678
TaskRabbit {
5779
connection,
5880
channel: bunshot_channel,
5981
previews_queue_key,
82+
car_queue_key,
6083
}
6184
}
6285

@@ -89,4 +112,29 @@ impl TaskRabbit {
89112
info!("Failed to publish message to screenshots queue");
90113
}
91114
}
115+
116+
pub async fn queue_car(&self, request: CarRequest) {
117+
let payload = serde_json::to_string(&request).unwrap();
118+
119+
// Publish to the car queue
120+
let confirm = self
121+
.channel
122+
.basic_publish(
123+
"",
124+
&self.car_queue_key,
125+
BasicPublishOptions::default(),
126+
payload.as_bytes(),
127+
BasicProperties::default().with_delivery_mode(2),
128+
)
129+
.await
130+
.unwrap()
131+
.await
132+
.unwrap();
133+
134+
if confirm == Confirmation::NotRequested || confirm == Confirmation::Ack(None) {
135+
info!("Message successfully published to car queue");
136+
} else {
137+
info!("Failed to publish message to car queue");
138+
}
139+
}
92140
}

engine/src/routes/site/deployments/mod.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ use poem_openapi::{param::Path, payload::Json, OpenApi};
33
use tracing::info;
44

55
use crate::{
6-
middlewares::auth::UserAuth,
7-
models::{
8-
deployment::{preview::DeploymentPreview, Deployment, DeploymentFile, DeploymentFileEntry}, domain::Domain, site::{Site, SiteId}
9-
},
10-
routes::{error::HttpError, ApiTags},
11-
state::State,
6+
middlewares::auth::UserAuth, models::{
7+
deployment::{preview::DeploymentPreview, Deployment, DeploymentFile, DeploymentFileEntry},
8+
domain::Domain,
9+
site::{Site, SiteId},
10+
}, rabbit::CarRequest, routes::{error::HttpError, ApiTags}, state::State
1211
};
1312

1413
use super::UploadPayload;
@@ -113,6 +112,22 @@ impl SiteDeploymentsApi {
113112
info!("Deployment complete");
114113

115114
if let Some(data) = payload.data {
115+
let data = data.into_vec().await.unwrap();
116+
117+
if let Some(car_bucket) = &state.storage.car_bucket {
118+
let path = format!("{}/car.zip", deployment.deployment_id);
119+
let _ = car_bucket.put_object(&path, &data).await.unwrap();
120+
121+
info!("Car uploaded to: {:?}", path);
122+
123+
if let Some(rabbit) = &state.rabbit {
124+
rabbit.queue_car(CarRequest {
125+
deployment_id: deployment.deployment_id.clone(),
126+
file_path: path.clone(),
127+
}).await;
128+
}
129+
}
130+
116131
Deployment::upload_files(&deployment, &state, data)
117132
.await
118133
.unwrap();
@@ -158,6 +173,22 @@ impl SiteDeploymentsApi {
158173
info!("Deployment complete");
159174

160175
if let Some(data) = payload.data {
176+
let data = data.into_vec().await.unwrap();
177+
178+
if let Some(car_bucket) = &state.storage.car_bucket {
179+
let path = format!("{}/car.zip", deployment.deployment_id);
180+
let _ = car_bucket.put_object(&path, &data).await.unwrap();
181+
182+
if let Some(rabbit) = &state.rabbit {
183+
rabbit.queue_car(CarRequest {
184+
deployment_id: deployment_id.clone(),
185+
file_path: path.clone(),
186+
}).await;
187+
}
188+
189+
info!("Car uploaded to: {:?}", path);
190+
}
191+
161192
Deployment::upload_files(&deployment, &state, data)
162193
.await
163194
.unwrap();
@@ -182,7 +213,9 @@ impl SiteDeploymentsApi {
182213
if let Some(rabbit) = &state.rabbit {
183214
info!("Queueing bunshot for domain: {:?}", domain);
184215
let domain = domain.domain();
185-
rabbit.queue_bunshot(&site_id.0, &deployment_id, &domain).await;
216+
rabbit
217+
.queue_bunshot(&site_id.0, &deployment_id, &domain)
218+
.await;
186219
}
187220
} else {
188221
info!("No domain was found for this site");
@@ -246,7 +279,9 @@ impl SiteDeploymentsApi {
246279

247280
if let Some(domain) = domain {
248281
info!("Queueing bunshot for domain: {:?}", domain.domain());
249-
rabbit.queue_bunshot(&site_id.0, &deployment_id.0, &domain.domain()).await;
282+
rabbit
283+
.queue_bunshot(&site_id.0, &deployment_id.0, &domain.domain())
284+
.await;
250285
} else {
251286
info!("No domain was found for this site");
252287
}

engine/src/state.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct AppConfig {
2323
pub database_url: String,
2424
pub s3: S3Config,
2525
pub s3_previews: Option<S3PreviewsConfig>,
26+
pub s3_car: Option<S3CarConfig>,
2627
pub github_app: Option<GithubAppConfig>,
2728
pub amqp: Option<AMQPConfig>,
2829
}
@@ -45,10 +46,20 @@ pub struct S3PreviewsConfig {
4546
pub secret_key: String,
4647
}
4748

49+
#[derive(Deserialize, Debug)]
50+
pub struct S3CarConfig {
51+
pub endpoint_url: String,
52+
pub region: String,
53+
pub bucket_name: String,
54+
pub access_key: String,
55+
pub secret_key: String,
56+
}
57+
4858
#[derive(Deserialize, Debug)]
4959
pub struct AMQPConfig {
5060
pub addr: String,
5161
pub previews_queue: Option<String>,
62+
pub car_queue: Option<String>,
5263
}
5364

5465
/// Github App Config
@@ -82,6 +93,8 @@ impl AppState {
8293
.map(|key| format!("s3.{}", key.as_str().to_lowercase()).into()))
8394
.merge(Env::prefixed("S3_PREVIEWS_")
8495
.map(|key| format!("s3_previews.{}", key.as_str().to_lowercase()).into()))
96+
.merge(Env::prefixed("S3_CAR_")
97+
.map(|key| format!("s3_car.{}", key.as_str().to_lowercase()).into()))
8598
.merge(Env::prefixed("GITHUB_APP_")
8699
.map(|key| format!("github_app.{}", key.as_str().to_lowercase()).into()))
87100
.merge(Env::prefixed("AMQP_")

engine/src/storage.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::state::AppConfig;
88
pub struct Storage {
99
pub bucket: Box<Bucket>,
1010
pub previews_bucket: Option<Box<Bucket>>,
11+
pub car_bucket: Option<Box<Bucket>>,
1112
}
1213

1314
impl Storage {
@@ -50,7 +51,29 @@ impl Storage {
5051
None
5152
};
5253

53-
Self { bucket, previews_bucket }
54+
let car_bucket = if let Some(car_config) = &config.s3_car {
55+
let car_region = Region::Custom {
56+
region: car_config.region.clone(),
57+
endpoint: car_config.endpoint_url.clone(),
58+
};
59+
let car_credentials = Credentials::new(
60+
Some(&car_config.access_key),
61+
Some(&car_config.secret_key),
62+
None,
63+
None,
64+
None,
65+
)
66+
.unwrap();
67+
let car_bucket = Bucket::new(&car_config.bucket_name, car_region, car_credentials)
68+
.unwrap()
69+
.with_path_style();
70+
71+
Some(car_bucket)
72+
} else {
73+
None
74+
};
75+
76+
Self { bucket, previews_bucket, car_bucket }
5477
}
5578

5679
pub async fn upload(

0 commit comments

Comments
 (0)