1use bytes::Bytes;
4use reqwest::Method;
5use serde::Deserialize;
6
7use crate::api::{UploadOptions, UploadResult, prepare_upload_headers};
8use crate::client::{Inner, request};
9use crate::swarm::{
10 BatchId, Error, EthAddress, Identifier, PrivateKey, Reference, Signature, SingleOwnerChunk,
11 calculate_single_owner_chunk_address, make_single_owner_chunk, unmarshal_single_owner_chunk,
12};
13
14use super::FileApi;
15use super::chunk::download_chunk_response;
16
17#[derive(Deserialize)]
18struct UploadBody {
19 reference: String,
20}
21
22impl FileApi {
23 pub async fn upload_soc(
27 &self,
28 batch_id: &BatchId,
29 owner: &EthAddress,
30 identifier: &Identifier,
31 signature: &Signature,
32 data: impl Into<Bytes>,
33 opts: Option<&UploadOptions>,
34 ) -> Result<UploadResult, Error> {
35 let path = format!("soc/{}/{}", owner.to_hex(), identifier.to_hex());
36 let builder = request(&self.inner, Method::POST, &path)?
37 .header("Content-Type", "application/octet-stream")
38 .query(&[("sig", signature.to_hex())])
39 .body(data.into());
40 let builder = Inner::apply_headers(builder, prepare_upload_headers(batch_id, opts));
41 let resp = self.inner.send(builder).await?;
42 let headers = resp.headers().clone();
43 let body: UploadBody = serde_json::from_slice(&resp.bytes().await?)?;
44 UploadResult::from_response(&body.reference, &headers)
45 }
46
47 pub fn make_soc_reader(&self, owner: EthAddress) -> SocReader {
49 SocReader {
50 owner,
51 inner: self.inner.clone(),
52 }
53 }
54
55 pub fn make_soc_writer(&self, signer: PrivateKey) -> Result<SocWriter, Error> {
58 let owner = signer.public_key()?.address();
59 Ok(SocWriter {
60 reader: SocReader {
61 owner,
62 inner: self.inner.clone(),
63 },
64 signer,
65 })
66 }
67}
68
69#[derive(Clone, Debug)]
73pub struct SocReader {
74 owner: EthAddress,
75 inner: std::sync::Arc<Inner>,
76}
77
78impl SocReader {
79 pub fn owner(&self) -> &EthAddress {
81 &self.owner
82 }
83
84 pub async fn download(&self, identifier: &Identifier) -> Result<SingleOwnerChunk, Error> {
87 let address = calculate_single_owner_chunk_address(identifier, &self.owner)?;
88 let resp = download_chunk_response(&self.inner, &address, None).await?;
89 let bytes = resp.bytes().await?;
90 unmarshal_single_owner_chunk(&bytes, &address)
91 }
92}
93
94#[derive(Clone, Debug)]
96pub struct SocWriter {
97 reader: SocReader,
98 signer: PrivateKey,
99}
100
101impl SocWriter {
102 pub fn owner(&self) -> &EthAddress {
104 self.reader.owner()
105 }
106
107 pub fn reader(&self) -> &SocReader {
109 &self.reader
110 }
111
112 pub async fn upload(
115 &self,
116 batch_id: &BatchId,
117 identifier: &Identifier,
118 data: &[u8],
119 opts: Option<&UploadOptions>,
120 ) -> Result<UploadResult, Error> {
121 let soc = make_single_owner_chunk(identifier, data, &self.signer)?;
122 let mut full = Vec::with_capacity(soc.span.as_bytes().len() + soc.payload.len());
123 full.extend_from_slice(soc.span.as_bytes());
124 full.extend_from_slice(&soc.payload);
125 let api = FileApi {
126 inner: self.reader.inner.clone(),
127 };
128 api.upload_soc(
129 batch_id,
130 &self.reader.owner,
131 identifier,
132 &soc.signature,
133 full,
134 opts,
135 )
136 .await
137 }
138}
139
140pub fn soc_address(identifier: &Identifier, owner: &EthAddress) -> Result<Reference, Error> {
143 calculate_single_owner_chunk_address(identifier, owner)
144}