cln-grpc: Add generation of request conversion

This is taking protobuf requests on one side and converting them into
the JSON-RPC requests.
This commit is contained in:
Christian Decker
2022-01-16 16:12:54 +01:00
parent 8d3871d791
commit 5d6e9d6dae
3 changed files with 131 additions and 1 deletions

View File

@@ -168,3 +168,75 @@ impl From<&responses::CloseResponse> for pb::CloseResponse {
} }
} }
#[allow(unused_variables)]
impl From<&pb::GetinfoRequest> for requests::GetinfoRequest {
fn from(c: &pb::GetinfoRequest) -> Self {
Self {
}
}
}
#[allow(unused_variables)]
impl From<&pb::ListfundsRequest> for requests::ListfundsRequest {
fn from(c: &pb::ListfundsRequest) -> Self {
Self {
spent: c.spent.clone(),
}
}
}
#[allow(unused_variables)]
impl From<&pb::ListchannelsRequest> for requests::ListchannelsRequest {
fn from(c: &pb::ListchannelsRequest) -> Self {
Self {
short_channel_id: c.short_channel_id.clone(),
source: c.source.clone().map(|v| hex::encode(v)),
destination: c.destination.clone().map(|v| hex::encode(v)),
}
}
}
#[allow(unused_variables)]
impl From<&pb::AddgossipRequest> for requests::AddgossipRequest {
fn from(c: &pb::AddgossipRequest) -> Self {
Self {
message: hex::encode(&c.message),
}
}
}
#[allow(unused_variables)]
impl From<&pb::AutocleaninvoiceRequest> for requests::AutocleaninvoiceRequest {
fn from(c: &pb::AutocleaninvoiceRequest) -> Self {
Self {
expired_by: c.expired_by.clone(),
cycle_seconds: c.cycle_seconds.clone(),
}
}
}
#[allow(unused_variables)]
impl From<&pb::CheckmessageRequest> for requests::CheckmessageRequest {
fn from(c: &pb::CheckmessageRequest) -> Self {
Self {
message: c.message.clone(),
zbase: c.zbase.clone(),
pubkey: c.pubkey.clone().map(|v| hex::encode(v)),
}
}
}
#[allow(unused_variables)]
impl From<&pb::CloseRequest> for requests::CloseRequest {
fn from(c: &pb::CloseRequest) -> Self {
Self {
id: hex::encode(&c.id),
unilateraltimeout: c.unilateraltimeout.clone(),
destination: c.destination.clone(),
fee_negotiation_step: c.fee_negotiation_step.clone(),
wrong_funding: c.wrong_funding.clone().map(|v| hex::encode(v)),
force_lease_closed: c.force_lease_closed.clone(),
}
}
}

View File

@@ -1,5 +1,5 @@
from msggen.model import Method, CompositeField, Service from msggen.model import Method, CompositeField, Service
from msggen.grpc import GrpcGenerator, GrpcConverterGenerator from msggen.grpc import GrpcGenerator, GrpcConverterGenerator, GrpcUnconverterGenerator
from msggen.rust import RustGenerator from msggen.rust import RustGenerator
from pathlib import Path from pathlib import Path
import subprocess import subprocess
@@ -136,6 +136,9 @@ def gengrpc(service):
fname = repo_root() / "cln-grpc" / "src" / "convert.rs" fname = repo_root() / "cln-grpc" / "src" / "convert.rs"
dest = open(fname, "w") dest = open(fname, "w")
GrpcConverterGenerator(dest).generate(service) GrpcConverterGenerator(dest).generate(service)
GrpcUnconverterGenerator(dest).generate(service)
def genrustjsonrpc(service): def genrustjsonrpc(service):
fname = repo_root() / "cln-rpc" / "src" / "model.rs" fname = repo_root() / "cln-rpc" / "src" / "model.rs"
dest = open(fname, "w") dest = open(fname, "w")

View File

@@ -249,3 +249,58 @@ class GrpcConverterGenerator:
raw = indent(text, " " * numindent) raw = indent(text, " " * numindent)
self.dest.write(raw) self.dest.write(raw)
class GrpcUnconverterGenerator(GrpcConverterGenerator):
"""Generator to generate the conversions from GRPC to JSON-RPC (for requests).
"""
def generate(self, service: Service):
self.generate_requests(service)
def generate_composite(self, prefix, field: CompositeField) -> None:
# 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<&pb::{field.typename}> for {prefix}::{field.typename} {{
fn from(c: &pb::{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):
raise ValueError("enums from i32 are not implemented yet")
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 = {
'hex': f'hex::encode(&c.{name})',
'txid?': f'c.{name}.clone().map(|v| hex::encode(v))',
'pubkey': f'hex::encode(&c.{name})',
'pubkey?': f'c.{name}.clone().map(|v| hex::encode(v))',
}.get(
typ,
f'c.{name}.clone()' # default to just assignment
)
self.write(f"{name}: {rhs},\n", numindent=3)
self.write(f"""\
}}
}}
}}
""")