I'm trying to set up a WAMP server that can handle session data of individual clients. However this seems more troublesome than initially thought.
Crossbar config:
{
"workers": [
{
"type": "router",
"realms": [
{
"name": "default",
"roles": [
{
"name": "anonymous",
"permissions": [
{
"uri": "*",
"call": true,
"register": true
}
]
}
]
}
],
"transports": [
{
"type": "websocket",
"endpoint": {
"type": "tcp",
"port": 8080
}
}
],
"components": [
{
"type": "class",
"classname": "server.Server",
"realm": "default",
"role": "anonymous"
}
]
}
]
}
server.py:
The server registers two RPCs, one for appending data and one for returning a string of the data. The data is stored as self.data
, but this is storing data for all sessions, not on a per client, per session basis. Once the session dies, the server should clean up the session data. Simply cleaning the list is no solution as simultaneous clients can access each others data.
The id of the client is available in the append
RPC (if the client discloses itself), however this seems fairly useless at this point.
from autobahn.twisted import wamp
from autobahn.wamp import types
class Server(wamp.ApplicationSession):
def __init__(self, *args, **kwargs):
wamp.ApplicationSession.__init__(self, *args, **kwargs)
self.data = []
def onJoin(self, details):
def append(data, details):
client_id = details.caller
self.data.append(data)
def get():
return ''.join(self.data)
options = types.RegisterOptions(details_arg='details')
self.register(append, 'append', options=options)
self.register(get, 'get')
client.py:
The client connects to the server, waits for the connection to open and executes RPCs. The client first appends 'a'
and 'b'
to the server's data, then the data is get and printed. The result should be ab
as data should be stored per client, per session. Once the session dies, the data should be cleaned up.
import asyncio
from autobahn.asyncio import wamp
from autobahn.asyncio import websocket
from autobahn.wamp import types
class Client(wamp.ApplicationSession):
def onOpen(self, protocol):
protocol.session = self
wamp.ApplicationSession.onOpen(self, protocol)
if __name__ == '__main__':
session_factory = wamp.ApplicationSessionFactory()
session_factory.session = Client
transport_factory = websocket.WampWebSocketClientFactory(session_factory)
loop = asyncio.get_event_loop()
transport, protocol = loop.run_until_complete(
asyncio.async(loop.create_connection(
transport_factory, 'localhost', '8080',)))
connected = asyncio.Event()
@asyncio.coroutine
def poll():
session = getattr(protocol, 'session', None)
if not session:
yield from asyncio.sleep(1)
asyncio.ensure_future(poll())
else:
connected.set()
# Wait for session to open.
asyncio.ensure_future(poll())
loop.run_until_complete(connected.wait())
# Client is connected, call RPCs.
options = types.CallOptions(disclose_me=True)
protocol.session.call('append', 'a', options=options)
protocol.session.call('append', 'b', options=options)
f = protocol.session.call('get', options=options)
# Get stored data and print it.
print(loop.run_until_complete(f))
Hope somebody can tell me how I can store data per client, per session in the server's memory.
I managed to create a hack for this. It doesn't seem like the perfect solution, but it works for now.
from autobahn.twisted import wamp
from autobahn.wamp import types
from twisted.internet.defer import inlineCallbacks
class Server(wamp.ApplicationSession):
def __init__(self, *args, **kwargs):
wamp.ApplicationSession.__init__(self, *args, **kwargs)
self.sessions = {}
def onJoin(self, details):
def on_client_join(details):
client_id = details['session']
self.sessions[client_id] = {}
def on_client_leave(client_id):
self.sessions.pop(client_id)
self.subscribe(on_client_join, 'wamp.session.on_join')
self.subscribe(on_client_leave, 'wamp.session.on_leave')
def get_session(details):
return self.sessions[details.caller]
@inlineCallbacks
def append(data, details):
session = yield self.call('get_session', details)
d = session.setdefault('data', [])
d.append(data)
@inlineCallbacks
def get(details):
session = yield self.call('get_session', details)
return ''.join(session['data'])
reg_options = types.RegisterOptions(details_arg='details')
self.register(get_session, 'get_session')
self.register(append, 'append', options=reg_options)
self.register(get, 'get', options=reg_options)
As session gets created when a client connects (on_client_join
), and the session gets destroyed when a client disconnects (on_client_leave
).
The server also needs permission to subscribe to the meta events. config.json:
...
"permissions": [
{
"uri": "*",
"call": true,
"register": true,
"subscribe": true,
}
]
....