-
Notifications
You must be signed in to change notification settings - Fork 453
Presence 2 #288
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
Presence 2 #288
Changes from all commits
9121baf
4dbefd1
2ef8181
6b687db
1489e36
a4499a5
33c7264
8ff4b33
0ff380d
d67dd6a
e8ec215
9c291b2
173bf3a
054d34d
642ded6
56b726b
762496a
e4c5e6d
428c46a
33450ae
f43b752
9409429
c4cf1b8
237d2ad
c8d35c5
3efb82c
f0451e3
5217635
ac26dae
48acccc
cab69fb
6a0ecc4
d41c961
fc351fa
6cd16f3
ad6a528
eaafc98
7259f7e
09f6415
23a06c3
824346f
d6e3e3d
0382c03
46d8a1b
fc16be7
9cb5564
6461a79
2358022
41a4743
ba7d880
3ffd1ab
6114bad
19446cd
0089f80
2054057
1a64a06
47193da
b23661c
521f77b
bdb6424
0f3084a
41cd2ea
986a695
ac55884
9187b34
7507731
1a1f52a
49ff5c2
87aa90b
2198e8e
cf0168d
4c46a05
f0b7b97
db39b69
60a567b
8b6872e
55e1a4d
7a79d98
693492d
538c3c1
963affa
810175e
0724fd7
7af8427
910b384
ca4816f
406d4e0
7c729d7
b0d4277
65ce131
f09ad62
1ff8798
2fb0637
d210133
95ae394
0b65164
1a7bc3e
8a05619
a551de3
3dfc938
df5a466
40abc17
9851465
5cc30e6
14b0d31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// The ESLint ecmaVersion argument is inconsistently used. Some rules will ignore it entirely, so if the rule has | ||
// been set, it will still error even if it's not applicable to that version number. Since Google sets these | ||
// rules, we have to turn them off ourselves. | ||
const DISABLED_ES6_OPTIONS = { | ||
'no-var': 'off', | ||
'prefer-rest-params': 'off' | ||
}; | ||
|
||
const SHAREDB_RULES = { | ||
// Comma dangle is not supported in ES3 | ||
'comma-dangle': ['error', 'never'], | ||
// We control our own objects and prototypes, so no need for this check | ||
'guard-for-in': 'off', | ||
// Google prescribes different indents for different cases. Let's just use 2 spaces everywhere. Note that we have | ||
// to override ESLint's default of 0 indents for this. | ||
'indent': ['error', 2, { | ||
'SwitchCase': 1 | ||
}], | ||
// Less aggressive line length than Google, which is especially useful when we have a lot of callbacks in our code | ||
'max-len': ['error', | ||
{ | ||
code: 120, | ||
tabWidth: 2, | ||
ignoreUrls: true, | ||
} | ||
], | ||
// Google overrides the default ESLint behaviour here, which is slightly better for catching erroneously unused variables | ||
'no-unused-vars': ['error', {vars: 'all', args: 'after-used'}], | ||
// It's more readable to ensure we only have one statement per line | ||
'max-statements-per-line': ['error', {max: 1}], | ||
// as-needed quote props are easier to write | ||
'quote-props': ['error', 'as-needed'], | ||
'require-jsdoc': 'off', | ||
'valid-jsdoc': 'off' | ||
}; | ||
|
||
module.exports = { | ||
extends: 'google', | ||
parserOptions: { | ||
ecmaVersion: 3 | ||
}, | ||
rules: Object.assign( | ||
{}, | ||
DISABLED_ES6_OPTIONS, | ||
SHAREDB_RULES | ||
), | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,4 +34,5 @@ coverage | |
# Dependency directories | ||
node_modules | ||
package-lock.json | ||
yarn.lock | ||
jspm_packages |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ tracker](https://github.com/share/sharedb/issues). | |
|
||
- Realtime synchronization of any JSON document | ||
- Concurrent multi-user collaboration | ||
- Realtime synchronization of any ephemeral "presence" data | ||
- Synchronous editing API with asynchronous eventual consistency | ||
- Realtime query subscriptions | ||
- Simple integration with any database - [MongoDB](https://github.com/share/sharedb-mongo), [PostgresQL](https://github.com/share/sharedb-postgres) (experimental) | ||
|
@@ -73,6 +74,22 @@ initial data. Then you can submit editing operations on the document (using | |
OT). Finally you can delete the document with a delete operation. By | ||
default, ShareDB stores all operations forever - nothing is truly deleted. | ||
|
||
## User Presence Synchronization | ||
|
||
ShareDB supports synchronization of user presence data such as cursor positions and text selections. This feature is opt-in, not enabled by default. To enable this feature, pass a presence implementation as the `presence` option to the ShareDB constructor. | ||
|
||
ShareDB includes an implementation of presence called `StatelessPresence`. This provides an implementation of presence that works out of the box, but it has some scalability problems. Each time a client joins a document, this implementation requests current presence information from all other clients, via the server. This approach may be problematic in terms of performance when a large number of users are present on the same document simultaneously. If you don't expect too many simultaneous users per document, `StatelessPresence` should work well. The server does not store any state at all regarding presence (it exists only in clients), hence the name "Stateless Presence". | ||
|
||
In `StatelessPresence`, presence data represents a user and is automatically synchronized between all clients subscribed to the same document. Its format is defined by the document's [OT Type](https://github.com/ottypes/docs) (specifically, by [`transformPresence`, `createPresence`, and `comparePresence`](https://github.com/teamwork/ot-docs#optional-properties)). All clients can modify their own presence data and receive a read-only version of other client's data. Presence data is automatically cleared when a client unsubscribes from the document or disconnects. It is also automatically transformed against applied operations, so that it still makes sense in the context of a modified document, for example a cursor position may be automatically advanced when a user types at the beginning of a text document. | ||
|
||
To use `StatelessPresence`, pass it into the ShareDB constructor like this: | ||
|
||
```js | ||
var ShareDB = require('sharedb'); | ||
var statelessPresence = require('sharedb/lib/presence/stateless'); | ||
var share = new ShareDB({ presence: statelessPresence })`). | ||
``` | ||
|
||
## Server API | ||
|
||
### Initialization | ||
|
@@ -91,6 +108,8 @@ __Options__ | |
* `options.pubsub` _(instance of `ShareDB.PubSub`)_ | ||
Notify other ShareDB processes when data changes | ||
through this pub/sub adapter. Defaults to `ShareDB.MemoryPubSub()`. | ||
* `options.presence` _(implementation of presence classes)_ | ||
Enable user presence synchronization. The value of `options.presence` option is expected to contain implementations of the classes `DocPresence`, `ConnectionPresence`, `AgentPresence`, and `BackendPresence`. Logic related to presence is encapsulated within these classes, so it is possible develop additional third party presence implementations external to ShareDB. | ||
|
||
#### Database Adapters | ||
* `ShareDB.MemoryDB`, backed by a non-persistent database with no queries | ||
|
@@ -308,6 +327,9 @@ Unique document ID | |
`doc.data` _(Object)_ | ||
Document contents. Available after document is fetched or subscribed to. | ||
|
||
`doc.presence` _(Object)_ | ||
Each property under `doc.presence` contains presence data shared by a client subscribed to this document. The property name is an empty string for this client's data and connection IDs for other clients' data. The structure of the presence object is defined by the OT type of the document (for example, in [ot-rich-text](https://github.com/Teamwork/ot-rich-text#presence) and [@datavis-tech/json0](https://github.com/datavis-tech/json0#presence)). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I agree with handing this off to the types, because:
To me, it feels more natural for us to define some sort of separate presence transformers, probably being passed in to the |
||
|
||
`doc.fetch(function(err) {...})` | ||
Populate the fields on `doc` with a snapshot of the document from the server. | ||
|
||
|
@@ -337,6 +359,9 @@ An operation was applied to the data. `source` will be `false` for ops received | |
`doc.on('del', function(data, source) {...})` | ||
The document was deleted. Document contents before deletion are passed in as an argument. `source` will be `false` for ops received from the server and defaults to `true` for ops generated locally. | ||
|
||
`doc.on('presence', function(srcList, submitted) {...})` | ||
Presence data has changed. `srcList` is an Array of `doc.presence` property names for which values have changed. `submitted` is `true`, if the event is the result of new presence data being submitted by the local or remote user, otherwise it is `false` - eg if the presence data was transformed against an operation or was cleared on unsubscribe, disconnect or roll-back. | ||
|
||
`doc.on('error', function(err) {...})` | ||
There was an error fetching the document or applying an operation. | ||
|
||
|
@@ -370,6 +395,11 @@ Invokes the given callback function after | |
|
||
Note that `whenNothingPending` does NOT wait for pending `model.query()` calls. | ||
|
||
`doc.submitPresence(presenceData[, function(err) {...}])` | ||
Set local presence data and publish it for other clients. | ||
`presenceData` structure depends on the document type. | ||
Presence is synchronized only when subscribed to the document. | ||
|
||
### Class: `ShareDB.Query` | ||
|
||
`query.ready` _(Boolean)_ | ||
|
@@ -467,6 +497,10 @@ Additional fields may be added to the error object for debugging context dependi | |
* 4022 - Database adapter does not support queries | ||
* 4023 - Cannot project snapshots of this type | ||
* 4024 - Invalid version | ||
* 4025 - Passing options to subscribe has not been implemented | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (NB: We'll need to change these to string error codes: #309) |
||
* 4026 - Not subscribed to document | ||
* 4027 - Presence data superseded | ||
* 4028 - OT Type does not support presence | ||
|
||
### 5000 - Internal error | ||
|
||
|
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.
I'm not sure about this API. It feels atypical both of normal JS, and also of this library. I think I'd rather pass in a single
presence
object which exposes API methods, much like the DB adapters.