Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cln: add JsonConverter for handling enum #225

Merged
merged 2 commits into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build+test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Setup .NET 6
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
dotnet-version: 6.0.303

- name: build project assemblies so that fsdocs can read assemblies and .xml files from bin/ .
run:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup .NET 6
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
dotnet-version: 6.0.303

- name: build project assemblies so that fsdocs can read assemblies and .xml files from bin/ .
run:
Expand Down
6 changes: 3 additions & 3 deletions src/DotNetLightning.ClnRpc/DotNetLightning.ClnRpc.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Compile Include="NewtonsoftJsonConverters.fs" />
<Compile Include="ManuallyDefinedTypes.fs" />
<Compile Include="Requests.fs" />
<Compile Include="SystemTextJsonConverterExtensions.fs" />
<Compile Include="Client.fs" />
<Compile Include="Client.Methods.fs" />
<Compile Include="Plugin/DTOs.fs" />
Expand All @@ -30,14 +31,13 @@
<ProjectReference Include="..\AEZ\AEZ.csproj" PrivateAssets="all" />
<ProjectReference Include="..\Macaroons\Macaroons.csproj" ExcludeAssets="all" />

<ProjectReference Include="..\DotNetLightning.Core\DotNetLightning.Core.fsproj" PrivateAssets="all"/>
<ProjectReference Include="..\DotNetLightning.Core\DotNetLightning.Core.fsproj" PrivateAssets="all" />
</ItemGroup>

<!-- this is a workaround only needed for nuget push (so, not Mono, but just "dotnet nuget"), for more info see
https://github.com/joemphilips/DotNetLightning/issues/14 and https://github.com/joemphilips/DotNetLightning/commit/c98307465f647257df1438beadb4cabc7db757f2
and https://github.com/NuGet/Home/issues/3891 and https://github.com/NuGet/Home/issues/3891#issuecomment-377319939 -->
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences"
Condition="'$(MSBuildRuntimeType)'!='Mono'">
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences" Condition="'$(MSBuildRuntimeType)'!='Mono'">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
Expand Down
22 changes: 22 additions & 0 deletions src/DotNetLightning.ClnRpc/Requests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3105,3 +3105,25 @@ type private Response =
| Ping of Responses.PingResponse
| SignMessage of Responses.SignmessageResponse


open DotNetLightning.ClnRpc.SystemTextJsonConverters
module internal AddJsonConverters =
let addEnumConverters(opts: JsonSerializerOptions) =
opts.Converters.Add(JsonStringEnumConverterEx<Responses.SendpayStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.CloseType>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.ConnectDirection>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.CreateinvoiceStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.DatastoreMode>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.DelinvoiceStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.DelinvoiceStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.SendonionStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.ListsendpaysStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.PayStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.WaitanyinvoiceStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.WaitinvoiceStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.WaitsendpayStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.NewaddrAddresstype>())
opts.Converters.Add(JsonStringEnumConverterEx<Responses.KeysendStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.FeeratesStyle>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.ListforwardsStatus>())
opts.Converters.Add(JsonStringEnumConverterEx<Requests.ListpaysStatus>())
17 changes: 17 additions & 0 deletions src/DotNetLightning.ClnRpc/SystemTextJsonConverterExtensions.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace DotNetLightning.ClnRpc.SystemTextJsonConverters

open System.Text.Json

open System.Runtime.CompilerServices
open NBitcoin

[<Extension; AbstractClass; Sealed>]
type ClnSharpClientHelpers =
[<Extension>]
static member internal AddDNLJsonConverters
(
this: JsonSerializerOptions,
n: Network
) =
this._AddDNLJsonConverters(n)
DotNetLightning.ClnRpc.AddJsonConverters.addEnumConverters(this)
52 changes: 48 additions & 4 deletions src/DotNetLightning.ClnRpc/SystemTextJsonConverters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ type OutPointJsonConverter() =
raise <| JsonException("not a valid txid:output tuple")
else
let o = OutPoint()
o.Hash <- splits.[0] |> uint256.Parse
o.N <- splits.[1] |> uint32
o.Hash <- splits[0] |> uint256.Parse
o.N <- splits[1] |> uint32
o

type FeerateJsonConverter() =
Expand Down Expand Up @@ -154,10 +154,54 @@ type OutputDescriptorJsonConverter(network: Network) =
reader.GetString() |> fun s -> OutputDescriptor.Parse(s, network)


open System.Collections.Generic
open System.Runtime.Serialization
open System.Linq

/// Taken from https://github.com/dotnet/runtime/issues/31081#issuecomment-848697673
type JsonStringEnumConverterEx<'TEnum when 'TEnum: enum<int32> and 'TEnum: equality and 'TEnum: (new:
unit -> 'TEnum) and 'TEnum: struct and 'TEnum :> Enum>() =
inherit JsonConverter<'TEnum>()

let _enumToString = Dictionary<'TEnum, string>()
let _stringToEnum = Dictionary<string, 'TEnum>()

do
let ty = typeof<'TEnum>

for v in Enum.GetValues<'TEnum>() do
let enumMember = ty.GetMember(v.ToString())[0]

let maybeAttr =
enumMember
.GetCustomAttributes(typeof<EnumMemberAttribute>, false)
.Cast<EnumMemberAttribute>()
.FirstOrDefault()
|> Option.ofObj

_stringToEnum.Add(v.ToString(), v)

match maybeAttr with
| Some attr ->
_enumToString.Add(v, attr.Value)
_stringToEnum.Add(attr.Value, v)
| None -> _enumToString.Add(v, v.ToString())

override this.Read(reader, _typeToConvert, _options) =
let stringV = reader.GetString()

match _stringToEnum.TryGetValue stringV with
| true, v -> v
| _ -> Unchecked.defaultof<'TEnum>

override this.Write(writer, value, _options) =
writer.WriteStringValue(_enumToString[value])


[<Extension; AbstractClass; Sealed>]
type ClnSharpClientHelpers =
type internal ClnSharpClientHelpersCore =
[<Extension>]
static member AddDNLJsonConverters
static member internal _AddDNLJsonConverters
(
this: JsonSerializerOptions,
n: Network
Expand Down
26 changes: 26 additions & 0 deletions tests/DotNetLightning.ClnRpc.Tests/SerializerTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ open DotNetLightning.ClnRpc
open DotNetLightning.ClnRpc.Plugin
open DotNetLightning.ClnRpc.NewtonsoftJsonConverters
open DotNetLightning.ClnRpc.Requests
open DotNetLightning.ClnRpc.Responses
open DotNetLightning.ClnRpc.SystemTextJsonConverters
open DotNetLightning.Serialization
open NBitcoin
Expand Down Expand Up @@ -213,3 +214,28 @@ type SerializerTests() =
Assert.Null(jObj.Root.["exclude"])
Assert.Null(jObj.Root.["cltv"])
()

[<Fact>]
member this.SerializeListPays() =
let req =
{
ListpaysRequest.Bolt11 =
"lnbcrt500u1p305fnmpp5vzsjps8uptzedfmrw8jsuw37m4mdlyjjua0qfzceph3a0nz7rtfqdql2djkuepqw3hjqsj5gvsxzerywfjhxuccqzptxqrrsssp5fak5cm2c3r5wtezcflfg6cs3psrp4kczvp4wly66h85y4m4hsrds9qyyssqqxemaw5w9r6hteaxmmhvqe4nkv654nyk88gahjt5mxfjjzkj945xe6frwuavv8u0fzwcst0mvrxj8nxlj3qad9dxgzv8rg9dup3r5kcqnwpqjk"
|> Some
PaymentHash = None
Status = ListpaysStatus.PENDING |> Some
}

let opts = JsonSerializerOptions()

let data1 =
opts.AddDNLJsonConverters(Network.RegTest)
JsonSerializer.SerializeToDocument(req, opts)

Assert.Equal(
"pending",
data1
.RootElement
.GetProperty("status")
.GetString()
)
22 changes: 19 additions & 3 deletions tools/fsharp_msggen/fsharp_msggen/fsharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,30 @@ def write_header(self):
"""
self.write(opens)

def _gen_stj_converter(self, prefix: str, field: EnumField):
self.write(f"opts.Converters.Add(JsonStringEnumConverterEx<{prefix}.{field.typename}>())\n", numindent=2)

def generate_stj_method(self, service: Service):
template = """
open DotNetLightning.ClnRpc.SystemTextJsonConverters
module internal AddJsonConverters =
let addEnumConverters(opts: JsonSerializerOptions) =
"""
self.write(template)
for method in service.methods:
for field in method.request.fields:
if isinstance(field, EnumField):
self._gen_stj_converter("Requests", field)
for field in method.response.fields:
if isinstance(field, EnumField):
self._gen_stj_converter("Responses", field)

def generate(self, service: Service):
self.write_header()
self.generate_requests(service)
self.generate_responses(service)
self.generate_enums(service)

self.generate_stj_method(service)

class FSharpClientExtensionGenerator:
def __init__(self, dest: TextIO):
Expand Down Expand Up @@ -340,8 +358,6 @@ def write_header(self):

"""
self.write(opens)

def generate(self, service: Service):
self.write_header()
self.generate_methods(service)