Skip to main content

openstack_keystone_distributed_storage/grpc/
identity_service.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13// SPDX-License-Identifier: Apache-2.0
14use std::sync::Arc;
15
16use tonic::Request;
17use tonic::Response;
18use tonic::Status;
19use tracing::debug;
20
21use crate::pb;
22use crate::protobuf::api::Response as PbResponse;
23use crate::protobuf::api::identity_service_server::IdentityService;
24use crate::types::StateMachineStore;
25use crate::types::*;
26
27/// External API service implementation providing key-value store operations.
28/// This service handles client requests for getting and setting values in the
29/// distributed store.
30///
31/// # Responsibilities
32/// - Ensure consistency through Raft consensus
33///
34/// # Protocol Safety
35/// This service implements the client-facing API and should validate all inputs
36/// before processing them through the Raft consensus protocol.
37pub struct IdentityServiceImpl {
38    /// The Raft node instance for consensus operations
39    raft_node: Raft,
40    /// The state machine store for direct reads
41    state_machine_store: Arc<StateMachineStore>,
42}
43
44impl IdentityServiceImpl {
45    /// Creates a new instance of the API service
46    ///
47    /// # Arguments
48    /// * `raft_node` - The Raft node instance this service will use
49    /// * `state_machine_store` - The state machine store for reading data
50    pub fn new(raft_node: Raft, state_machine_store: Arc<StateMachineStore>) -> Self {
51        Self {
52            raft_node,
53            state_machine_store,
54        }
55    }
56}
57
58#[tonic::async_trait]
59impl IdentityService for IdentityServiceImpl {
60    /// Sets a value for a given key in the distributed store
61    ///
62    /// # Arguments
63    /// * `request` - Contains the key and value to set
64    ///
65    /// # Returns
66    /// * `Ok(Response)` - Success response after the value is set
67    /// * `Err(Status)` - Error status if the set operation fails
68    #[tracing::instrument(level = "trace", skip(self))]
69    async fn set(
70        &self,
71        request: Request<pb::api::SetRequest>,
72    ) -> Result<Response<PbResponse>, Status> {
73        let req = request.into_inner();
74        debug!("Processing set request for key: {}", req.key.clone());
75
76        let res = self
77            .raft_node
78            .client_write(req.clone())
79            .await
80            .map_err(|e| Status::internal(format!("Failed to write to store: {}", e)))?;
81
82        debug!("Successfully set value for key: {}", req.key);
83        Ok(Response::new(res.data))
84    }
85
86    /// Gets a value for a given key from the distributed store
87    ///
88    /// # Arguments
89    /// * `request` - Contains the key to retrieve
90    ///
91    /// # Returns
92    /// * `Ok(Response)` - Success response containing the value
93    /// * `Err(Status)` - Error status if the get operation fails
94    #[tracing::instrument(level = "trace", skip(self))]
95    async fn get(
96        &self,
97        request: Request<pb::api::GetRequest>,
98    ) -> Result<Response<PbResponse>, Status> {
99        let req = request.into_inner();
100        debug!("Processing get request for key: {}", req.key);
101
102        let value = self
103            .state_machine_store
104            .data()
105            .get(&req.key)
106            .map_err(|_| Status::internal(format!("Key not found: {}", req.key)))?
107            .map(|x| String::from_utf8(x.to_vec()))
108            .transpose()
109            .map_err(|e| Status::internal(format!("error while converting the data, {}", e)))?;
110
111        debug!("Successfully retrieved value for key: {}", req.key);
112        Ok(Response::new(PbResponse { value }))
113    }
114}