Skip to content

Commit

Permalink
feat(net): implement Event listener (v2) (#691)
Browse files Browse the repository at this point in the history
  • Loading branch information
vobradovich authored Nov 28, 2024
1 parent 8dec37d commit 2b033a4
Show file tree
Hide file tree
Showing 26 changed files with 465 additions and 295 deletions.
21 changes: 10 additions & 11 deletions net/rs/client-gen/src/ctor_generators.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{helpers::*, type_decl_generators::*};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::prelude::*;
use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
Expand All @@ -22,20 +21,21 @@ impl<'a> CtorFactoryGenerator<'a> {
}

pub(crate) fn finalize(self) -> Tokens {
let class_name = format!("{}Factory", self.service_name);
let class_name = &format!("{}Factory", self.service_name);
let remoting = &csharp::import("global::Sails.Remoting.Abstractions.Core", "IRemoting");

quote! {
public interface I$(&class_name)$['\r']
public interface I$class_name$['\r']
{
$(self.interface_tokens)
}
$['\n']
public sealed partial class $(&class_name) : I$(&class_name)$['\r']
{$['\n']
public sealed partial class $class_name : I$class_name$['\r']
{
$['\n']
private readonly $remoting remoting;
$['\n']
public $(&class_name)($remoting remoting)$['\r']
public $class_name($remoting remoting)$['\r']
{
this.remoting = remoting;
}
Expand All @@ -53,13 +53,12 @@ impl<'a> Visitor<'a> for CtorFactoryGenerator<'a> {
}

fn visit_ctor_func(&mut self, func: &'a CtorFunc) {
let func_name_pascal = &func.name().to_case(Case::Pascal);
let func_name = func.name();

self.interface_tokens.push();
self.interface_tokens.append(summary_comment(func.docs()));
self.interface_tokens.push();

let route_bytes = &path_bytes(func.name()).0;
let args = &encoded_fn_args_comma_prefixed(func.params());
let args_with_type = &self.type_generator.fn_params_with_types(func.params());
let void_type = primitive_type_to_dotnet(PrimitiveType::Null);
Expand All @@ -68,14 +67,14 @@ impl<'a> Visitor<'a> for CtorFactoryGenerator<'a> {
let action = &csharp::import("global::Sails.Remoting", "RemotingAction");

quote_in! { self.interface_tokens =>
$activation $func_name_pascal($args_with_type);$['\r']
$activation $func_name($args_with_type);$['\r']
};

quote_in! { self.class_tokens =>
$(inheritdoc())
public $activation $func_name_pascal($args_with_type)
public $activation $func_name($args_with_type)
{
return new $action<$(void_type)>(this.remoting, [$route_bytes]$args);
return new $action<$(void_type)>(this.remoting, nameof($func_name), string.Empty $args);
}
$['\n']
};
Expand Down
68 changes: 22 additions & 46 deletions net/rs/client-gen/src/events_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub(crate) struct EventsGenerator<'a> {
type_generator: TypeDeclGenerator<'a>,
enum_tokens: Tokens,
class_tokens: Tokens,
listener_tokens: Tokens,
event_routes_tokens: Tokens,
}

impl<'a> EventsGenerator<'a> {
Expand All @@ -19,23 +19,21 @@ impl<'a> EventsGenerator<'a> {
type_generator,
enum_tokens: Tokens::new(),
class_tokens: Tokens::new(),
listener_tokens: Tokens::new(),
event_routes_tokens: Tokens::new(),
}
}

pub(crate) fn finalize(self) -> Tokens {
let name = &self.service_name.to_case(Case::Pascal);
let name = self.service_name;
let enum_name = &format!("{}Events", name);
let class_name = &format!("Enum{}Events", name);
let listener_name = &format!("{}Listener", name);

let system_buffer = &csharp::import("global::System", "Buffer");
let core_listener = &csharp::import(
"global::Sails.Remoting.Abstractions.Core",
"IRemotingListener",
);
let service_listener =
&csharp::import("global::Sails.Remoting.Abstractions", "IRemotingListener");
let remoting = &csharp::import("global::Sails.Remoting.Abstractions.Core", "IRemoting");
let task = &csharp::import("global::System.Threading.Tasks", "Task");
let cancellation_token = &csharp::import("global::System.Threading", "CancellationToken");
let listener = &csharp::import("global::Sails.Remoting.Abstractions.Core", "EventListener");
let actor_id_type = primitive_type_to_dotnet(PrimitiveType::ActorId);

quote! {
public enum $enum_name
Expand All @@ -51,46 +49,27 @@ impl<'a> EventsGenerator<'a> {
}
}
$['\n']
public sealed partial class $listener_name : $service_listener<$class_name>
public sealed partial class $listener_name
{
private static readonly byte[][] EventRoutes =
$['\n']
private const string ROUTE = $(quoted(name));
$['\n']
private static readonly string[] EventRoutes =
[
$(self.listener_tokens)
$(self.event_routes_tokens)
];
$['\n']
private readonly $core_listener remoting;
private readonly $remoting remoting;
$['\n']
public $listener_name($core_listener remoting)
public $listener_name($remoting remoting)
{
this.remoting = remoting;
}
$['\n']
public async global::System.Collections.Generic.IAsyncEnumerable<$class_name> ListenAsync([global::System.Runtime.CompilerServices.EnumeratorCancellation] global::System.Threading.CancellationToken cancellationToken = default)
{
await foreach (var bytes in this.remoting.ListenAsync(cancellationToken))
{
byte idx = 0;
foreach (var route in EventRoutes)
{
if (route.Length > bytes.Length)
{
continue;
}
if (route.AsSpan().SequenceEqual(bytes.AsSpan()[..route.Length]))
{
var bytesLength = bytes.Length - route.Length + 1;
var data = new byte[bytesLength];
data[0] = idx;
$system_buffer.BlockCopy(bytes, route.Length, data, 1, bytes.Length - route.Length);

var p = 0;
$class_name ev = new();
ev.Decode(bytes, ref p);
yield return ev;
}
idx++;
}
}
public async $task<$listener<($actor_id_type, $class_name)>> ListenAsync($cancellation_token cancellationToken = default)
{$['\r']
var listener = await this.remoting.ListenAsync(cancellationToken);$['\r']
return listener.ToServiceEventListener<$class_name>(ROUTE, EventRoutes);$['\r']
}
}
$['\n']
Expand All @@ -105,12 +84,9 @@ impl<'a> Visitor<'a> for EventsGenerator<'a> {

fn visit_service_event(&mut self, event: &'a ServiceEvent) {
let name = &self.service_name.to_case(Case::Pascal);
let service_route_bytes = path_bytes(self.service_name).0;
let event_route_bytes = path_bytes(event.name()).0;
let route_bytes = [service_route_bytes, event_route_bytes].join(", ");

quote_in! { self.listener_tokens =>
[$(&route_bytes)],
quote_in! { self.event_routes_tokens =>
$(quoted(event.name())),
};

quote_in! { self.enum_tokens =>
Expand Down
17 changes: 0 additions & 17 deletions net/rs/client-gen/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,8 @@ use genco::{
lang::{csharp::Tokens, Csharp},
tokens::{FormatInto, ItemStr},
};
use parity_scale_codec::Encode;
use sails_idl_parser::ast::FuncParam;

pub(crate) fn path_bytes(path: &str) -> (String, usize) {
if path.is_empty() {
(String::new(), 0)
} else {
let service_path_bytes = path.encode();
let service_path_encoded_length = service_path_bytes.len();
let service_path_bytes = service_path_bytes
.into_iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ");

(service_path_bytes, service_path_encoded_length)
}
}

pub(crate) fn encoded_fn_args_comma_prefixed(params: &[FuncParam]) -> String {
params
.iter()
Expand Down
14 changes: 6 additions & 8 deletions net/rs/client-gen/src/service_generators.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{helpers::*, type_decl_generators::*};
use convert_case::{Case, Casing};
use csharp::Tokens;
use genco::prelude::*;
use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*};
Expand All @@ -23,7 +22,7 @@ impl<'a> ServiceClientGenerator<'a> {
}

pub(crate) fn finalize(self) -> Tokens {
let name = &self.service_name.to_case(Case::Pascal);
let name = &self.service_name;
let remoting = &csharp::import("global::Sails.Remoting.Abstractions.Core", "IRemoting");

quote! {
Expand All @@ -34,6 +33,9 @@ impl<'a> ServiceClientGenerator<'a> {
$['\n']
public sealed partial class $name : I$name$['\r']
{
$['\n']
private const string ROUTE = nameof($name);
$['\n']
private readonly $remoting remoting;
$['\n']
public $name($remoting remoting)
Expand All @@ -55,11 +57,7 @@ impl<'a> Visitor<'a> for ServiceClientGenerator<'a> {
}

fn visit_service_func(&mut self, func: &'a ServiceFunc) {
let func_name_pascal = &func.name().to_case(Case::Pascal);

let service_route_bytes = path_bytes(self.service_name.as_str()).0;
let func_route_bytes = path_bytes(func.name()).0;
let route_bytes = [service_route_bytes, func_route_bytes].join(", ");
let func_name_pascal = func.name();

let args = &encoded_fn_args_comma_prefixed(func.params());
let args_with_type = &self.type_generator.fn_params_with_types(func.params());
Expand All @@ -78,7 +76,7 @@ impl<'a> Visitor<'a> for ServiceClientGenerator<'a> {
$(inheritdoc())
public $return_type<$func_return_type> $func_name_pascal($args_with_type)
{
return new $action<$func_return_type>(this.remoting, [$(&route_bytes)]$args);
return new $action<$func_return_type>(this.remoting, ROUTE, nameof($func_name_pascal) $args);
}
};
}
Expand Down
10 changes: 7 additions & 3 deletions net/rs/client-gen/tests/snapshots/generator__basic_works.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ ICall<global::Substrate.NetApi.Model.Types.Primitive.U8> DoThat(global::Substrat
}

public sealed partial class Basic : IBasic
{ private readonly IRemoting remoting;
{

private const string ROUTE = nameof(Basic);

private readonly IRemoting remoting;

public Basic(IRemoting remoting) { this.remoting = remoting; }

/// <inheritdoc/>
public ICall<global::Substrate.NetApi.Model.Types.Primitive.U16> DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction<global::Substrate.NetApi.Model.Types.Primitive.U16>(this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 105, 115], p1, p2); }
public ICall<global::Substrate.NetApi.Model.Types.Primitive.U16> DoThis(global::Substrate.NetApi.Model.Types.Primitive.U32 p1, MyParam p2) { return new RemotingAction<global::Substrate.NetApi.Model.Types.Primitive.U16>(this.remoting, ROUTE, nameof(DoThis) , p1, p2); }
/// <inheritdoc/>
public ICall<global::Substrate.NetApi.Model.Types.Primitive.U8> DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple<global::Substrate.NetApi.Model.Types.Primitive.U8, global::Substrate.NetApi.Model.Types.Primitive.U32> p1) { return new RemotingAction<global::Substrate.NetApi.Model.Types.Primitive.U8>(this.remoting, [20, 66, 97, 115, 105, 99, 24, 68, 111, 84, 104, 97, 116], p1); } }
public ICall<global::Substrate.NetApi.Model.Types.Primitive.U8> DoThat(global::Substrate.NetApi.Model.Types.Base.BaseTuple<global::Substrate.NetApi.Model.Types.Primitive.U8, global::Substrate.NetApi.Model.Types.Primitive.U32> p1) { return new RemotingAction<global::Substrate.NetApi.Model.Types.Primitive.U8>(this.remoting, ROUTE, nameof(DoThat) , p1); } }

public sealed partial class MyParam : global::Substrate.NetApi.Model.Types.Base.BaseType {
public global::Substrate.NetApi.Model.Types.Primitive.U32 F1 { get; init; } = new();
Expand Down
25 changes: 19 additions & 6 deletions net/rs/client-gen/tests/snapshots/generator__events_works.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ using global::Sails.Remoting.Abstractions;
using global::Sails.Remoting.Abstractions.Core;
using global::System;
using global::System.Collections.Generic;
using global::System.Threading;
using global::System.Threading.Tasks;

#nullable enable

Expand All @@ -20,12 +22,16 @@ public interface IServiceWithEvents
}

public sealed partial class ServiceWithEvents : IServiceWithEvents
{ private readonly IRemoting remoting;
{

private const string ROUTE = nameof(ServiceWithEvents);

private readonly IRemoting remoting;

public ServiceWithEvents(IRemoting remoting) { this.remoting = remoting; }

/// <inheritdoc/>
public ICall<global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU64> DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction<global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU64>(this.remoting, [68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 24, 68, 111, 84, 104, 105, 115], p1, p2); } }
public ICall<global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU64> DoThis(global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 p1, MyParam p2) { return new RemotingAction<global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU64>(this.remoting, ROUTE, nameof(DoThis) , p1, p2); } }

public enum ServiceWithEventsEvents { One,
Two,
Expand All @@ -39,13 +45,20 @@ this.AddTypeDecoder<MyParam>(ServiceWithEventsEvents.Three);
this.AddTypeDecoder<global::Substrate.NetApi.Model.Types.Base.BaseVoid>(ServiceWithEventsEvents.Reset);
} }

public sealed partial class ServiceWithEventsListener : IRemotingListener<EnumServiceWithEventsEvents> { private static readonly byte[][] EventRoutes = [ [68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 12, 79, 110, 101],[68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 12, 84, 119, 111],[68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 20, 84, 104, 114, 101, 101],[68, 83, 101, 114, 118, 105, 99, 101, 87, 105, 116, 104, 69, 118, 101, 110, 116, 115, 20, 82, 101, 115, 101, 116], ];
public sealed partial class ServiceWithEventsListener {

private const string ROUTE = "ServiceWithEvents";

private readonly global::Sails.Remoting.Abstractions.Core.IRemotingListener remoting;
private static readonly string[] EventRoutes = [ "One","Two","Three","Reset", ];

public ServiceWithEventsListener(global::Sails.Remoting.Abstractions.Core.IRemotingListener remoting) { this.remoting = remoting; }
private readonly IRemoting remoting;

public async global::System.Collections.Generic.IAsyncEnumerable<EnumServiceWithEventsEvents> ListenAsync([global::System.Runtime.CompilerServices.EnumeratorCancellation] global::System.Threading.CancellationToken cancellationToken = default) { await foreach (var bytes in this.remoting.ListenAsync(cancellationToken)) { byte idx = 0; foreach (var route in EventRoutes) { if (route.Length > bytes.Length) { continue; } if (route.AsSpan().SequenceEqual(bytes.AsSpan()[..route.Length])) { var bytesLength = bytes.Length - route.Length + 1; var data = new byte[bytesLength]; data[0] = idx; Buffer.BlockCopy(bytes, route.Length, data, 1, bytes.Length - route.Length); var p = 0; EnumServiceWithEventsEvents ev = new(); ev.Decode(bytes, ref p); yield return ev; } idx++; } } } }
public ServiceWithEventsListener(IRemoting remoting) { this.remoting = remoting; }

public async Task<EventListener<(global::Substrate.Gear.Api.Generated.Model.gprimitives.ActorId, EnumServiceWithEventsEvents)>> ListenAsync(CancellationToken cancellationToken = default) {
var listener = await this.remoting.ListenAsync(cancellationToken);
return listener.ToServiceEventListener<EnumServiceWithEventsEvents>(ROUTE, EventRoutes);
} }

public sealed partial class MyParam : global::Substrate.NetApi.Model.Types.Base.BaseType {
public global::Substrate.Gear.Client.NetApi.Model.Types.Primitive.NonZeroU256 F1 { get; init; } = new();
Expand Down
Loading

0 comments on commit 2b033a4

Please sign in to comment.