stanvooz
stanvooz

Reputation: 542

How to get data with websocket in a class and instantiate variable

I'm trying to get a websocket connection working in a class, because I need to access the variable self.closeoutside of the class. The problem is that the connection is not established and I also can't access the variable inside on_message

How can I get it to work?

import websocket
import json


class WS:

    def __init__(self):

        self.socket = 'wss://ftx.com/ws/'

    def stream(self):
        self.ws = websocket.WebSocketApp(self.socket,
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close)
        self.ws.run_forever()

    def on_open(self):

        print('connected')

        data = {'op': 'subscribe', 'channel': 'ticker', 'market': 'ETH-PERP'}
        self.ws.send(json.dumps(data))

    def on_close(ws):
        print('disconnected')

    def on_message(self,message):

        json_msg = json.loads(message)
        self.close = json_msg['data']['last']

    def get_data_out(self):

        return self.close
   
    def on_error(ws,error):
        print(error)

Upvotes: 1

Views: 3409

Answers (1)

furas
furas

Reputation: 142794

I tried to run your code

WS().stream()

but it doesn't work for me (even if I add missing on_open=self.on_open)

I found even ftx documentation and its example with also use module websocket but I didn't test it.

But if I use different module websockets (with char s) instead of websocket (without char s) then I can subscribe channel and get values.


Minimal working example

import asyncio
import websockets
import json

async def handler():
    async with websockets.connect('wss://ftx.com/ws/') as ws:
        
        # subscribe
        data = {'op': 'subscribe', 'channel': 'ticker', 'market': 'ETH-PERP'}
        await ws.send(json.dumps(data))

        # get all messages (not only with `update`)
        async for message in ws:
            print(message)

# --- main ---
     
asyncio.get_event_loop().run_until_complete(handler())

To get only last value it needs to filter messages:

        async for message in ws:
            data = json.loads(message)
            if data['type'] == 'update':
                print(data['data']['last'])

But it still need to write more code if you want to use it as class.


BTW:

It seems websocket (without char s) is very old module and last updated was in 2010 and websockets (with char s) was updated in 2021 (few weeks/months ago).

https://pypi.org/project/websocket/

https://pypi.org/project/websockets/


EDIT:

In other question I found command which show more information about connection:

websocket.enableTrace(True)

and this shows errors because functions are executed with more values then you defined.
They have to get websocket as first argument (after self)

You have:

def on_open   (self):
def on_close  (ws):
def on_message(self, message):
def on_error  (ws, error):

but it has to be

def on_open   (self, ws):
def on_close  (self, ws):
def on_message(self, ws, message):
def on_error  (self, ws, error):

You also forgot on_open=self.on_open


Full working code

import websocket
import json

class WS:

    def __init__(self):
        self.socket = 'wss://ftx.com/ws/'
        self.close = None # default value at start

    def stream(self):
        self.ws = websocket.WebSocketApp(
                    self.socket,
                    on_message=self.on_message,
                    on_error=self.on_error,
                    on_close=self.on_close,
                    on_open=self.on_open
                  )

        print('run forever')
        self.ws.run_forever()
        
    def on_open(self, ws):
        print('on_open:', ws)

        data = {'op': 'subscribe', 'channel': 'ticker', 'market': 'ETH-PERP'}
        
        self.ws.send(json.dumps(data))

    def on_close(self, ws):
        print('on_close:', ws)

    def on_message(self, ws, message):
        print('on_message:', ws, message)
        
        data = json.loads(message)

        if data['type'] == 'update':
            self.close = data['data']['last']

    def get_data_out(self):
        return self.close
   
    def on_error(self, ws, error):
        print('on_error:', ws, error)
        
# --- main ---

websocket.enableTrace(True)  # if you want to see more information  
                             # but code works also without this line

WS().stream()

Upvotes: 2

Related Questions