feat: add grpc support
This commit is contained in:
@@ -5,10 +5,11 @@ use mcpaas_core::{
|
||||
GeneratedDraftStatus, OperationId, OperationStatus, Protocol, SampleId, Samples, Target,
|
||||
};
|
||||
use mcpaas_mapping::{JsonPathRoot, MappingSet, infer_mapping_from_samples};
|
||||
use mcpaas_proto::{ProtoService, services_from_descriptor_set_bytes};
|
||||
use mcpaas_registry::{
|
||||
CreateVersionRequest, OperationSampleMetadata, OperationSummary, OperationVersionRecord,
|
||||
PostgresRegistry, PublishRequest, RegistryOperation, SampleKind, SaveAuthProfileRequest,
|
||||
SaveSampleMetadataRequest,
|
||||
SaveDescriptorMetadataRequest, SaveSampleMetadataRequest,
|
||||
};
|
||||
use mcpaas_runtime::{PreparedRequest, RuntimeError, RuntimeExecutor, RuntimeOperation};
|
||||
use mcpaas_schema::Schema;
|
||||
@@ -139,6 +140,27 @@ pub struct ImportResponse {
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct DescriptorUploadResponse {
|
||||
pub descriptor_id: String,
|
||||
pub version: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct GrpcServiceSummary {
|
||||
pub package: String,
|
||||
pub service: String,
|
||||
pub methods: Vec<GrpcMethodSummary>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct GrpcMethodSummary {
|
||||
pub name: String,
|
||||
pub kind: String,
|
||||
pub input_schema: Schema,
|
||||
pub output_schema: Schema,
|
||||
}
|
||||
|
||||
impl AdminService {
|
||||
pub fn new(registry: PostgresRegistry, storage_root: PathBuf) -> Self {
|
||||
Self {
|
||||
@@ -345,6 +367,138 @@ impl AdminService {
|
||||
Ok(self.registry.list_auth_profiles().await?)
|
||||
}
|
||||
|
||||
pub async fn upload_descriptor_set(
|
||||
&self,
|
||||
operation_id: &OperationId,
|
||||
source_name: Option<&str>,
|
||||
payload: &[u8],
|
||||
) -> Result<DescriptorUploadResponse, ApiError> {
|
||||
let summary = self.get_operation(operation_id).await?;
|
||||
if summary.protocol != Protocol::Grpc {
|
||||
return Err(ApiError::validation(
|
||||
"descriptor upload is only allowed for grpc operations",
|
||||
));
|
||||
}
|
||||
|
||||
let services = services_from_descriptor_set_bytes(payload)
|
||||
.map_err(|error| ApiError::validation(error.to_string()))?;
|
||||
let descriptor_id = mcpaas_core::DescriptorId::new(new_prefixed_id("desc"));
|
||||
let storage_ref = self
|
||||
.storage
|
||||
.write_descriptor(
|
||||
operation_id,
|
||||
summary.current_draft_version,
|
||||
mcpaas_registry::DescriptorKind::DescriptorSet,
|
||||
&descriptor_id,
|
||||
source_name,
|
||||
payload,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.registry
|
||||
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
||||
descriptor: &mcpaas_registry::DescriptorMetadata {
|
||||
id: descriptor_id.clone(),
|
||||
operation_id: Some(operation_id.clone()),
|
||||
version: Some(summary.current_draft_version),
|
||||
descriptor_kind: mcpaas_registry::DescriptorKind::DescriptorSet,
|
||||
storage_ref,
|
||||
source_name: source_name.map(ToOwned::to_owned),
|
||||
package_index: Some(
|
||||
serde_json::to_value(&services)
|
||||
.map_err(|error| ApiError::internal(error.to_string()))?,
|
||||
),
|
||||
created_at: now_string()?,
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(DescriptorUploadResponse {
|
||||
descriptor_id: descriptor_id.as_str().to_owned(),
|
||||
version: summary.current_draft_version,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn upload_proto_file(
|
||||
&self,
|
||||
operation_id: &OperationId,
|
||||
source_name: Option<&str>,
|
||||
payload: &[u8],
|
||||
) -> Result<DescriptorUploadResponse, ApiError> {
|
||||
let summary = self.get_operation(operation_id).await?;
|
||||
if summary.protocol != Protocol::Grpc {
|
||||
return Err(ApiError::validation(
|
||||
"proto upload is only allowed for grpc operations",
|
||||
));
|
||||
}
|
||||
|
||||
let descriptor_id = mcpaas_core::DescriptorId::new(new_prefixed_id("desc"));
|
||||
let storage_ref = self
|
||||
.storage
|
||||
.write_descriptor(
|
||||
operation_id,
|
||||
summary.current_draft_version,
|
||||
mcpaas_registry::DescriptorKind::ProtoUpload,
|
||||
&descriptor_id,
|
||||
source_name,
|
||||
payload,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.registry
|
||||
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
||||
descriptor: &mcpaas_registry::DescriptorMetadata {
|
||||
id: descriptor_id.clone(),
|
||||
operation_id: Some(operation_id.clone()),
|
||||
version: Some(summary.current_draft_version),
|
||||
descriptor_kind: mcpaas_registry::DescriptorKind::ProtoUpload,
|
||||
storage_ref,
|
||||
source_name: source_name.map(ToOwned::to_owned),
|
||||
package_index: None,
|
||||
created_at: now_string()?,
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(DescriptorUploadResponse {
|
||||
descriptor_id: descriptor_id.as_str().to_owned(),
|
||||
version: summary.current_draft_version,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn list_grpc_services(
|
||||
&self,
|
||||
operation_id: &OperationId,
|
||||
version: Option<u32>,
|
||||
) -> Result<Vec<GrpcServiceSummary>, ApiError> {
|
||||
let summary = self.get_operation(operation_id).await?;
|
||||
if summary.protocol != Protocol::Grpc {
|
||||
return Err(ApiError::validation(
|
||||
"grpc services are only available for grpc operations",
|
||||
));
|
||||
}
|
||||
|
||||
let version = version.unwrap_or(summary.current_draft_version);
|
||||
let descriptor = self
|
||||
.registry
|
||||
.list_descriptor_metadata(operation_id, version)
|
||||
.await?
|
||||
.into_iter()
|
||||
.rev()
|
||||
.find(|descriptor| {
|
||||
descriptor.descriptor_kind == mcpaas_registry::DescriptorKind::DescriptorSet
|
||||
})
|
||||
.ok_or_else(|| ApiError::not_found("descriptor set was not uploaded"))?;
|
||||
let bytes = self.storage.read_bytes(&descriptor.storage_ref).await?;
|
||||
let services = services_from_descriptor_set_bytes(&bytes)
|
||||
.map_err(|error| ApiError::validation(error.to_string()))?;
|
||||
|
||||
services
|
||||
.into_iter()
|
||||
.map(proto_service_summary)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn get_auth_profile(
|
||||
&self,
|
||||
auth_profile_id: &AuthProfileId,
|
||||
@@ -612,6 +766,7 @@ fn build_request_preview(
|
||||
"path": prepared.path_params,
|
||||
"query": prepared.query_params,
|
||||
"headers": prepared.headers,
|
||||
"grpc": prepared.grpc.unwrap_or(Value::Null),
|
||||
"variables": prepared.variables.unwrap_or(Value::Null),
|
||||
"body": prepared.body.unwrap_or(Value::Null)
|
||||
}))
|
||||
@@ -672,3 +827,25 @@ fn now_string() -> Result<String, ApiError> {
|
||||
.format(&Rfc3339)
|
||||
.map_err(|error| ApiError::internal(error.to_string()))
|
||||
}
|
||||
|
||||
fn proto_service_summary(service: ProtoService) -> Result<GrpcServiceSummary, ApiError> {
|
||||
let methods = service
|
||||
.unary_methods()
|
||||
.map(|method| {
|
||||
Ok(GrpcMethodSummary {
|
||||
name: method.name.clone(),
|
||||
kind: "unary".to_owned(),
|
||||
input_schema: mcpaas_proto::message_to_schema(&method.input)
|
||||
.map_err(|error| ApiError::validation(error.to_string()))?,
|
||||
output_schema: mcpaas_proto::message_to_schema(&method.output)
|
||||
.map_err(|error| ApiError::validation(error.to_string()))?,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, ApiError>>()?;
|
||||
|
||||
Ok(GrpcServiceSummary {
|
||||
package: service.package,
|
||||
service: service.name,
|
||||
methods,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user