alien_bindings/providers/function/
grpc.rs1use crate::error::{ErrorData, Result};
2use crate::traits::{Binding, Function, FunctionInvokeRequest, FunctionInvokeResponse};
3use alien_error::{Context as _, IntoAlienError as _};
4use async_trait::async_trait;
5use std::collections::BTreeMap;
6use std::fmt::{Debug, Formatter};
7use tonic::transport::Channel;
8
9pub mod proto {
11 tonic::include_proto!("alien_bindings.function");
12}
13
14use proto::{function_service_client::FunctionServiceClient, GetFunctionUrlRequest, InvokeRequest};
15
16pub struct GrpcFunction {
18 client: FunctionServiceClient<Channel>,
19 binding_name: String,
20}
21
22impl Debug for GrpcFunction {
23 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("GrpcFunction")
25 .field("binding_name", &self.binding_name)
26 .finish()
27 }
28}
29
30impl GrpcFunction {
31 pub async fn new(binding_name: String, grpc_endpoint: String) -> Result<Self> {
33 let channel = crate::providers::grpc_provider::create_grpc_channel(grpc_endpoint).await?;
34 Self::new_from_channel(channel, binding_name).await
35 }
36
37 pub async fn new_from_channel(channel: Channel, binding_name: String) -> Result<Self> {
39 let client = FunctionServiceClient::new(channel);
40
41 Ok(Self {
42 client,
43 binding_name,
44 })
45 }
46}
47
48impl Binding for GrpcFunction {}
49
50#[async_trait]
51impl Function for GrpcFunction {
52 async fn invoke(&self, request: FunctionInvokeRequest) -> Result<FunctionInvokeResponse> {
53 let mut client = self.client.clone();
54
55 let grpc_request = tonic::Request::new(InvokeRequest {
56 binding_name: self.binding_name.clone(),
57 target_function: request.target_function,
58 method: request.method,
59 path: request.path,
60 headers: request.headers.into_iter().collect(),
61 body: request.body,
62 timeout_seconds: request.timeout.map(|t| t.as_secs()),
63 });
64
65 let response = client
66 .invoke(grpc_request)
67 .await
68 .into_alien_error()
69 .context(ErrorData::GrpcRequestFailed {
70 service: "FunctionService".to_string(),
71 method: "invoke".to_string(),
72 details: "Failed to invoke function".to_string(),
73 })?;
74
75 let response_inner = response.into_inner();
76 Ok(FunctionInvokeResponse {
77 status: response_inner.status as u16,
78 headers: response_inner
79 .headers
80 .into_iter()
81 .collect::<BTreeMap<_, _>>(),
82 body: response_inner.body,
83 })
84 }
85
86 async fn get_function_url(&self) -> Result<Option<String>> {
87 let mut client = self.client.clone();
88
89 let grpc_request = tonic::Request::new(GetFunctionUrlRequest {
90 binding_name: self.binding_name.clone(),
91 });
92
93 let response = client
94 .get_function_url(grpc_request)
95 .await
96 .into_alien_error()
97 .context(ErrorData::GrpcRequestFailed {
98 service: "FunctionService".to_string(),
99 method: "get_function_url".to_string(),
100 details: "Failed to get function URL".to_string(),
101 })?;
102
103 Ok(response.into_inner().url)
104 }
105
106 fn as_any(&self) -> &dyn std::any::Any {
107 self
108 }
109}