| 505 | } |
| 506 | |
| 507 | async fn write_text( |
| 508 | &self, |
| 509 | path: &WorkspacePath, |
| 510 | content: &str, |
| 511 | ) -> WorkspaceResult<WorkspaceWriteOutcome> { |
| 512 | let key = self.key_for(path); |
| 513 | let body = ByteStream::from(content.as_bytes().to_vec()); |
| 514 | let bytes = content.len() as u64; |
| 515 | |
| 516 | let start = std::time::Instant::now(); |
| 517 | let send_result = self |
| 518 | .client |
| 519 | .put_object() |
| 520 | .bucket(&self.bucket) |
| 521 | .key(&key) |
| 522 | .body(body) |
| 523 | .content_type("text/plain; charset=utf-8") |
| 524 | .send() |
| 525 | .await; |
| 526 | emit_s3_call_event( |
| 527 | "s3.put_object", |
| 528 | &self.bucket, |
| 529 | &key, |
| 530 | bytes, |
| 531 | send_result.is_ok(), |
| 532 | start.elapsed(), |
| 533 | ); |
| 534 | send_result.map_err(|e| { |
| 535 | anyhow!( |
| 536 | "Failed to write S3 object s3://{}/{}: {}", |
| 537 | self.bucket, |
| 538 | key, |
| 539 | e |
| 540 | ) |
| 541 | })?; |
| 542 | |
| 543 | Ok(WorkspaceWriteOutcome { |
| 544 | bytes: content.len(), |
| 545 | lines: content.lines().count(), |
| 546 | }) |
| 547 | } |
| 548 | |
| 549 | async fn list_dir(&self, path: &WorkspacePath) -> WorkspaceResult<Vec<WorkspaceDirEntry>> { |
| 550 | let prefix = self.list_prefix_for(path); |