sendMessage from outside in autobahn running in separate thread
Asked Answered
C

2

7

I want to call sendMessage method from outside of MyServerProtocol class and send a message to connected clients. I use threading to do this.

When I use this code :

from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory
from twisted.internet import reactor
import threading

class MyServerProtocol(WebSocketServerProtocol):
    def onConnect(self, request):
        print("Client connecting: {0}".format(request.peer))

    def onOpen(self):
        print("WebSocket connection open.")

    def onMessage(self, payload, isBinary):
        if isBinary:
            print("Binary message received: {0} bytes".format(len(payload)))
        else:
            print("Text message received: {0}".format(payload.decode('utf8')))

        self.sendMessage(payload, isBinary)

    def onClose(self, wasClean, code, reason):
        print("WebSocket connection closed: {0}".format(reason))


class Connection(threading.Thread):
    def __init__(self):
        super(Connection, self).__init__()

    def run(self):
        self.factory = WebSocketServerFactory("ws://localhost:9000", debug=False)
        self.factory.protocol = MyServerProtocol
        reactor.listenTCP(9000, self.factory)
        reactor.run(installSignalHandlers=0)

    def send(self, data):
        reactor.callFromThread(self.factory.protocol.sendMessage, self.factory.protocol, data)

connection = Connection()
connection.daemon = True
connection.start()
connection.send('test')

this error happens:

connection.send('test')
reactor.callFromThread(self.factory.protocol.sendMessage, self.factory.protocol, data)
AttributeError: 'Connection' object has no attribute 'factory'

If I try to comment out the line connection.send('test'), this error happens:

TypeError: 'NoneType' object is not iterable

What is the problem with my code ?

Am I doing this the right way? Or is there another way to send message to clients from outside of the protocol class?

Thanks.

Crust answered 1/3, 2015 at 22:10 Comment(2)
Does self.factory exists when you call send ? Try to put a sleep between start() and send() and check. Also, use a debugger.Stiff
Did you ever figure out how to do this? I am having the same problem.Ineluctable
T
6

is [there] another way to send clients message from outside of server class?

I do something like this to send message. I use twisted to run my web app.

import json
from autobahn.twisted.websocket import WebSocketServerProtocol
from twisted.internet import reactor

class MyProtocol(WebSocketServerProtocol):
    connections = list()

    def onConnect(self, request):
        self.connections.append(self)

    def onClose(self, wasClean, code, reason):
        self.connections.remove(self)

    @classmethod
    def broadcast_message(cls, data):
        payload = json.dumps(data, ensure_ascii = False).encode('utf8')
        for c in set(cls.connections):
            reactor.callFromThread(cls.sendMessage, c, payload)


# Somewhere else
MyProtocol.broadcast_message({'greeting': 'Hello world'})

I do not know if it is The Right Way™, but it works well for me.

Toothbrush answered 3/1, 2016 at 4:47 Comment(0)
H
0

add self.factory to your "init(self):" see below:

from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory
    from twisted.internet import reactor
    import threading

    class MyServerProtocol(WebSocketServerProtocol):
        def onConnect(self, request):
            print("Client connecting: {0}".format(request.peer))

        def onOpen(self):
            print("WebSocket connection open.")

        def onMessage(self, payload, isBinary):
            if isBinary:
                print("Binary message received: {0} bytes".format(len(payload)))
            else:
                print("Text message received: {0}".format(payload.decode('utf8')))

            self.sendMessage(payload, isBinary)

        def onClose(self, wasClean, code, reason):
            print("WebSocket connection closed: {0}".format(reason))


    class Connection(threading.Thread):
        def __init__(self,factory):
            super(Connection, self).__init__()
            self.factory=WebSocketServerFactory("ws://localhost:9000", debug=False)
        def run(self):
            self.factory.protocol = MyServerProtocol()
            reactor.listenTCP(9000, self.factory)
            reactor.run(installSignalHandlers=0)

        def send(self, data):
            reactor.callFromThread(self.factory.protocol.sendMessage, self.factory.protocol, data)

    connection = Connection()
    connection.daemon = True
    connection.start()
    connection.send('test')
Highoctane answered 27/3, 2015 at 6:54 Comment(1)
Does this threading handle multiple connections of peers too?Cottonweed

© 2022 - 2024 — McMap. All rights reserved.