DEV Community

Cover image for SignalR core python client: A simple Chat Hub Client
Andrés Baamonde Lozano
Andrés Baamonde Lozano

Posted on • Edited on

SignalR core python client: A simple Chat Hub Client

Intro

To end this Sunday I decided to publish a library where I have been working both at work and at home. As soon as i can. I will include additional features to it, such as login (which is already done but not included in the PyPi package).

I have tried to maintain similarities with the other signalR clients. Making implementation easier. Examples will be complatible with the aspnet core chat examples.

Library is based on websocket_client removing this dependency is a decision that i havent chose yet.

Examples

A tiny how to of using the library could be:

hub_connection = HubConnection(server_url)
hub_connection.build()
hub_connection.on("ReceiveMessage", print)
hub_connection.start()
hub_connection.send("SendMessage", [username, message])
hub_connection.stop()
Enter fullscreen mode Exit fullscreen mode

A fully console example, firslty runing a signalR core chat example, host and port must be replaced by yours:

from signalrcore.hub_connection import HubConnection


def input_with_default(input_text, default_value):
    value = input(input_text.format(default_value))
    return default_value if value is None or value.strip() == "" else value


server_url = input_with_default('Enter your server url(default: {0}): ', "ws://localhost:62342/chathub")

username = input_with_default('Enter your username (default: {0}): ', "mandrewcito")

hub_connection = HubConnection(server_url)
hub_connection.build()
hub_connection.on("ReceiveMessage", print)
hub_connection.start()
message = None
# Do login

while message != "exit()":
    message = input(">> ")
    if message is not None and message is not "" and message is not "exit()":
        hub_connection.send("SendMessage", [username, message])
hub_connection.stop()
Enter fullscreen mode Exit fullscreen mode

Future

  • Authentication (implementation is done but it needs a little refactor)
  • Message pack

Links

Github
Pypi

Any feedback about this is welcomed, leave a comment below :).

Top comments (36)

Collapse
 
arthas1888 profile image
Gustavo Adolfo Morales

i have the following error, when I try to send a msg
DEBUG:SignalRCoreClient:Sending message InvocationMessage: invocation_id 3d582dd3-13c6-45a4-a43e-a67067ca409d, target SendMessage, arguments ['ola']
DEBUG:root:{"type": 1, "headers": {}, "target": "SendMessage", "arguments": ["ola"], "invocationId": "3d582dd3-13c6-45a4-a43e-a67067ca409d", "streamIds": null}

DEBUG:SignalRCoreClient:Message received{"type":7,"error":"Connection closed with an error.","allowReconnect":true}
any ideas? thanks

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

have you the same args on your .NET methods?. Same number of agruments and type? 'SendMessage(string message)'

Collapse
 
arthas1888 profile image
Gustavo Adolfo Morales

yes, even I used the same example here docs.microsoft.com/en-us/aspnet/co... with your example chat without auth but I get the same result, so I don't know what could be, the web socket python always close

Thread Thread
 
mandrewcito profile image
Andrés Baamonde Lozano

If you are using that example you need sending 2 parameters ["user", "message"]. Did you try this?¿

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales

yes of course, I did

Thread Thread
 
mandrewcito profile image
Andrés Baamonde Lozano

Can you show SendMessage declaration and the call for hubconnection.send ¿?. That will be helpful

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales

this is the repo github.com/arthas1888/TestSignalRP..., please check it, thanks
attacth image of the error

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales • Edited

I found the error is the next:

Error when processing requests.
System.IO.InvalidDataException: Expected 'streamIds' to be of type Array.
   at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.ParseMessage(ReadOnlySequence`1 input, IInvocationBinder binder)
   at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.TryParseMessage(ReadOnlySequence`1& input, IInvocationBinder binder, HubMessage& message)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.DispatchMessagesAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.RunHubAsync(HubConnectionContext connection)

and only occurs when I send some msg from signalr client python

Thread Thread
 
mandrewcito profile image
Andrés Baamonde Lozano

yes, i just fixed it on version 0.8.1 >.< you can download it! my bad :(

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales

Ohhh thanks so much, on other hand I found another error, when I use reconnect option, and I shut the web app the python script become crazy, open and close the connection and when run the app again is worst

 dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
      Removing connection Dzkn8DxPR9X12-Tnvpt3Rg from the list of connections.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[4]
      Waiting for the application to finish sending data.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[4]
      Waiting for the application to finish sending data.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[2]
      Socket closed.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[2]
      Socket closed.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
      Removing connection n9ouQEgkR-s8-GGeAOqsxQ from the list of connections.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
      Removing connection jk8OfY3v9fcpQnVqfTUKcA from the list of connections.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[4]
      Waiting for the application to finish sending data.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[2]
      Socket closed.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
      Removing connection RM207tkuWjX4QRsFNYJhDQ from the list of connections.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[4]
      Waiting for the application to finish sending data.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[2]
      Socket closed.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
      Removing connection S28Oe86KWmo_2O4KvmJf7A from the list of connections.
Thread Thread
 
mandrewcito profile image
Andrés Baamonde Lozano

hmm, I'll check it later. I have a lot of issues/features pending related to the reconnection. I will code them on the following days.

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales

ok thanks so much

Thread Thread
 
arthas1888 profile image
Gustavo Adolfo Morales

I uploaded a new version of this signalR client including improves in re-connections, please check it and if you look everything good you can update your library, thanks
the link github.com/arthas1888/TestSignalRP...

Collapse
 
samy0392 profile image
Samer Abbas

Great work!
One question, if I want to store the json data coming in through hub_connection.on("ReceiveMessage", print), in a txt file, how would I do that?

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

Yes, you can, 'print' is only the callback function. If you create a function like this:

import uuid
import json
def save_message(msg):
    with open(f"{uuid.uuid4()}.json",'w+') as fh:
        fh.write(json.dumps(msg))
Enter fullscreen mode Exit fullscreen mode

Then you only need to replace 'print' on the callback register function:

hub_connection.on("ReceiveMessage", save_message)
Enter fullscreen mode Exit fullscreen mode

This changes will save data passed trhoung signalr

Collapse
 
ddua123 profile image
ddua123

Getting this error- raise TypeError(f'Object of type {o.class.name} '
f'is not JSON serializable')
E TypeError: Object of type WebSocketService is not JSON serializable
Please let me know how to correct it?

Collapse
 
samy0392 profile image
Samer Abbas

Thank you so much!

Collapse
 
akanaan profile image
a-kanaan

any idea why I am receving handshake error

DEBUG:SignalRCoreClient:-- web socket error --
Handshake status 400 Bad Request
ERROR:SignalRCoreClient:Handshake status 400 Bad Request

server_url = input_with_default('Enter your server url(default: {0}): ', "ws://mypc.domin.com:4500/faces")

'faces' is the hub name
endpoints.MapHub("faces");

without 'faces' it returns OK

thank you

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

Hi,

When you connect to a websocket. Previously, you negotiated the connection at mypc.domin.com:4500/faces/negotiate with a POST request. The response of that request will result a connection id that is passed on querystring of the ws://mypc.domin.com:4500/faces request.

If you are not sure that you are connecting to your hub. Try to override on your hub the following method:

public override async Task OnConnectedAsync ()

Collapse
 
akanaan profile image
a-kanaan

all the time I was testing using IIS hosted hub, but I tested now running from Visual Studio, and I got my python code working fetching the info from the hub. the issue seems related to IIS. when testing again using IIS hub, I am getting again the handshake error

Collapse
 
akanaan profile image
a-kanaan

thank you Andrés Baamonde Lozano for your reply

curl -XPOST mypc.domain.com:4500/faces/negotiate -H 'Content-Length:0'
{"connectionId":"4Qwmg1Q1jsGN-5-gGpmbPw","availableTransports":[{"transport":"ServerSentEvents","transferFormats":["Text"]},{"transport":"LongPolling","transferFormats":["Text","Binary"]}]}

but I am when using the sample code to have python code connected to the Hub I am getting the following error:
DEBUG:SignalRCoreClient:Handler registered started broadcast
DEBUG:SignalRCoreClient:Connection started
DEBUG:root:start url:ws://mypc.domain.com:4500/faces
DEBUG:SignalRCoreClient:-- web socket error --
Handshake status 400 Bad Request
ERROR:SignalRCoreClient:Handshake status 400 Bad Request
DEBUG:SignalRCoreClient:-- web socket close --

any idea please if I have missed something?

Collapse
 
dchoub profile image
Dhwani Choubisa

Hi Team,

I am using python client for websocket connection in my test.
when I try to make websocket connection on my local Kubernetes environment it works fine but the same thing is not working on QA environment, throws handshakeError

Only difference I can see in Developer(asp .Net) code is as below

.withURL(url),
{skipNegotiation: True,
Transport: HttpTransportType. webSocket}

Can you please help me, how can I pass the same parameter in my python code

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

hi!, now at version 0.8.4 you can skip negotiation (included at options dictionary). Take a look to "skip negotiation" section mandrewcito.github.io/signalrcore/

Collapse
 
dchoub profile image
Dhwani Choubisa

Thank you so much!! I really appreciate your effort.
let me test this and will keep you posted.

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

Negotiate at this moment is not skippable, i will think on that option thank you! ( i will ad it to my task list)

Collapse
 
samy0392 profile image
Samer Abbas

I am trying to make a service of this chat example, which will run at boot up using systemd but it fails with import: not found on all the imports in the program.

How can I make it execute as a service?

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

Have you venv? if answer is yes try to execute with full path to your python venv´s interpreter.

Collapse
 
sebastianeberl6 profile image
Sebastian Eberl

Hello! I have the following problem:
On the server side I have defined a hub method -> Subscribe(long[] ids)
I wanted to call this method with hub_connection.send("Subscribe", [2312, 12312])
But json transforming the decimal value automatically into strings, so I defined a new method with Subscribe1(string[] ids) and calling it with hub_connection.send("Subscribe", ["2312", "12312"]) but again the it says: InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked
Do you have any Ideas?

Collapse
 
samy0392 profile image
Samer Abbas

How would I go about reconnecting in case of websocket disconnect?

Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

On disconnect event is only logged, but HubConnection inherits from websocket.WebSocketApp you can search a solution for you problem in this library. Now i have free time to work in library again, so asap i try to fix this issue. Here is an issue related github.com/websocket-client/websoc...

Collapse
 
samy0392 profile image
Samer Abbas

I have looked at the link. The only thing I see is to add run_forever, but you already have that in base_hub_connection.

run_forever seems to work when network cable is disconnected but it only tries to reconnect for approx 1 minute, and it also gives a websocket error after 1 min.

Thread Thread
 
mandrewcito profile image
Andrés Baamonde Lozano

This weekend i was working on it, during this week. I will update library with "ondisconnected" method to configure reconnection. I tried to do that simplest way. I will explain the implementation on a post, to see if someone gives me feedback and improve that feature.

Collapse
 
akanaan profile image
a-kanaan

thank you very much for your effort you put on this.

  1. is it ok to use it for commercial apps?
  2. I noticed that the package does not support https?
Collapse
 
mandrewcito profile image
Andrés Baamonde Lozano

I supports https on the latest version(github.com/mandrewcito/signalrcore...) and yes you can use it! any colaboration is welcomed :D

Collapse
 
akanaan profile image
a-kanaan

thank you Andrés Baamonde Lozano.