mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
cln-grpc: Add result conversion generator to msggen
This takes the Rust bindings and converts them into the generated protobuf bindings: > JSON-RPC -> Rust bindings -> grpc bindings -> protobuf
This commit is contained in:
parent
4c105d2424
commit
8d3871d791
@ -2,7 +2,9 @@ cln-grpc-wrongdir:
|
||||
$(MAKE) -C .. cln-grpc-all
|
||||
|
||||
CLN_GRPC_EXAMPLES :=
|
||||
CLN_GRPC_GENALL = cln-grpc/proto/node.proto
|
||||
CLN_GRPC_GENALL = cln-grpc/proto/node.proto \
|
||||
cln-grpc/src/convert.rs
|
||||
|
||||
DEFAULT_TARGETS += $(CLN_GRPC_EXAMPLES) $(CLN_GRPC_GENALL)
|
||||
|
||||
$(CLN_GRPC_GENALL): $(JSON_SCHEMA)
|
||||
|
BIN
cln-grpc/src/convert.rs
Normal file
BIN
cln-grpc/src/convert.rs
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
from msggen.model import Method, CompositeField, Service
|
||||
from msggen.grpc import GrpcGenerator
|
||||
from msggen.grpc import GrpcGenerator, GrpcConverterGenerator
|
||||
from msggen.rust import RustGenerator
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
@ -132,6 +132,10 @@ def gengrpc(service):
|
||||
fname = repo_root() / "cln-grpc" / "proto" / "node.proto"
|
||||
dest = open(fname, "w")
|
||||
GrpcGenerator(dest).generate(service)
|
||||
|
||||
fname = repo_root() / "cln-grpc" / "src" / "convert.rs"
|
||||
dest = open(fname, "w")
|
||||
GrpcConverterGenerator(dest).generate(service)
|
||||
def genrustjsonrpc(service):
|
||||
fname = repo_root() / "cln-rpc" / "src" / "model.rs"
|
||||
dest = open(fname, "w")
|
||||
|
@ -151,3 +151,101 @@ class GrpcGenerator:
|
||||
|
||||
for message in [f for f in fields if isinstance(f, CompositeField)]:
|
||||
self.generate_message(message)
|
||||
|
||||
|
||||
class GrpcConverterGenerator:
|
||||
def __init__(self, dest: TextIO):
|
||||
self.dest = dest
|
||||
self.logger = logging.getLogger("msggen.grpc.GrpcConversionGenerator")
|
||||
|
||||
def generate_array(self, prefix, field: ArrayField):
|
||||
if isinstance(field.itemtype, CompositeField):
|
||||
self.generate_composite(prefix, field.itemtype)
|
||||
|
||||
def generate_composite(self, prefix, field: CompositeField):
|
||||
"""Generates the conversions from JSON-RPC to GRPC.
|
||||
"""
|
||||
# First pass: generate any sub-fields before we generate the
|
||||
# top-level field itself.
|
||||
for f in field.fields:
|
||||
if isinstance(f, ArrayField):
|
||||
self.generate_array(prefix, f)
|
||||
|
||||
# And now we can convert the current field:
|
||||
self.write(f"""\
|
||||
#[allow(unused_variables)]
|
||||
impl From<&{prefix}::{field.typename}> for pb::{field.typename} {{
|
||||
fn from(c: &{prefix}::{field.typename}) -> Self {{
|
||||
Self {{
|
||||
""")
|
||||
|
||||
for f in field.fields:
|
||||
name = f.normalized()
|
||||
if isinstance(f, ArrayField):
|
||||
self.write(f"{name}: c.{name}.iter().map(|s| s.into()).collect(),\n", numindent=3)
|
||||
|
||||
elif isinstance(f, EnumField):
|
||||
self.write(f"{name}: c.{name} as i32,\n", numindent=3)
|
||||
|
||||
elif isinstance(f, PrimitiveField):
|
||||
typ = f.typename + ("?" if not f.required else "")
|
||||
# We may need to reduce or increase the size of some
|
||||
# types, or have some conversion such as
|
||||
# hex-decoding. Also includes the `Some()` that grpc
|
||||
# requires for non-native types.
|
||||
rhs = {
|
||||
'u8': f'c.{name}.into()',
|
||||
'u16': f'c.{name}.into()',
|
||||
'u16?': f'c.{name}.map(|v| v.into())',
|
||||
'msat': f'Some(c.{name}.into())',
|
||||
'msat?': f'c.{name}.map(|f| f.into())',
|
||||
'pubkey': f'hex::decode(&c.{name}).unwrap()',
|
||||
'pubkey?': f'c.{name}.as_ref().map(|v| hex::decode(&v).unwrap())',
|
||||
'hex': f'hex::decode(&c.{name}).unwrap()',
|
||||
'hex?': f'c.{name}.as_ref().map(|v| hex::decode(&v).unwrap())',
|
||||
'txid': f'hex::decode(&c.{name}).unwrap()',
|
||||
'txid?': f'c.{name}.as_ref().map(|v| hex::decode(&v).unwrap())',
|
||||
}.get(
|
||||
typ,
|
||||
f'c.{name}.clone()' # default to just assignment
|
||||
)
|
||||
self.write(f"{name}: {rhs},\n", numindent=3)
|
||||
|
||||
self.write(f"""\
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
""")
|
||||
|
||||
def generate_requests(self, service):
|
||||
for meth in service.methods:
|
||||
req = meth.request
|
||||
self.generate_composite("requests", req)
|
||||
|
||||
def generate_responses(self, service):
|
||||
for meth in service.methods:
|
||||
res = meth.response
|
||||
self.generate_composite("responses", res)
|
||||
|
||||
def generate(self, service: Service) -> None:
|
||||
self.write("""
|
||||
// This file was automatically derived from the JSON-RPC schemas in
|
||||
// `doc/schemas`. Do not edit this file manually as it would get
|
||||
// overwritten.
|
||||
|
||||
use std::convert::From;
|
||||
#[allow(unused_imports)]
|
||||
use cln_rpc::model::{responses,requests};
|
||||
use crate::pb;
|
||||
|
||||
""")
|
||||
|
||||
self.generate_responses(service)
|
||||
|
||||
def write(self, text: str, numindent: int = 0) -> None:
|
||||
raw = dedent(text)
|
||||
if numindent > 0:
|
||||
raw = indent(text, " " * numindent)
|
||||
|
||||
self.dest.write(raw)
|
||||
|
Loading…
Reference in New Issue
Block a user