kuska-ssb/src/api/helper.rs

385 lines
11 KiB
Rust

use crate::{
api::dto::content::{
FriendsHops, InviteCreateOptions, RelationshipQuery, SubsetQuery, SubsetQueryOptions,
TypedMessage,
},
feed::Message,
rpc::{ArgType, Body, BodyType, RequestNo, RpcType, RpcWriter},
};
use async_std::io::Write;
use super::{dto, error::Result};
const MAX_RPC_BODY_LEN: usize = 65536;
#[derive(Debug)]
pub enum ApiMethod {
InviteCreate,
InviteUse,
FriendsIsFollowing,
FriendsIsBlocking,
FriendsHops,
GetSubset,
Publish,
WhoAmI,
Get,
CreateHistoryStream,
CreateFeedStream,
Latest,
BlobsGet,
BlobsCreateWants,
}
impl ApiMethod {
pub fn selector(&self) -> &'static [&'static str] {
use ApiMethod::*;
match self {
InviteCreate => &["invite", "create"],
InviteUse => &["invite", "use"],
FriendsIsFollowing => &["friends", "isFollowing"],
FriendsIsBlocking => &["friends", "isBlocking"],
FriendsHops => &["friends", "hops"],
GetSubset => &["partialReplication", "getSubset"],
Publish => &["publish"],
WhoAmI => &["whoami"],
Get => &["get"],
CreateHistoryStream => &["createHistoryStream"],
CreateFeedStream => &["createFeedStream"],
Latest => &["latest"],
BlobsGet => &["blobs", "get"],
BlobsCreateWants => &["blobs", "createWants"],
}
}
pub fn from_selector(s: &[&str]) -> Option<Self> {
use ApiMethod::*;
match s {
["invite", "create"] => Some(InviteCreate),
["invite", "use"] => Some(InviteUse),
["friends", "isFollowing"] => Some(FriendsIsFollowing),
["friends", "isBlocking"] => Some(FriendsIsBlocking),
["friends", "hops"] => Some(FriendsHops),
["partialReplication", "getSubset"] => Some(GetSubset),
["publish"] => Some(Publish),
["whoami"] => Some(WhoAmI),
["get"] => Some(Get),
["createHistoryStream"] => Some(CreateHistoryStream),
["createFeedStream"] => Some(CreateFeedStream),
["latest"] => Some(Latest),
["blobs", "get"] => Some(BlobsGet),
["blobs", "createWants"] => Some(BlobsCreateWants),
_ => None,
}
}
pub fn from_rpc_body(body: &Body) -> Option<Self> {
let selector = body.name.iter().map(|v| v.as_str()).collect::<Vec<_>>();
Self::from_selector(&selector)
}
}
pub struct ApiCaller<W: Write + Unpin> {
rpc: RpcWriter<W>,
}
impl<W: Write + Unpin> ApiCaller<W> {
pub fn new(rpc: RpcWriter<W>) -> Self {
Self { rpc }
}
pub fn rpc(&mut self) -> &mut RpcWriter<W> {
&mut self.rpc
}
/// Send ["invite", "create"] request.
pub async fn invite_create_req_send(&mut self, uses: u16) -> Result<RequestNo> {
let args = InviteCreateOptions { uses };
let req_no = self
.rpc
.send_request(
ApiMethod::InviteCreate.selector(),
RpcType::Async,
ArgType::Object,
&args,
// specify None value for `opts`
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["invite", "use"] request.
pub async fn invite_use_req_send(&mut self, invite_code: &str) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::InviteUse.selector(),
RpcType::Async,
ArgType::Array,
&invite_code,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["friends", "isFollowing"] request.
pub async fn friends_is_following_req_send(
&mut self,
args: RelationshipQuery,
) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::FriendsIsFollowing.selector(),
RpcType::Async,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["friends", "isBlocking"] request.
pub async fn friends_is_blocking_req_send(
&mut self,
args: RelationshipQuery,
) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::FriendsIsBlocking.selector(),
RpcType::Async,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["friends", "hops"] request
pub async fn friends_hops_req_send(&mut self, args: FriendsHops) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::FriendsHops.selector(),
RpcType::Source,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["partialReplication", "getSubset"] request.
pub async fn getsubset_req_send(
&mut self,
query: SubsetQuery,
opts: Option<SubsetQueryOptions>,
) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::GetSubset.selector(),
RpcType::Source,
ArgType::Tuple,
&query,
&opts,
)
.await?;
Ok(req_no)
}
/// Send ["publish"] request.
pub async fn publish_req_send(&mut self, msg: TypedMessage) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::Publish.selector(),
RpcType::Async,
ArgType::Array,
&msg,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["publish"] response.
pub async fn publish_res_send(&mut self, req_no: RequestNo, msg_ref: String) -> Result<()> {
Ok(self
.rpc
.send_response(req_no, RpcType::Async, BodyType::JSON, msg_ref.as_bytes())
.await?)
}
/// Send ["whoami"] request.
pub async fn whoami_req_send(&mut self) -> Result<RequestNo> {
let args: [&str; 0] = [];
let req_no = self
.rpc
.send_request(
ApiMethod::WhoAmI.selector(),
RpcType::Async,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["whoami"] response.
pub async fn whoami_res_send(&mut self, req_no: RequestNo, id: String) -> Result<()> {
let body = serde_json::to_string(&dto::WhoAmIOut { id })?;
Ok(self
.rpc
.send_response(req_no, RpcType::Async, BodyType::JSON, body.as_bytes())
.await?)
}
/// Send ["get"] request.
pub async fn get_req_send(&mut self, msg_id: &str) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::Get.selector(),
RpcType::Async,
ArgType::Array,
&msg_id,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["get"] response.
pub async fn get_res_send(&mut self, req_no: RequestNo, msg: &Message) -> Result<()> {
self.rpc
.send_response(
req_no,
RpcType::Async,
BodyType::JSON,
msg.to_string().as_bytes(),
)
.await?;
Ok(())
}
/// Send ["createHistoryStream"] request.
pub async fn create_history_stream_req_send(
&mut self,
args: &dto::CreateHistoryStreamIn,
) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::CreateHistoryStream.selector(),
RpcType::Source,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["createFeedStream"] request.
pub async fn create_feed_stream_req_send<'a>(
&mut self,
args: &dto::CreateStreamIn<u64>,
) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::CreateFeedStream.selector(),
RpcType::Source,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["latest"] request.
pub async fn latest_req_send(&mut self) -> Result<RequestNo> {
let args: [&str; 0] = [];
let req_no = self
.rpc
.send_request(
ApiMethod::Latest.selector(),
RpcType::Async,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send ["blobs","get"] request.
pub async fn blobs_get_req_send(&mut self, args: &dto::BlobsGetIn) -> Result<RequestNo> {
let req_no = self
.rpc
.send_request(
ApiMethod::BlobsGet.selector(),
RpcType::Source,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send feed response
pub async fn feed_res_send(&mut self, req_no: RequestNo, feed: &str) -> Result<()> {
self.rpc
.send_response(req_no, RpcType::Source, BodyType::JSON, feed.as_bytes())
.await?;
Ok(())
}
/// Send blob create wants
pub async fn blob_create_wants_req_send(&mut self) -> Result<RequestNo> {
let args: [&str; 0] = [];
let req_no = self
.rpc
.send_request(
ApiMethod::BlobsCreateWants.selector(),
RpcType::Source,
ArgType::Array,
&args,
&None::<()>,
)
.await?;
Ok(req_no)
}
/// Send blob response
pub async fn blobs_get_res_send<D: AsRef<[u8]>>(
&mut self,
req_no: RequestNo,
data: D,
) -> Result<()> {
let mut offset = 0;
let data = data.as_ref();
while offset < data.len() {
let limit = std::cmp::min(data.len(), offset + MAX_RPC_BODY_LEN);
self.rpc
.send_response(
req_no,
RpcType::Source,
BodyType::Binary,
&data[offset..limit],
)
.await?;
offset += MAX_RPC_BODY_LEN;
}
self.rpc.send_stream_eof(req_no).await?;
Ok(())
}
}