Coverage Report

Created: 2025-12-04 08:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/runner/work/lyquor/lyquor/net/rpc/src/client.rs
Line
Count
Source
1
use std::collections::HashSet;
2
3
use super::{Attributes, Method, Service};
4
use crate::{
5
    format_method_name, format_method_path, format_service_name, generate_deprecated, generate_doc_comments,
6
    naive_snake_case,
7
};
8
use proc_macro2::TokenStream;
9
use quote::{format_ident, quote};
10
11
0
pub(crate) fn generate_internal<T: Service>(
12
0
    service: &T, emit_package: bool, proto_path: &str, compile_well_known_types: bool, attributes: &Attributes,
13
0
    disable_comments: &HashSet<String>,
14
0
) -> TokenStream {
15
0
    let service_ident = quote::format_ident!("{}Client", service.name());
16
0
    let client_mod = quote::format_ident!("{}_client", naive_snake_case(service.name()));
17
0
    let methods = generate_methods(
18
0
        service,
19
0
        emit_package,
20
0
        proto_path,
21
0
        compile_well_known_types,
22
0
        disable_comments,
23
    );
24
25
0
    let rpcerr = generate_errors();
26
27
0
    let package = if emit_package { service.package() } else { "" };
28
0
    let service_name = format_service_name(service, emit_package);
29
30
0
    let service_doc = if disable_comments.contains(&service_name) {
31
0
        TokenStream::new()
32
    } else {
33
0
        generate_doc_comments(service.comment())
34
    };
35
36
0
    let mod_attributes = attributes.for_mod(package);
37
0
    let struct_attributes = attributes.for_struct(&service_name);
38
39
0
    quote! {
40
        /// Generated client implementations.
41
        #(#mod_attributes)*
42
        pub mod #client_mod {
43
            #![allow(
44
                unused_variables,
45
                dead_code,
46
                missing_docs,
47
                clippy::wildcard_imports,
48
                // will trigger if compression is disabled
49
                clippy::let_unit_value,
50
            )]
51
52
            use prost::Message;
53
            use http_body_util::{BodyExt, Full};
54
            use lyquor_net_rpc::http as http;
55
            pub use crate::pool::RequestSender;
56
            use thiserror::Error;
57
58
            #rpcerr
59
60
            #service_doc
61
            #(#struct_attributes)*
62
            #[derive(Clone)]
63
            pub struct #service_ident {
64
                sender: RequestSender,
65
            }
66
67
            impl #service_ident
68
            {
69
70
                pub fn new(s: RequestSender) -> Self {
71
                    Self { sender: s }
72
                }
73
74
                #methods
75
            }
76
        }
77
    }
78
0
}
79
80
0
fn generate_errors() -> TokenStream {
81
0
    quote! {
82
83
        #[derive(Debug, Error)]
84
        pub enum RPCError {
85
            #[error("bad request")]
86
            BadRequest,
87
            #[error("bad response")]
88
            BadResponse,
89
            #[error("check service")]
90
            CheckService,
91
            #[error("Transport error")]
92
            TransportErr,
93
            #[error("unknown error")]
94
            Unknown,
95
        }
96
    }
97
0
}
98
99
0
fn generate_methods<T: Service>(
100
0
    service: &T, emit_package: bool, proto_path: &str, compile_well_known_types: bool,
101
0
    disable_comments: &HashSet<String>,
102
0
) -> TokenStream {
103
0
    let mut stream = TokenStream::new();
104
105
0
    for method in service.methods() {
106
0
        if !disable_comments.contains(&format_method_name(service, method, emit_package)) {
107
0
            stream.extend(generate_doc_comments(method.comment()));
108
0
        }
109
0
        if method.deprecated() {
110
0
            stream.extend(generate_deprecated());
111
0
        }
112
0
        let method = generate_unary(service, method, emit_package, proto_path, compile_well_known_types);
113
114
0
        stream.extend(method);
115
    }
116
117
0
    stream
118
0
}
119
120
0
fn generate_unary<T: Service>(
121
0
    service: &T, method: &T::Method, emit_package: bool, proto_path: &str, compile_well_known_types: bool,
122
0
) -> TokenStream {
123
0
    let ident = format_ident!("{}", method.name());
124
0
    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
125
0
    let path = format_method_path(service, method, emit_package);
126
127
0
    quote! {
128
        pub async fn #ident(
129
            &mut self,
130
            request: #request,
131
        ) -> std::result::Result<#response, RPCError> {
132
           let path = http::uri::PathAndQuery::from_static(#path);
133
           let req_builder = http::Request::builder()
134
                .uri(path)
135
                .method("POST")
136
                .header("content-type", "application/grpc")
137
                .header("grpc-accept-encoding", "identity")
138
                .header("grpc-encoding", "identity")
139
                .header("lyquor-pkt-type", "RPC");
140
141
            let req = req_builder.body(Full::from(
142
                request.encode_to_vec()
143
            ));
144
            let req = match req {
145
                Ok(r) => r,
146
                Err(e) => {
147
                    return Err(RPCError::BadRequest)
148
                }
149
            };
150
151
            let resp = self.sender.send_request(req).await;
152
            match resp {
153
                Ok(resp) => {
154
                    let bytes = resp.collect().await;
155
                    match bytes {
156
                        Ok(b) => {
157
                            match #response::decode(b.to_bytes()) {
158
                                Ok(r) => {
159
                                    Ok(r)
160
                                },
161
                                Err(_) => {
162
                                    Err(RPCError::CheckService)
163
                                }
164
                            }
165
                        },
166
                        Err(e) => {
167
                            Err(RPCError::BadResponse)
168
                        }
169
                    }
170
                },
171
                Err(e) => Err(RPCError::TransportErr)
172
            }
173
           //self.inner.unary(req, path, codec).await
174
        }
175
    }
176
0
}