mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-11 01:27:58 +01:00
cln-grpc: Generate server dispatcher
The server doesn't do much more than unwrapping the request from its grpc envelope, convert it into the matching JSON-RPC binding struct, initiate the RPC connection (until we have connection pooling), and then forwards the converted request. The inverse then happens for the result.
This commit is contained in:
parent
5d6e9d6dae
commit
62dc078271
4 changed files with 319 additions and 2 deletions
|
@ -3,7 +3,8 @@ cln-grpc-wrongdir:
|
|||
|
||||
CLN_GRPC_EXAMPLES :=
|
||||
CLN_GRPC_GENALL = cln-grpc/proto/node.proto \
|
||||
cln-grpc/src/convert.rs
|
||||
cln-grpc/src/convert.rs \
|
||||
cln-grpc/src/server.rs
|
||||
|
||||
DEFAULT_TARGETS += $(CLN_GRPC_EXAMPLES) $(CLN_GRPC_GENALL)
|
||||
|
||||
|
|
240
cln-grpc/src/server.rs
Normal file
240
cln-grpc/src/server.rs
Normal file
|
@ -0,0 +1,240 @@
|
|||
use crate::pb::node_server::Node;
|
||||
use crate::pb;
|
||||
use cln_rpc::{Request, Response, ClnRpc};
|
||||
use anyhow::Result;
|
||||
use std::path::{Path, PathBuf};
|
||||
use cln_rpc::model::requests;
|
||||
use log::debug;
|
||||
use crate::convert::*;
|
||||
use tonic::{Code, Status};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Server
|
||||
{
|
||||
rpc_path: PathBuf,
|
||||
}
|
||||
|
||||
impl Server
|
||||
{
|
||||
pub async fn new(path: &Path) -> Result<Self>
|
||||
{
|
||||
Ok(Self {
|
||||
rpc_path: path.to_path_buf(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Node for Server
|
||||
{
|
||||
async fn getinfo(
|
||||
&self,
|
||||
request: tonic::Request<pb::GetinfoRequest>,
|
||||
) -> Result<tonic::Response<pb::GetinfoResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::GetinfoRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::Getinfo(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method Getinfo: {:?}", e)))?;
|
||||
match result {
|
||||
Response::Getinfo(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call Getinfo",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn list_funds(
|
||||
&self,
|
||||
request: tonic::Request<pb::ListfundsRequest>,
|
||||
) -> Result<tonic::Response<pb::ListfundsResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::ListfundsRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::ListFunds(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method ListFunds: {:?}", e)))?;
|
||||
match result {
|
||||
Response::ListFunds(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call ListFunds",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn list_channels(
|
||||
&self,
|
||||
request: tonic::Request<pb::ListchannelsRequest>,
|
||||
) -> Result<tonic::Response<pb::ListchannelsResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::ListchannelsRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::ListChannels(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method ListChannels: {:?}", e)))?;
|
||||
match result {
|
||||
Response::ListChannels(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call ListChannels",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn add_gossip(
|
||||
&self,
|
||||
request: tonic::Request<pb::AddgossipRequest>,
|
||||
) -> Result<tonic::Response<pb::AddgossipResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::AddgossipRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::AddGossip(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method AddGossip: {:?}", e)))?;
|
||||
match result {
|
||||
Response::AddGossip(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call AddGossip",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn auto_clean_invoice(
|
||||
&self,
|
||||
request: tonic::Request<pb::AutocleaninvoiceRequest>,
|
||||
) -> Result<tonic::Response<pb::AutocleaninvoiceResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::AutocleaninvoiceRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::AutoCleanInvoice(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method AutoCleanInvoice: {:?}", e)))?;
|
||||
match result {
|
||||
Response::AutoCleanInvoice(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call AutoCleanInvoice",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn check_message(
|
||||
&self,
|
||||
request: tonic::Request<pb::CheckmessageRequest>,
|
||||
) -> Result<tonic::Response<pb::CheckmessageResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::CheckmessageRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::CheckMessage(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method CheckMessage: {:?}", e)))?;
|
||||
match result {
|
||||
Response::CheckMessage(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call CheckMessage",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn close(
|
||||
&self,
|
||||
request: tonic::Request<pb::CloseRequest>,
|
||||
) -> Result<tonic::Response<pb::CloseResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
let req: requests::CloseRequest = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::Close(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method Close: {:?}", e)))?;
|
||||
match result {
|
||||
Response::Close(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {:?} to method call Close",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
from msggen.model import Method, CompositeField, Service
|
||||
from msggen.grpc import GrpcGenerator, GrpcConverterGenerator, GrpcUnconverterGenerator
|
||||
from msggen.grpc import GrpcGenerator, GrpcConverterGenerator, GrpcUnconverterGenerator, GrpcServerGenerator
|
||||
from msggen.rust import RustGenerator
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
@ -138,6 +138,10 @@ def gengrpc(service):
|
|||
GrpcConverterGenerator(dest).generate(service)
|
||||
GrpcUnconverterGenerator(dest).generate(service)
|
||||
|
||||
fname = repo_root() / "cln-grpc" / "src" / "server.rs"
|
||||
dest = open(fname, "w")
|
||||
GrpcServerGenerator(dest).generate(service)
|
||||
|
||||
|
||||
def genrustjsonrpc(service):
|
||||
fname = repo_root() / "cln-rpc" / "src" / "model.rs"
|
||||
|
|
|
@ -304,3 +304,75 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
|
|||
|
||||
""")
|
||||
|
||||
|
||||
class GrpcServerGenerator(GrpcConverterGenerator):
|
||||
def generate(self, service: Service) -> None:
|
||||
self.write(f"""\
|
||||
use crate::pb::node_server::Node;
|
||||
use crate::pb;
|
||||
use cln_rpc::{{Request, Response, ClnRpc}};
|
||||
use anyhow::Result;
|
||||
use std::path::{{Path, PathBuf}};
|
||||
use cln_rpc::model::requests;
|
||||
use log::debug;
|
||||
use crate::convert::*;
|
||||
use tonic::{{Code, Status}};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Server
|
||||
{{
|
||||
rpc_path: PathBuf,
|
||||
}}
|
||||
|
||||
impl Server
|
||||
{{
|
||||
pub async fn new(path: &Path) -> Result<Self>
|
||||
{{
|
||||
Ok(Self {{
|
||||
rpc_path: path.to_path_buf(),
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Node for Server
|
||||
{{
|
||||
""")
|
||||
|
||||
for method in service.methods:
|
||||
# Tonic will convert to snake-case, so we have to do it here too
|
||||
name = re.sub(r'(?<!^)(?=[A-Z])', '_', method.name).lower()
|
||||
self.write(f"""\
|
||||
async fn {name}(
|
||||
&self,
|
||||
request: tonic::Request<pb::{method.request.typename}>,
|
||||
) -> Result<tonic::Response<pb::{method.response.typename}>, tonic::Status> {{
|
||||
let req = request.into_inner();
|
||||
let req: requests::{method.request.typename} = (&req).into();
|
||||
debug!("Client asked for getinfo");
|
||||
let mut rpc = ClnRpc::new(&self.rpc_path)
|
||||
.await
|
||||
.map_err(|e| Status::new(Code::Internal, e.to_string()))?;
|
||||
let result = rpc.call(Request::{method.name}(req))
|
||||
.await
|
||||
.map_err(|e| Status::new(
|
||||
Code::Unknown,
|
||||
format!("Error calling method {method.name}: {{:?}}", e)))?;
|
||||
match result {{
|
||||
Response::{method.name}(r) => Ok(
|
||||
tonic::Response::new((&r).into())
|
||||
),
|
||||
r => Err(Status::new(
|
||||
Code::Internal,
|
||||
format!(
|
||||
"Unexpected result {{:?}} to method call {method.name}",
|
||||
r
|
||||
)
|
||||
)),
|
||||
}}
|
||||
|
||||
}}\n\n""", numindent=0)
|
||||
|
||||
self.write(f"""\
|
||||
}}
|
||||
""", numindent=0)
|
||||
|
|
Loading…
Add table
Reference in a new issue