diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index c5c41f81b..a7c5caa25 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -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(), + } + } +} + diff --git a/contrib/msggen/msggen/__main__.py b/contrib/msggen/msggen/__main__.py index 01585c83a..98747a18b 100644 --- a/contrib/msggen/msggen/__main__.py +++ b/contrib/msggen/msggen/__main__.py @@ -1,5 +1,5 @@ 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 pathlib import Path import subprocess @@ -136,6 +136,9 @@ def gengrpc(service): fname = repo_root() / "cln-grpc" / "src" / "convert.rs" dest = open(fname, "w") GrpcConverterGenerator(dest).generate(service) + GrpcUnconverterGenerator(dest).generate(service) + + def genrustjsonrpc(service): fname = repo_root() / "cln-rpc" / "src" / "model.rs" dest = open(fname, "w") diff --git a/contrib/msggen/msggen/grpc.py b/contrib/msggen/msggen/grpc.py index 54d4976c8..aed92378b 100644 --- a/contrib/msggen/msggen/grpc.py +++ b/contrib/msggen/msggen/grpc.py @@ -249,3 +249,58 @@ class GrpcConverterGenerator: raw = indent(text, " " * numindent) 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"""\ + }} + }} + }} + + """) +