#[allow(unused_imports)]
use async_trait::async_trait;
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
#[allow(unused_imports)]
use std::{borrow::Borrow, borrow::Cow, io::Write, string::ToString};
#[allow(unused_imports)]
use wasmbus_rpc::{
cbor::*,
common::{
deserialize, message_format, serialize, Context, Message, MessageDispatch, MessageFormat,
SendOpts, Transport,
},
error::{RpcError, RpcResult},
Timestamp,
};
#[allow(dead_code)]
pub const SMITHY_VERSION: &str = "1.0";
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct Chunk {
#[serde(rename = "objectId")]
pub object_id: ObjectId,
#[serde(rename = "containerId")]
pub container_id: ContainerId,
#[serde(with = "serde_bytes")]
#[serde(default)]
pub bytes: Vec<u8>,
#[serde(default)]
pub offset: u64,
#[serde(rename = "isLast")]
#[serde(default)]
pub is_last: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ChunkResponse {
#[serde(rename = "cancelDownload")]
#[serde(default)]
pub cancel_download: bool,
}
pub type ContainerId = String;
pub type ContainerIds = Vec<ContainerId>;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ContainerMetadata {
#[serde(rename = "containerId")]
pub container_id: ContainerId,
#[serde(rename = "createdAt")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created_at: Option<Timestamp>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ContainerObject {
#[serde(rename = "containerId")]
pub container_id: ContainerId,
#[serde(rename = "objectId")]
pub object_id: ObjectId,
}
pub type ContainersInfo = Vec<ContainerMetadata>;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct GetObjectRequest {
#[serde(rename = "objectId")]
pub object_id: ObjectId,
#[serde(rename = "containerId")]
pub container_id: ContainerId,
#[serde(rename = "rangeStart")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub range_start: Option<u64>,
#[serde(rename = "rangeEnd")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub range_end: Option<u64>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct GetObjectResponse {
#[serde(default)]
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(rename = "initialChunk")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub initial_chunk: Option<Chunk>,
#[serde(rename = "contentLength")]
#[serde(default)]
pub content_length: u64,
#[serde(rename = "contentType")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(rename = "contentEncoding")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_encoding: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ItemResult {
#[serde(default)]
pub key: String,
#[serde(default)]
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ListObjectsRequest {
#[serde(rename = "containerId")]
#[serde(default)]
pub container_id: String,
#[serde(rename = "startWith")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub start_with: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub continuation: Option<String>,
#[serde(rename = "endWith")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub end_with: Option<String>,
#[serde(rename = "endBefore")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub end_before: Option<String>,
#[serde(rename = "maxItems")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_items: Option<u32>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ListObjectsResponse {
pub objects: ObjectsInfo,
#[serde(rename = "isLast")]
#[serde(default)]
pub is_last: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub continuation: Option<String>,
}
pub type MultiResult = Vec<ItemResult>;
pub type ObjectId = String;
pub type ObjectIds = Vec<ObjectId>;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ObjectMetadata {
#[serde(rename = "objectId")]
pub object_id: ObjectId,
#[serde(rename = "containerId")]
pub container_id: ContainerId,
#[serde(rename = "contentLength")]
#[serde(default)]
pub content_length: u64,
#[serde(rename = "lastModified")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_modified: Option<Timestamp>,
#[serde(rename = "contentType")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(rename = "contentEncoding")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_encoding: Option<String>,
}
pub type ObjectsInfo = Vec<ObjectMetadata>;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct PutChunkRequest {
pub chunk: Chunk,
#[serde(rename = "streamId")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_id: Option<String>,
#[serde(rename = "cancelAndRemove")]
#[serde(default)]
pub cancel_and_remove: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct PutObjectRequest {
pub chunk: Chunk,
#[serde(rename = "contentType")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(rename = "contentEncoding")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_encoding: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct PutObjectResponse {
#[serde(rename = "streamId")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_id: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct RemoveObjectsRequest {
#[serde(rename = "containerId")]
pub container_id: ContainerId,
pub objects: ObjectIds,
}
#[async_trait]
pub trait Blobstore {
fn contract_id() -> &'static str {
"wasmcloud:blobstore"
}
async fn container_exists(&self, ctx: &Context, arg: &ContainerId) -> RpcResult<bool>;
async fn create_container(&self, ctx: &Context, arg: &ContainerId) -> RpcResult<()>;
async fn get_container_info(
&self,
ctx: &Context,
arg: &ContainerId,
) -> RpcResult<ContainerMetadata>;
async fn list_containers(&self, ctx: &Context) -> RpcResult<ContainersInfo>;
async fn remove_containers(&self, ctx: &Context, arg: &ContainerIds) -> RpcResult<MultiResult>;
async fn object_exists(&self, ctx: &Context, arg: &ContainerObject) -> RpcResult<bool>;
async fn get_object_info(
&self,
ctx: &Context,
arg: &ContainerObject,
) -> RpcResult<ObjectMetadata>;
async fn list_objects(
&self,
ctx: &Context,
arg: &ListObjectsRequest,
) -> RpcResult<ListObjectsResponse>;
async fn remove_objects(
&self,
ctx: &Context,
arg: &RemoveObjectsRequest,
) -> RpcResult<MultiResult>;
async fn put_object(
&self,
ctx: &Context,
arg: &PutObjectRequest,
) -> RpcResult<PutObjectResponse>;
async fn get_object(
&self,
ctx: &Context,
arg: &GetObjectRequest,
) -> RpcResult<GetObjectResponse>;
async fn put_chunk(&self, ctx: &Context, arg: &PutChunkRequest) -> RpcResult<()>;
}
#[doc(hidden)]
#[async_trait]
pub trait BlobstoreReceiver: MessageDispatch + Blobstore {
async fn dispatch(&self, ctx: &Context, message: Message<'_>) -> Result<Vec<u8>, RpcError> {
match message.method {
"ContainerExists" => {
let value: ContainerId = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerId': {}", e)))?;
let resp = Blobstore::container_exists(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"CreateContainer" => {
let value: ContainerId = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerId': {}", e)))?;
Blobstore::create_container(self, ctx, &value).await?;
Ok(vec![])
}
"GetContainerInfo" => {
let value: ContainerId = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerId': {}", e)))?;
let resp = Blobstore::get_container_info(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"ListContainers" => {
let resp = Blobstore::list_containers(self, ctx).await?;
wasmbus_rpc::common::serialize(&resp)
}
"RemoveContainers" => {
let value: ContainerIds = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerIds': {}", e)))?;
let resp = Blobstore::remove_containers(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"ObjectExists" => {
let value: ContainerObject = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerObject': {}", e)))?;
let resp = Blobstore::object_exists(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"GetObjectInfo" => {
let value: ContainerObject = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ContainerObject': {}", e)))?;
let resp = Blobstore::get_object_info(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"ListObjects" => {
let value: ListObjectsRequest = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'ListObjectsRequest': {}", e)))?;
let resp = Blobstore::list_objects(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"RemoveObjects" => {
let value: RemoveObjectsRequest = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'RemoveObjectsRequest': {}", e)))?;
let resp = Blobstore::remove_objects(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"PutObject" => {
let value: PutObjectRequest = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'PutObjectRequest': {}", e)))?;
let resp = Blobstore::put_object(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"GetObject" => {
let value: GetObjectRequest = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'GetObjectRequest': {}", e)))?;
let resp = Blobstore::get_object(self, ctx, &value).await?;
wasmbus_rpc::common::serialize(&resp)
}
"PutChunk" => {
let value: PutChunkRequest = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'PutChunkRequest': {}", e)))?;
let _resp = Blobstore::put_chunk(self, ctx, &value).await?;
let buf = Vec::new();
Ok(buf)
}
_ => Err(RpcError::MethodNotHandled(format!(
"Blobstore::{}",
message.method
))),
}
}
}
#[derive(Clone, Debug)]
pub struct BlobstoreSender<T: Transport> {
transport: T,
}
impl<T: Transport> BlobstoreSender<T> {
pub fn via(transport: T) -> Self {
Self { transport }
}
pub fn set_timeout(&self, interval: std::time::Duration) {
self.transport.set_timeout(interval);
}
}
#[cfg(target_arch = "wasm32")]
impl BlobstoreSender<wasmbus_rpc::actor::prelude::WasmHost> {
pub fn new() -> Self {
let transport =
wasmbus_rpc::actor::prelude::WasmHost::to_provider("wasmcloud:blobstore", "default")
.unwrap();
Self { transport }
}
pub fn new_with_link(link_name: &str) -> wasmbus_rpc::error::RpcResult<Self> {
let transport =
wasmbus_rpc::actor::prelude::WasmHost::to_provider("wasmcloud:blobstore", link_name)?;
Ok(Self { transport })
}
}
#[async_trait]
impl<T: Transport + std::marker::Sync + std::marker::Send> Blobstore for BlobstoreSender<T> {
#[allow(unused)]
async fn container_exists(&self, ctx: &Context, arg: &ContainerId) -> RpcResult<bool> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.ContainerExists",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: bool = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': Boolean", e)))?;
Ok(value)
}
#[allow(unused)]
async fn create_container(&self, ctx: &Context, arg: &ContainerId) -> RpcResult<()> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.CreateContainer",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
Ok(())
}
#[allow(unused)]
async fn get_container_info(
&self,
ctx: &Context,
arg: &ContainerId,
) -> RpcResult<ContainerMetadata> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.GetContainerInfo",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: ContainerMetadata = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': ContainerMetadata", e)))?;
Ok(value)
}
#[allow(unused)]
async fn list_containers(&self, ctx: &Context) -> RpcResult<ContainersInfo> {
let buf = *b"";
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.ListContainers",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: ContainersInfo = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': ContainersInfo", e)))?;
Ok(value)
}
#[allow(unused)]
async fn remove_containers(&self, ctx: &Context, arg: &ContainerIds) -> RpcResult<MultiResult> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.RemoveContainers",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: MultiResult = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': MultiResult", e)))?;
Ok(value)
}
#[allow(unused)]
async fn object_exists(&self, ctx: &Context, arg: &ContainerObject) -> RpcResult<bool> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.ObjectExists",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: bool = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': Boolean", e)))?;
Ok(value)
}
#[allow(unused)]
async fn get_object_info(
&self,
ctx: &Context,
arg: &ContainerObject,
) -> RpcResult<ObjectMetadata> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.GetObjectInfo",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: ObjectMetadata = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': ObjectMetadata", e)))?;
Ok(value)
}
#[allow(unused)]
async fn list_objects(
&self,
ctx: &Context,
arg: &ListObjectsRequest,
) -> RpcResult<ListObjectsResponse> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.ListObjects",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: ListObjectsResponse = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': ListObjectsResponse", e)))?;
Ok(value)
}
#[allow(unused)]
async fn remove_objects(
&self,
ctx: &Context,
arg: &RemoveObjectsRequest,
) -> RpcResult<MultiResult> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.RemoveObjects",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: MultiResult = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': MultiResult", e)))?;
Ok(value)
}
#[allow(unused)]
async fn put_object(
&self,
ctx: &Context,
arg: &PutObjectRequest,
) -> RpcResult<PutObjectResponse> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.PutObject",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: PutObjectResponse = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': PutObjectResponse", e)))?;
Ok(value)
}
#[allow(unused)]
async fn get_object(
&self,
ctx: &Context,
arg: &GetObjectRequest,
) -> RpcResult<GetObjectResponse> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.GetObject",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: GetObjectResponse = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': GetObjectResponse", e)))?;
Ok(value)
}
#[allow(unused)]
async fn put_chunk(&self, ctx: &Context, arg: &PutChunkRequest) -> RpcResult<()> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "Blobstore.PutChunk",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
Ok(())
}
}
#[async_trait]
pub trait ChunkReceiver {
fn contract_id() -> &'static str {
"wasmcloud:blobstore"
}
async fn receive_chunk(&self, ctx: &Context, arg: &Chunk) -> RpcResult<ChunkResponse>;
}
#[doc(hidden)]
#[async_trait]
pub trait ChunkReceiverReceiver: MessageDispatch + ChunkReceiver {
async fn dispatch(&self, ctx: &Context, message: Message<'_>) -> Result<Vec<u8>, RpcError> {
match message.method {
"ReceiveChunk" => {
let value: Chunk = wasmbus_rpc::common::deserialize(&message.arg)
.map_err(|e| RpcError::Deser(format!("'Chunk': {}", e)))?;
let resp = ChunkReceiver::receive_chunk(self, ctx, &value).await?;
let buf = wasmbus_rpc::common::serialize(&resp)?;
Ok(buf)
}
_ => Err(RpcError::MethodNotHandled(format!(
"ChunkReceiver::{}",
message.method
))),
}
}
}
#[derive(Clone, Debug)]
pub struct ChunkReceiverSender<T: Transport> {
transport: T,
}
impl<T: Transport> ChunkReceiverSender<T> {
pub fn via(transport: T) -> Self {
Self { transport }
}
pub fn set_timeout(&self, interval: std::time::Duration) {
self.transport.set_timeout(interval);
}
}
#[cfg(not(target_arch = "wasm32"))]
impl<'send> ChunkReceiverSender<wasmbus_rpc::provider::ProviderTransport<'send>> {
pub fn for_actor(ld: &'send wasmbus_rpc::core::LinkDefinition) -> Self {
Self {
transport: wasmbus_rpc::provider::ProviderTransport::new(ld, None),
}
}
}
#[cfg(target_arch = "wasm32")]
impl ChunkReceiverSender<wasmbus_rpc::actor::prelude::WasmHost> {
pub fn to_actor(actor_id: &str) -> Self {
let transport =
wasmbus_rpc::actor::prelude::WasmHost::to_actor(actor_id.to_string()).unwrap();
Self { transport }
}
}
#[async_trait]
impl<T: Transport + std::marker::Sync + std::marker::Send> ChunkReceiver
for ChunkReceiverSender<T>
{
#[allow(unused)]
async fn receive_chunk(&self, ctx: &Context, arg: &Chunk) -> RpcResult<ChunkResponse> {
let buf = wasmbus_rpc::common::serialize(arg)?;
let resp = self
.transport
.send(
ctx,
Message {
method: "ChunkReceiver.ReceiveChunk",
arg: Cow::Borrowed(&buf),
},
None,
)
.await?;
let value: ChunkResponse = wasmbus_rpc::common::deserialize(&resp)
.map_err(|e| RpcError::Deser(format!("'{}': ChunkResponse", e)))?;
Ok(value)
}
}