Files
komp_ac/client/src/services/grpc_client.rs
2025-09-12 21:25:49 +02:00

299 lines
9.4 KiB
Rust

// src/services/grpc_client.rs
use common::proto::komp_ac::common::Empty;
use common::proto::komp_ac::table_structure::table_structure_service_client::TableStructureServiceClient;
use common::proto::komp_ac::table_structure::{
GetTableStructureRequest, TableStructureResponse,
};
use common::proto::komp_ac::table_definition::{
table_definition_client::TableDefinitionClient,
PostTableDefinitionRequest, ProfileTreeResponse, TableDefinitionResponse,
};
use common::proto::komp_ac::table_script::{
table_script_client::TableScriptClient,
PostTableScriptRequest, TableScriptResponse,
};
use common::proto::komp_ac::tables_data::{
tables_data_client::TablesDataClient,
GetTableDataByPositionRequest,
GetTableDataRequest, // ADD THIS
GetTableDataResponse,
DeleteTableDataRequest, // ADD THIS
DeleteTableDataResponse, // ADD THIS
GetTableDataCountRequest,
PostTableDataRequest, PostTableDataResponse, PutTableDataRequest,
PutTableDataResponse,
};
use crate::search::SearchGrpc;
use common::proto::komp_ac::search::SearchResponse;
use common::proto::komp_ac::table_validation::{
table_validation_service_client::TableValidationServiceClient,
GetTableValidationRequest,
TableValidationResponse,
CountMode as PbCountMode,
FieldValidation as PbFieldValidation,
CharacterLimits as PbCharacterLimits,
};
use anyhow::{Context, Result};
use std::collections::HashMap;
use tonic::transport::{Channel, Endpoint};
use prost_types::Value;
use std::time::Duration;
#[derive(Clone)]
pub struct GrpcClient {
channel: Channel,
table_structure_client: TableStructureServiceClient<Channel>,
table_definition_client: TableDefinitionClient<Channel>,
table_script_client: TableScriptClient<Channel>,
tables_data_client: TablesDataClient<Channel>,
search_client: SearchGrpc,
table_validation_client: TableValidationServiceClient<Channel>,
}
impl GrpcClient {
pub async fn new() -> Result<Self> {
let endpoint = Endpoint::from_static("http://[::1]:50051")
.connect_timeout(Duration::from_secs(5))
.tcp_keepalive(Some(Duration::from_secs(30)))
.keep_alive_while_idle(true)
.http2_keep_alive_interval(Duration::from_secs(15))
.keep_alive_timeout(Duration::from_secs(5));
let channel = endpoint
.connect()
.await
.context("Failed to create gRPC channel")?;
let table_structure_client =
TableStructureServiceClient::new(channel.clone());
let table_definition_client =
TableDefinitionClient::new(channel.clone());
let table_script_client = TableScriptClient::new(channel.clone());
let tables_data_client = TablesDataClient::new(channel.clone());
let search_client = SearchGrpc::new(channel.clone());
let table_validation_client =
TableValidationServiceClient::new(channel.clone());
Ok(Self {
channel,
table_structure_client,
table_definition_client,
table_script_client,
tables_data_client,
search_client,
table_validation_client,
})
}
// Expose the shared channel so other typed clients can reuse it.
pub fn channel(&self) -> Channel {
self.channel.clone()
}
// Fetch validation rules for a table. Absence of a field in response = no validation.
pub async fn get_table_validation(
&mut self,
profile_name: String,
table_name: String,
) -> Result<TableValidationResponse> {
let req = GetTableValidationRequest {
profile_name,
table_name,
};
let resp = self
.table_validation_client
.get_table_validation(tonic::Request::new(req))
.await
.context("gRPC GetTableValidation call failed")?;
Ok(resp.into_inner())
}
pub async fn get_table_structure(
&mut self,
profile_name: String,
table_name: String,
) -> Result<TableStructureResponse> {
let grpc_request = GetTableStructureRequest {
profile_name,
table_name,
};
let request = tonic::Request::new(grpc_request);
let response = self
.table_structure_client
.get_table_structure(request)
.await
.context("gRPC GetTableStructure call failed")?;
Ok(response.into_inner())
}
pub async fn get_profile_tree(
&mut self,
) -> Result<ProfileTreeResponse> {
let request = tonic::Request::new(Empty::default());
let response = self
.table_definition_client
.get_profile_tree(request)
.await
.context("gRPC GetProfileTree call failed")?;
Ok(response.into_inner())
}
pub async fn post_table_definition(
&mut self,
request: PostTableDefinitionRequest,
) -> Result<TableDefinitionResponse> {
let tonic_request = tonic::Request::new(request);
let response = self
.table_definition_client
.post_table_definition(tonic_request)
.await
.context("gRPC PostTableDefinition call failed")?;
Ok(response.into_inner())
}
pub async fn post_table_script(
&mut self,
request: PostTableScriptRequest,
) -> Result<TableScriptResponse> {
let tonic_request = tonic::Request::new(request);
let response = self
.table_script_client
.post_table_script(tonic_request)
.await
.context("gRPC PostTableScript call failed")?;
Ok(response.into_inner())
}
// Existing TablesData methods
pub async fn get_table_data_count(
&mut self,
profile_name: String,
table_name: String,
) -> Result<u64> {
let grpc_request = GetTableDataCountRequest {
profile_name,
table_name,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.get_table_data_count(request)
.await
.context("gRPC GetTableDataCount call failed")?;
Ok(response.into_inner().count as u64)
}
pub async fn get_table_data_by_position(
&mut self,
profile_name: String,
table_name: String,
position: i32,
) -> Result<GetTableDataResponse> {
let grpc_request = GetTableDataByPositionRequest {
profile_name,
table_name,
position,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.get_table_data_by_position(request)
.await
.context("gRPC GetTableDataByPosition call failed")?;
Ok(response.into_inner())
}
// ADD THIS: Missing get_table_data method
pub async fn get_table_data(
&mut self,
profile_name: String,
table_name: String,
id: i64,
) -> Result<GetTableDataResponse> {
let grpc_request = GetTableDataRequest {
profile_name,
table_name,
id,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.get_table_data(request)
.await
.context("gRPC GetTableData call failed")?;
Ok(response.into_inner())
}
// ADD THIS: Missing delete_table_data method
pub async fn delete_table_data(
&mut self,
profile_name: String,
table_name: String,
record_id: i64,
) -> Result<DeleteTableDataResponse> {
let grpc_request = DeleteTableDataRequest {
profile_name,
table_name,
record_id,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.delete_table_data(request)
.await
.context("gRPC DeleteTableData call failed")?;
Ok(response.into_inner())
}
pub async fn post_table_data(
&mut self,
profile_name: String,
table_name: String,
data: HashMap<String, Value>,
) -> Result<PostTableDataResponse> {
let grpc_request = PostTableDataRequest {
profile_name,
table_name,
data,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.post_table_data(request)
.await
.context("gRPC PostTableData call failed")?;
Ok(response.into_inner())
}
pub async fn put_table_data(
&mut self,
profile_name: String,
table_name: String,
id: i64,
data: HashMap<String, Value>,
) -> Result<PutTableDataResponse> {
let grpc_request = PutTableDataRequest {
profile_name,
table_name,
id,
data,
};
let request = tonic::Request::new(grpc_request);
let response = self
.tables_data_client
.put_table_data(request)
.await
.context("gRPC PutTableData call failed")?;
Ok(response.into_inner())
}
pub async fn search_table(
&mut self,
table_name: String,
query: String,
) -> Result<SearchResponse> {
self.search_client.search_table(table_name, query).await
}
}