Uh oh!
There was an error while loading. Please reload this page.
Store custom client ID on Agent/Connection ID - #224
Conversation
It can be useful to identify which connection submitted what operation. This is already possible to some extent by tracking the ID randomly generated when instantiating `Agent`. However, this ID obviously changes on every connection, and bears no relation to the actual client that is connecting. This change allows the client to specify some ID when connecting, which will be concatenated on to the agent's ID like this: `<randomId>:<clientId>` Keeping the `randomId` ensures that the IDs remain unique, and concatenating the `clientId` allows the consumer to later determine which operations were submitted by the client that matches that ID, by checking the `src` field stored on an operation.
coveralls
commented
Jul 16, 2018
gkubisa
left a comment
There was a problem hiding this comment.
Looks good to me. Could you update README.md before I merge (into https://github.com/teamwork/sharedb), please?
If we prepend the custom client ID to the agent ID rather than prepend, then we gain the advantage of being able to easily group and fetch ops made by the same client (provided the underlying data structure has an appropriate index).
alecgibson
commented
Jul 16, 2018
@gkubisa I've added a bit more documentation for |
gkubisa
commented
Jul 16, 2018
Nice, thanks @alecgibson 👍 It's merged and published as |
gkubisa
commented
Jul 16, 2018
It would be great, if the remote In my opinion the above events should be emitted with an Event object, rather than individual params for |
alecgibson
commented
Jul 16, 2018
@gkubisa this isn't to be confused with the (other) The intended use case for this |
gkubisa
commented
Jul 16, 2018
Grand, I might look into exposing it in the client API at some point. |
alecgibson
commented
Jul 16, 2018
Yes, that would make sense. My use-case is really only about dumping them into the database for retrieval via Mongo (outside of ShareDb), but they should be pretty trivial to extract again, too at the other end. I thought I wouldn't implement that end, because I don't really know what would be required. |
alecgibson
commented
Jul 18, 2018
As we discussed in the PR meeting, I'll close this in favour of just storing this on metadata in the middleware. If anyone does want this sort of functionality in the future, we discussed that the best option is just to let consumers pass in a |
curran
commented
Jul 19, 2018
How would the equivalent middleware code look? Might it be possible to convert this PR into a reusable middleware package? It would be a shame to see this work go to waste, especially if it address a common problem. |
alecgibson
commented
Jul 19, 2018
@curran I need to implement this, so once I've done it I'll try to share a gist or something. |
@curran for reference, this is roughly what the middleware looks like: share.use('connect',(request,callback)=>{// Clone request to avoid mutation after connectionconstrequestJson=JSON.stringify(request.req||{});constrequestData=JSON.parse(requestJson);Object.assign(request.agent.custom,requestData);callback();});share.use('submit',(request,callback)=>{request.op.m.userId=request.agent.custom.userId;callback();});I think it's probably too small to bother putting into a library. |
curran
commented
Jul 20, 2018
Awesome. Thanks! |
houshuang
commented
Sep 30, 2018
@alecgibson Hi, this looks like exactly what I need, but I need a bit more context to use it. My use case is that I want to identify a userid when logging in from the client, however for the life of me I cannot figure out how to pass the custom userId when connecting from a client? Your help would be much appreciated! I tried constReconnectingWebSocket=require('reconnectingwebsocket');constsharedbClient=require('sharedb/lib/client');socket=newReconnectingWebSocket(shareDbUrl);_connection=newsharedbClient.Connection(socket,{userId: 'stian'});but when console.logging the request in the middleware, it was undefined. And anyway I don't see any code in the client library which would pass any information along to the server? |
alecgibson
commented
Oct 1, 2018
@houshuang you need to pass the information in from the server side, so wherever it is in your backend code that you call |
houshuang
commented
Oct 1, 2018
via email
Thank you very much for replying, but I still don't quite understand. I
start up a listener on the server, and then each client connects
individually directly with the ShareDB port, so how would the backend know,
at the time the listener is started, which user is connecting from the
front-end? I was expecting to be able to send this information from the
front-end when connect()ing somehow. …On Mon, Oct 1, 2018 at 12:05 PM Alec Gibson ***@***.***> wrote:
@houshuang <https://github.com/houshuang> you need to pass the
information in from the server side
<https://github.com/share/sharedb/blob/master/lib/backend.js#L137-L168>,
so wherever it is in your backend code that you call share.connect or
share.listen, you need to pass the user Id in there (eg by retrieving it
through an authentication cookie or similar).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#224 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AADwhwqqRPBiS3nBud-jzrwTSY13BHtAks5ugejPgaJpZM4VQ9cv>
.
-- http://reganmian.net/blog -- Random Stuff that Matters |
alecgibson
commented
Oct 1, 2018
@houshuang on your server you should some code that looks something like this (from the varWebSocketJSONStream=require('websocket-json-stream');// 'ws' is a websocket server connection, as passed into// new (require('ws').Server).on('connection', ...)varstream=newWebSocketJSONStream(ws);share.listen(stream);Each websocket will be unique to the connecting client, which you are hopefully somehow authenticating when they connect. With that authentication information, you should have a handle on their user ID on the server, so you should be able to adapt the above to something like: varwss=newWebSocket.Server();wss.on('connection',function(ws,req){// If you're using Express you'll need to use cookie-parser.constauthenticationToken=req.cookies.token;// Then you'll presumably need to do something with your token// to check what the user's ID is (eg db lookup, or parse JWT, etc.)constuserId=getUserIdFrom(token);conststream=newWebSocketJSONStream(ws);backend.listen(stream,{userId: userId});}); |
It can be useful to identify which connection submitted what operation.
This is already possible to some extent by tracking the ID randomly
generated when instantiating
Agent.However, this ID obviously changes on every connection, and bears no
relation to the actual client that is connecting.
This change allows the client to specify some ID when connecting, which
will be concatenated on to the agent's ID like this:
<randomId>:<clientId>Keeping the
randomIdensures that the IDs remain unique, andconcatenating the
clientIdallows the consumer to later determinewhich operations were submitted by the client that matches that ID, by
checking the
srcfield stored on an operation.