-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
@gkubisa I've added a bit more documentation for |
Nice, thanks @alecgibson 👍 It's merged and published as |
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 |
@gkubisa this isn't to be confused with the (other) The intended use case for this |
Grand, I might look into exposing it in the client API at some point. |
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. |
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 |
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. |
@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 connection
const requestJson = JSON.stringify(request.req || {});
const requestData = 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. |
Awesome. Thanks! |
@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 const ReconnectingWebSocket = require('reconnectingwebsocket');
const sharedbClient = require('sharedb/lib/client');
socket = new ReconnectingWebSocket(shareDbUrl);
_connection = new sharedbClient.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? |
@houshuang you need to pass the information in from the server side, so wherever it is in your backend code that you call |
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
|
@houshuang on your server you should some code that looks something like this (from the var WebSocketJSONStream = require('websocket-json-stream');
// 'ws' is a websocket server connection, as passed into
// new (require('ws').Server).on('connection', ...)
var stream = new WebSocketJSONStream(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: var wss = new WebSocket.Server();
wss.on('connection', function(ws, req) {
// If you're using Express you'll need to use cookie-parser.
const authenticationToken = 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.)
const userId = getUserIdFrom(token);
const stream = new WebSocketJSONStream(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
randomId
ensures that the IDs remain unique, andconcatenating the
clientId
allows the consumer to later determinewhich operations were submitted by the client that matches that ID, by
checking the
src
field stored on an operation.