Copied from api_gateway, removed REST handlers (port 8080), added tonic-web + CORS for grpc-web browser access. Binary renamed: api-gateway → api Changes: - Package name: api-gateway → api - Deleted src/handlers/ (REST ML endpoints on port 8080) - Added tonic-web 0.13 + tower-http CORS layer - Server::builder().accept_http1(true) for grpc-web - CORS_ORIGINS env var (default http://localhost:5173) - Metrics server on port 9091 (axum) preserved - All 95 lib tests pass, 0 clippy warnings - Added services/api to workspace members Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
221 lines
6.9 KiB
Rust
221 lines
6.9 KiB
Rust
//! Config Service Proxy - Zero-copy gRPC forwarding for config.ConfigService
|
|
//!
|
|
//! Forwards to trading-service backend (config runs in the same process).
|
|
|
|
use futures::Stream;
|
|
use std::pin::Pin;
|
|
use tonic::{Request, Response, Status};
|
|
use tracing::{error, instrument};
|
|
|
|
use crate::config_backend::config_service_client::ConfigServiceClient;
|
|
use crate::config_backend::config_service_server::ConfigService;
|
|
use crate::config_backend::{
|
|
ConfigChangeEvent, DeleteConfigurationRequest, DeleteConfigurationResponse,
|
|
ExportConfigurationRequest, ExportConfigurationResponse, GetConfigSchemaRequest,
|
|
GetConfigSchemaResponse, GetConfigurationHistoryRequest, GetConfigurationHistoryResponse,
|
|
GetConfigurationRequest, GetConfigurationResponse, ImportConfigurationRequest,
|
|
ImportConfigurationResponse, ListCategoriesRequest, ListCategoriesResponse,
|
|
RollbackConfigurationRequest, RollbackConfigurationResponse, StreamConfigChangesRequest,
|
|
UpdateConfigSchemaRequest, UpdateConfigSchemaResponse, UpdateConfigurationRequest,
|
|
UpdateConfigurationResponse, ValidateConfigurationRequest, ValidateConfigurationResponse,
|
|
};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct ConfigServiceProxy {
|
|
client: ConfigServiceClient<tonic::transport::Channel>,
|
|
}
|
|
|
|
impl ConfigServiceProxy {
|
|
pub fn new(client: ConfigServiceClient<tonic::transport::Channel>) -> Self {
|
|
Self { client }
|
|
}
|
|
}
|
|
|
|
#[tonic::async_trait]
|
|
impl ConfigService for ConfigServiceProxy {
|
|
type StreamConfigChangesStream =
|
|
Pin<Box<dyn Stream<Item = Result<ConfigChangeEvent, Status>> + Send>>;
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn get_configuration(
|
|
&self,
|
|
request: Request<GetConfigurationRequest>,
|
|
) -> Result<Response<GetConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.get_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend GetConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn update_configuration(
|
|
&self,
|
|
request: Request<UpdateConfigurationRequest>,
|
|
) -> Result<Response<UpdateConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.update_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend UpdateConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn delete_configuration(
|
|
&self,
|
|
request: Request<DeleteConfigurationRequest>,
|
|
) -> Result<Response<DeleteConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.delete_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend DeleteConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn list_categories(
|
|
&self,
|
|
request: Request<ListCategoriesRequest>,
|
|
) -> Result<Response<ListCategoriesResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.list_categories(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend ListCategories failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn stream_config_changes(
|
|
&self,
|
|
request: Request<StreamConfigChangesRequest>,
|
|
) -> Result<Response<Self::StreamConfigChangesStream>, Status> {
|
|
let stream = self
|
|
.client
|
|
.clone()
|
|
.stream_config_changes(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend StreamConfigChanges failed: {}", e);
|
|
e
|
|
})?;
|
|
Ok(Response::new(Box::pin(stream.into_inner())))
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn validate_configuration(
|
|
&self,
|
|
request: Request<ValidateConfigurationRequest>,
|
|
) -> Result<Response<ValidateConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.validate_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend ValidateConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn get_configuration_history(
|
|
&self,
|
|
request: Request<GetConfigurationHistoryRequest>,
|
|
) -> Result<Response<GetConfigurationHistoryResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.get_configuration_history(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend GetConfigurationHistory failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn rollback_configuration(
|
|
&self,
|
|
request: Request<RollbackConfigurationRequest>,
|
|
) -> Result<Response<RollbackConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.rollback_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend RollbackConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn export_configuration(
|
|
&self,
|
|
request: Request<ExportConfigurationRequest>,
|
|
) -> Result<Response<ExportConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.export_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend ExportConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn import_configuration(
|
|
&self,
|
|
request: Request<ImportConfigurationRequest>,
|
|
) -> Result<Response<ImportConfigurationResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.import_configuration(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend ImportConfiguration failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn get_config_schema(
|
|
&self,
|
|
request: Request<GetConfigSchemaRequest>,
|
|
) -> Result<Response<GetConfigSchemaResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.get_config_schema(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend GetConfigSchema failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
|
|
#[instrument(skip(self, request), err)]
|
|
async fn update_config_schema(
|
|
&self,
|
|
request: Request<UpdateConfigSchemaRequest>,
|
|
) -> Result<Response<UpdateConfigSchemaResponse>, Status> {
|
|
self.client
|
|
.clone()
|
|
.update_config_schema(request)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Backend UpdateConfigSchema failed: {}", e);
|
|
e
|
|
})
|
|
}
|
|
}
|