maybe you have an example for your open api for websocketapp?

Created at 11 Apr 2023, 01:56
JO

jon.slater

Joined 26.01.2023

maybe you have an example for your open api for websocketapp?
11 Apr 2023, 01:56


 hello,

I am an python engineer, and I can already see that ctrader_open_api will work for me. However, I have a problem.

I do not want to use reactor; instead I want like to write a python websocketApp to use your protobuf api.

Therefore I apparently have a problem with SSL. I've spend some time to try to understand the ssl context, specifically the set_ciphers() from ctrader_open_api.

There is some code:

```

def on_open(ws):
    print(f"on_open ws={ws}")

    # Create an instance of ProtoOAApplicationAuthReq
    auth_request = ProtoOAAccountAuthReq()
    # Set the client ID and secret
    auth_request.ctidTraderAccountId = 25928084
    auth_request.accessToken = "97RfUCjLnvqM2-v_HzLwRN_-_hUhCLhhq23xxxxxx"
    auth_request.payloadType = ProtoOAPayloadType.PROTO_OA_ACCOUNT_AUTH_REQ
    # # Serialize the message to a string

    msg = ProtoMessage(payload=auth_request.SerializeToString(),
                       clientMsgId="nothing",
                       payloadType=auth_request.payloadType)
    data = msg.SerializeToString()

    # data = sendall(message=auth_request, clientMsgId="web-socket.py")
    ws.send(data)


host = "wss://demo.ctraderapi.com:5035"

ssl_context = ssl.create_default_context()
ssl_context.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_COMPRESSION | ssl.OP_CIPHER_SERVER_PREFERENCE | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_DH_USE | ssl.OP_SINGLE_ECDH_USE | ssl.OP_NO_TICKET
ssl_context.set_ciphers("TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-CCM8:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-CCM8:DHE-RSA-AES128-CCM:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-CCM8:AES256-CCM:AES128-CCM8:AES128-CCM:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA")

web_socket_app = websocket.WebSocketApp(host,
                                        on_message=on_message,
                                        on_error=on_error,
                                        on_close=on_close,
                                        on_open=on_open)

sslopt = {"ssl_context": ssl_context}
web_socket_app.run_forever(sslopt=sslopt)

```

The problem, as far as I can see, the WebSocketApp becomes closed immediately, I'm not sure why.

this is the output:

```

on_open ws=<websocket._app.WebSocketApp object at 0x7f4f28147620>
++Sent raw: b'\x81\xc1\xd2\x86\x9fn\xda0\x8f|\xe1\x8e)~\xc2\x12\\\xc0\xde\x9c\xb6W\xe5\xd4\xf9;\x91\xec\xd3\x00\xa4\xf7\xd2\\\xff\xf0\xc0&\xa8\xca\xe8<\x9c\xd9\xb21\xba\xd3\xf7-\x9e\xee\xf7\x1f\xe0\xb5\xe7\x16\xaa\xfe\xe7\x16\xc8\x81\xf1\x01\xa6\xee\xf6\x00\xb5'
++Sent decoded: fin=1 opcode=1 data=b'\x08\xb6\x10\x123\x08\xb6\x10\x10\x94\xc3\xae\x0c\x1a)97RfUCjLnvqM2-v_HzLwRN_-_hUhCLhhq23xxxxxx\x1a\x07nothing'
++Rcv raw: b'\x88\x05\x03\xe8Bye'
++Rcv decoded: fin=1 opcode=8 data=b'\x03\xe8Bye'
++Sent raw: b'\x88\x82\x97\xe3\xe2\x12\x94\x0b'
++Sent decoded: fin=1 opcode=8 data=b'\x03\xe8'
on_close ws=<websocket._app.WebSocketApp object at 0x7f4f28147620>, status_code=1000, msg=Bye
sys:1: ResourceWarning: unclosed <ssl.SSLSocket fd=6, family=2, type=1, proto=6, laddr=('192.168.1.192', 41470), raddr=('3.33.208.221', 5035)>
ResourceWarning: Enable tracemalloc to get the object allocation traceback

```

I believe that the ws.send should come from SSL.y send() but does not; ie:

```

    def send(self, buf, flags=0):
        """
        Send data on the connection. NOTE: If you get one of the WantRead,
        WantWrite or WantX509Lookup exceptions on this, you have to call the
        method again with the SAME buffer.

        :param buf: The string, buffer or memoryview to send
        :param flags: (optional) Included for compatibility with the socket
                      API, the value is ignored
        :return: The number of bytes written
        """

I cannot get and data from on_message().

I hope you could help, perhaps even if you have a python SSL websocketapp example for your api?

Kinds regards,

Jon


@jon.slater
Replies

jon.slater
06 May 2023, 01:22 ( Updated at: 06 May 2023, 01:23 )

 

Instead I used a websocket and a http server :

 

    for path, resource in resources.items():
        root.putChild(path, resource)

    reactor.listenTCP(http_port, Site(root))

    factory_set_live = WebSocketServerFactory()
    factory_set_live.protocol = WebSocketProtocol
    set_live_ws_resource = WebSocketResource(factory_set_live)
    root.putChild(b"ws", set_live_ws_resource)
    reactor.listenTCP(websocket_port, factory_set_live)

    print(
        f"listening on ports {http_port} (HTTP) and {websocket_port} (WebSocket).")

    _data.start()

    reactor.run()

 

Reactor is very robust; I never used it before.

I hope this can help somebody else.

 


@jon.slater