First of all the Autobahn project offers an Open-Source implementation of the communication protocol WAMP.
WAMP offers the two communication pattern RPC (Remote-Procedure-Call) and PUBSUB (Publish-Subscribe). So in your case it is necessary to figure out which of the two pattern fits your needs.
RPC
According to the WAMP FAQ RPC the RPC involves three Roles. These are:
In your case, the Callee is the server whereas the Caller (Client) calls a method on the server. This is what apparently works for you. (A return value can be send to the Callee/client). The dealer is responsible for the routing and can be ignored at the moment. So considering the above pattern it seems to be not fitting for your problem.
PUBSUB
The second pattern is PUBSUB. This pattern consists of the three roles (taken from WAMP FAQ PUBSUB):
- Publisher
- Subscriber
- Broker
So what happens is, that the Publisher (Server) publishes events to topics. A Subscriber (Client) can subscribe to a topic of the Publisher. Once an event is published the Subscriber receives the event including the payload. That means that you could offer a topic "Broadcast" and let all clients subscribe to the topic. If required you can send a broadcast message to all clients.
Then you have to deal with the problem of sending a message to single clients (Subscribers). According to the documentation, the publish function for publishing a topic has an optional parameter to give a list of "Clients" that are eligible to receive the event. WAMP Documentation (Class Publish)
--------EDIT--------
It is not clear what is meant by the "external application" and in what language it is supposed to be written. The explained problem by the Author can be solved if the external application is either written in python, JavaScript or Cpp or an Android App using the Autobahn framework with (WAMP).
Autobahn offers, as mentioned in the question, also a websocket protocol implementation. Another approach to solve the problem could be by using Autobahn Websockets and for the "external Application" a Websocket implementation of choice. Autobahn offers for Python and Android Websocket solutions. Of course there are more Websocket libraries or modules available. Java Websocket library, Python Websocket Client module and more...
So lets say the Websocket Server is implemented using the Autobahn framework. The external application is another client connecting to the server and sending a defined string starting with "send_broadcast:PAYLOAD" and the payload appended. On the server you could check the message for the string and if the msg starts with "send_broadcast" you can then send the broadcast to all connected clients. If you want to send the msg to just one client you can define another string like "send_to_single:IP:PAYLOAD" for example. The server implementation could then have another elif branch that checks for the "send_to_single" and call another method, maybe "def send_to_single"?, and pass another argument given the ip of the client. Instead of sending to all clients ,as in the broadcast method, you could send the msg only to the given client. Another way for your own communication protocol would be using JSON.
you could define your msg as follows:
{
"type": "broadcast",
"msg": "your_message"
}
or
{
"type": "single",
"elegible": ["IP_1", "???"],
"msg": "your_message"
}
On the Server you then load the Payload, check the type and do the further steps.
Server
import sys
from twisted.internet import reactor
from twisted.python import log
from twisted.web.server import Site
from twisted.web.static import File
from autobahn.twisted.websocket import WebSocketServerFactory, \
WebSocketServerProtocol, \
listenWS
class BroadcastServerProtocol(WebSocketServerProtocol):
def onOpen(self):
self.factory.register(self)
def onConnect(self, request):
print("Client connecting: {}".format(request.peer))
def onMessage(self, payload, isBinary):
if not isBinary:
if "send_broadcast" in payload.decode('utf8'):
msg = "Send broadcast was ordered"
self.factory.broadcast(msg)
def connectionLost(self, reason):
WebSocketServerProtocol.connectionLost(self, reason)
self.factory.unregister(self)
class BroadcastServerFactory(WebSocketServerFactory):
"""
Simple broadcast server broadcasting any message it receives to all
currently connected clients.
"""
def __init__(self, url, debug=False, debugCodePaths=False):
WebSocketServerFactory.__init__(self, url, debug=debug, debugCodePaths=debugCodePaths)
self.clients = []
self.tickcount = 0
self.tick()
def tick(self):
self.tickcount += 1
self.broadcast("tick %d from server" % self.tickcount)
reactor.callLater(1, self.tick)
def register(self, client):
if client not in self.clients:
print("registered client {}".format(client.peer))
self.clients.append(client)
def unregister(self, client):
if client in self.clients:
print("unregistered client {}".format(client.peer))
self.clients.remove(client)
def broadcast(self, msg):
print("broadcasting message '{}' ..".format(msg))
for c in self.clients:
c.sendMessage(msg.encode('utf8'))
print("message sent to {}".format(c.peer))
class BroadcastPreparedServerFactory(BroadcastServerFactory):
"""
Functionally same as above, but optimized broadcast using
prepareMessage and sendPreparedMessage.
"""
def broadcast(self, msg):
print("broadcasting prepared message '{}' ..".format(msg))
preparedMsg = self.prepareMessage(msg)
for c in self.clients:
c.sendPreparedMessage(preparedMsg)
print("prepared message sent to {}".format(c.peer))
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'debug':
log.startLogging(sys.stdout)
debug = True
else:
debug = False
ServerFactory = BroadcastServerFactory
# ServerFactory = BroadcastPreparedServerFactory
factory = ServerFactory("ws://localhost:9000",
debug=debug,
debugCodePaths=debug)
factory.protocol = BroadcastServerProtocol
factory.setProtocolOptions(allowHixie76=True)
listenWS(factory)
webdir = File(".")
web = Site(webdir)
reactor.listenTCP(8080, web)
reactor.run()
Client
The client is written as well in Python using a different module implementation and still works. It is of course neccessary to comunicate with a Websocket Server using the Websocket protocol.
from websocket import create_connection
ws = create_connection("ws://localhost:9000")
print "Sending 'send_broadcast'..."
ws.send("send_broadcast:PAYLOAD")
print "Sent"
print "Reeiving..." # OPTIONAL
result = ws.recv() # OPTIONAL
print "Received '%s'" % result # OPTIONAL
ws.close(
)