lores_app_node/stores/
grpc.rs1use std::pin::Pin;
2use std::sync::Arc;
3
4use futures::StreamExt;
5use lores_p2panda_client::{PandaClient, PandaError, PublishResult};
6use tokio::sync::Mutex;
7
8use crate::{
9 stores::{OperationStore, OperationStream, RawOperationEvent, StoreError, StorePublishResult},
10 NodeId, OperationId,
11};
12
13impl From<PandaError> for StoreError {
14 fn from(e: PandaError) -> Self {
15 match e {
16 PandaError::RegionNotBound(msg) => StoreError::RegionNotBound(msg),
17 PandaError::Rpc(s) => StoreError::Other(s.to_string()),
18 }
19 }
20}
21
22pub(crate) struct GrpcOperationStore {
25 client: Arc<Mutex<PandaClient>>,
26 app_id: String,
27 instance_id: String,
28}
29
30impl GrpcOperationStore {
31 pub(crate) fn new(client: Arc<Mutex<PandaClient>>, app_id: impl Into<String>, instance_id: impl Into<String>) -> Self {
32 Self {
33 client,
34 app_id: app_id.into(),
35 instance_id: instance_id.into(),
36 }
37 }
38}
39
40impl OperationStore for GrpcOperationStore {
41 fn publish(
42 &mut self,
43 payload: Vec<u8>,
44 idempotency_key: Option<String>,
45 ) -> Pin<Box<dyn std::future::Future<Output = Result<StorePublishResult, StoreError>> + Send + '_>> {
46 Box::pin(async move {
47 let PublishResult { operation_id, node_id } = self
48 .client
49 .lock()
50 .await
51 .publish(&self.app_id, &self.instance_id, payload, idempotency_key.map(|k| k.into_bytes()))
52 .await
53 .map_err(StoreError::from)?;
54 Ok(StorePublishResult {
55 operation_id: operation_id.into_non_empty().map(OperationId),
56 node_id: node_id.into_non_empty().map(NodeId),
57 })
58 })
59 }
60
61 fn subscribe(&mut self) -> Pin<Box<dyn std::future::Future<Output = Result<OperationStream, StoreError>> + Send + '_>> {
62 Box::pin(async move {
63 let response = self
64 .client
65 .lock()
66 .await
67 .subscribe(&self.app_id, &self.instance_id)
68 .await
69 .map_err(StoreError::from)?;
70
71 let stream: OperationStream = Box::pin(response.into_inner().map(|item| {
72 item.map(|event| RawOperationEvent {
73 payload: event.payload,
74 author: Some(event.author),
75 operation_id: Some(event.operation_id),
76 timestamp: Some(event.timestamp),
77 })
78 .map_err(|s| StoreError::Other(s.to_string()))
79 }));
80
81 Ok(stream)
82 })
83 }
84}