LiamMorrow / OrgnalR

SignalR backplane implemented through Orleans
Apache License 2.0
34 stars 7 forks source link

HubContext #30

Closed dgeller-OUHSC closed 1 year ago

dgeller-OUHSC commented 1 year ago

Is there an intention to implement the HubContext (or is there something I'm missing) so that messages can be sent from a grain to a hub?

https://github.com/OrleansContrib/SignalR.Orleans#hub-context

LiamMorrow commented 1 year ago

Yeah there is a mechanism built in which will allow you to send messages to clients and grains. It's not as ergonomic as HubContext but it does work. In your grain, you can inject OrgnalR.Core.Provider.IActorProviderFactory and Orleans.Serialization.Serializer.
You can then get a reference to a group (or user) in a hub by calling:

        actorProviderFactory
            .GetGroupActor("HubName", "groupName")

Sending use that reference to send a message:

actor.AcceptMessageAsync(
                new AnonymousMessage(
                    new HashSet<string>(),
                    new MethodMessage("ClientMethodName", serializer.SerializeToArray(new object[] { clientMethodParam1, clientMethodParam2 }))
                )
            );
dgeller-OUHSC commented 1 year ago

Excellent. I'll give this a shot, thank you!

bbehrens commented 1 year ago

@LiamMorrow Let's think through this situation. It's a core use case for us so potentially for others as well. Would it make sense for us to include an abstraction in OrgnalR akin to HubContext with the same methods so that in my Grain, I can simply take a dependency on IHubContext and the stuff you mentioned is just taken care of for me?

The alternative to me is that anyone that wants to do this creates their own abstraction in their codebase. Your thoughts?

bbehrens commented 1 year ago

@LiamMorrow Hit me up on twitter or email linked in my profile. Would like to arrange a chat offline

LiamMorrow commented 1 year ago

https://github.com/LiamMorrow/OrgnalR/pull/31

I definitely agree that the above method leaves a lot to be desired. I've written up this PR #31 which will hopefully help a bit. It exposes a HubContext through a IHubContextProvider. This can be used to send messages to clients.

It's still not perfect - we only expose the untyped SendAsync method, similar to what you get inside of the Hub when you don't specify a client interface. So if your client has a method SomeMethod(string arg1, int arg2), it is an untyped call:


        await hubContextProvider
            .GetHubContext<IMyHub>()
            .Clients
            .All // can also use Group, or User, or Connection
            .SendAsync("SomeMethod", arg1, arg2);

Note this can be made slightly better by using nameof:

        await hubContextProvider
            .GetHubContext<IMyHub>()
            .Clients
            .All // can also use Group, or User, or Connection
            .SendAsync(nameof(ISomeClient.SomeMethod), arg1, arg2) // arg1 and arg2 are just typed as `object`

I have some preliminary thoughts about how we can get strong typing working, through generated proxy classes which implement the ISomeClient interface either at runtime or through a source generator. But I figure the above gets us 80% of the way in 20% of the time.

LiamMorrow commented 1 year ago

So just to finalize this ticket. I've just merge #33 which allows you to get a fully typed client. I've used the same type client generator that is used internally in signalr, so wasn't that difficult. It's reflection based rather than source generated, but you'll only pay that cost once per client.

Released in 2.1.0

bbehrens commented 1 year ago

Fantastic! Thanks so much for your quick responses! You beat me to the observability lifecycle change for the arbitrary wait. Well done sir! send me an email or text from my profile would like to have offline chat

On Sat, Dec 3, 2022 at 11:28 PM Liam Morrow @.***> wrote:

So just to finalize this ticket. I've just merge #33 https://github.com/LiamMorrow/OrgnalR/pull/33 which allows you to get a fully typed client. I've used the same type client generator that is used internally in signalr, so wasn't that difficult. It's reflection based rather than source generated, but you'll only pay that cost once per client

— Reply to this email directly, view it on GitHub https://github.com/LiamMorrow/OrgnalR/issues/30#issuecomment-1336325944, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAPCR5BLX2AJ6IGRWHBEUTWLQTXDANCNFSM6AAAAAASREKRUU . You are receiving this because you commented.Message ID: @.***>

-- Brandon Behrens 512.659.7171 (c)

LiamMorrow commented 1 year ago

No dramas at all, I've reached out via email :)