Skip to content

Commit

Permalink
Awareness emits different events for update and for change
Browse files Browse the repository at this point in the history
  • Loading branch information
dmonad committed Jun 5, 2020
1 parent fa8ebc1 commit 6f4d055
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 38 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ offline.
</dd>
<b><code>setLocalStateField(string, any)</code></b>
<dd>
Only update a single field on the local awareness object. Does not do
Only update a single field on the local awareness object. Does not do
anything if the local state is not set.
</dd>
<b><code>getStates():Map&lt;number,Object&lt;string,any&gt;&gt;</code></b>
Expand All @@ -58,7 +58,15 @@ on('change', ({ added: Array&lt;number&gt;, updated: Array&lt;number&gt;
removed: Array&lt;number&gt; }, [transactionOrigin:any]) => ..)
</code></b>
<dd>
Listen to remote and local changes on the awareness instance.
Listen to remote and local state changes on the awareness instance.
</dd>
<b><code>
on('update', ({ added: Array&lt;number&gt;, updated: Array&lt;number&gt;
removed: Array&lt;number&gt; }, [transactionOrigin:any]) => ..)
</code></b>
<dd>
Listen to remote and local awareness changes on the awareness instance.
This event is called even when the awarenes state does not change.
</dd>
</dl>

Expand Down
30 changes: 26 additions & 4 deletions awareness.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as decoding from 'lib0/decoding.js'
import * as time from 'lib0/time.js'
import * as math from 'lib0/math.js'
import { Observable } from 'lib0/observable.js'
import * as f from 'lib0/function.js'
import * as Y from 'yjs' // eslint-disable-line

export const outdatedTimeout = 30000
Expand Down Expand Up @@ -91,6 +92,7 @@ export class Awareness extends Observable {
const clientID = this.doc.clientID
const currLocalMeta = this.meta.get(clientID)
const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1
const prevState = this.states.get(clientID)
if (state === null) {
this.states.delete(clientID)
} else {
Expand All @@ -102,15 +104,24 @@ export class Awareness extends Observable {
})
const added = []
const updated = []
const filteredUpdated = []
const removed = []
if (state === null) {
removed.push(clientID)
} else if (currLocalMeta === undefined) {
added.push(clientID)
} else if (prevState == null) {
if (state != null) {
added.push(clientID)
}
} else {
updated.push(clientID)
if (!f.equalityDeep(prevState, state)) {
filteredUpdated.push(clientID)
}
}
this.emit('change', [{ added, updated, removed }, 'local'])
if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local'])
}
this.emit('update', [{ added, updated, removed }, 'local'])
}
/**
* @param {string} field
Expand Down Expand Up @@ -157,6 +168,7 @@ export const removeAwarenessStates = (awareness, clients, origin) => {
}
if (removed.length > 0) {
awareness.emit('change', [{ added: [], updated: [], removed }, origin])
awareness.emit('update', [{ added: [], updated: [], removed }, origin])
}
}

Expand Down Expand Up @@ -190,13 +202,15 @@ export const applyAwarenessUpdate = (awareness, update, origin) => {
const timestamp = time.getUnixTime()
const added = []
const updated = []
const filteredUpdated = []
const removed = []
const len = decoding.readVarUint(decoder)
for (let i = 0; i < len; i++) {
const clientID = decoding.readVarUint(decoder)
let clock = decoding.readVarUint(decoder)
const state = JSON.parse(decoding.readVarString(decoder))
const clientMeta = awareness.meta.get(clientID)
const prevState = awareness.states.get(clientID)
const currClock = clientMeta === undefined ? 0 : clientMeta.clock
if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
if (state === null) {
Expand All @@ -220,12 +234,20 @@ export const applyAwarenessUpdate = (awareness, update, origin) => {
} else if (clientMeta !== undefined && state === null) {
removed.push(clientID)
} else if (state !== null) {
if (!f.equalityDeep(state, prevState)) {
filteredUpdated.push(clientID)
}
updated.push(clientID)
}
}
}
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
awareness.emit('change', [{
added, updated: filteredUpdated, removed
}, origin])
}
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
awareness.emit('update', [{
added, updated, removed
}, origin])
}
Expand Down
35 changes: 35 additions & 0 deletions awareness.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

import * as Y from 'yjs'
import * as t from 'lib0/testing.js'
import * as awareness from './awareness.js'

/**
* @param {t.TestCase} tc
*/
export const testAwareness = tc => {
const doc1 = new Y.Doc()
doc1.clientID = 0
const doc2 = new Y.Doc()
doc2.clientID = 1
const aw1 = new awareness.Awareness(doc1)
const aw2 = new awareness.Awareness(doc2)
aw1.on('update', /** @param {any} p */ ({ added, updated, removed }) => {
const enc = awareness.encodeAwarenessUpdate(aw1, added.concat(updated).concat(removed))
awareness.applyAwarenessUpdate(aw2, enc, 'custom')
})
let lastChange = /** @type {any} */ (null)
aw2.on('change', /** @param {any} change */ change => {
lastChange = change
})
aw1.setLocalState({ x: 4 })
t.compare(aw2.getStates().get(0), { x: 4 })
t.assert(/** @type {any} */ (aw2.meta.get(0)).clock === 1)
t.compare(lastChange.added, [0])
lastChange = null
aw1.setLocalState({ x: 4 })
t.assert(lastChange === null)
t.assert(/** @type {any} */ (aw2.meta.get(0)).clock === 2)
aw1.setLocalState(null)
t.assert(lastChange.removed.length === 1)
t.compare(aw1.getStates().get(0), undefined)
}
42 changes: 22 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"version": "0.2.3",
"description": "Yjs encoding protocols",
"type": "module",
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"files": [
"dist/*",
"auth.*",
Expand All @@ -12,9 +16,10 @@
"scripts": {
"clean": "rm -rf dist *.d.ts */*.d.ts *.d.ts.map */*.d.ts.map",
"dist": "rm -rf dist && rollup -c",
"test": "npm run lint",
"test": "npm run lint && npm run dist && node dist/test.cjs",
"lint": "standard && tsc",
"types": "tsc --outDir .",
"debug": "rollup -c && concurrently 'rollup -wc' 'http-server -o test.html'",
"preversion": "npm run dist && npm run test && npm run types",
"postpublish": "npm run clean"
},
Expand All @@ -38,11 +43,10 @@
},
"homepage": "https://github.com/yjs/y-protocols#readme",
"dependencies": {
"lib0": "^0.2.20"
"lib0": "^0.2.28"
},
"devDependencies": {
"rollup": "^1.1.2",
"rollup-cli": "^1.0.9",
"rollup": "^1.29.0",
"standard": "^12.0.1",
"typescript": "^3.8.3",
"yjs": "^13.0.4"
Expand Down
31 changes: 23 additions & 8 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import fs from 'fs'
import path from 'path'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'

const files = fs.readdirSync('./').filter(file => /(?<!\.(test|config))\.js$/.test(file))
const files = ['awareness.js', 'auth.js', 'sync.js', 'test.js']

export default files.map(file => ({
input: file,
export default [{
input: './test.js',
output: {
file: path.join('./dist', file.slice(0, -3) + '.cjs'),
file: './dist/test.js',
format: 'iife',
sourcemap: true
},
plugins: [
resolve({ mainFields: ['module', 'browser', 'main'] }),
commonjs()
]
}, {
input: files,
output: {
dir: './dist',
format: 'cjs',
sourcemap: true,
entryFileNames: '[name].cjs',
chunkFileNames: '[name]-[hash].cjs',
paths: /** @param {any} path */ path => {
if (/^lib0\//.test(path)) {
return `lib0/dist/${path.slice(5, -3) + '.cjs'}`
}
return path
}
}
}))
},
external: /** @param {any} id */ id => /^lib0\/|yjs/.test(id)
}]
9 changes: 9 additions & 0 deletions test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Testing y-protocols</title>
</head>
<body>
<script src="./dist/test.js"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { runTests } from 'lib0/testing.js'
import * as log from 'lib0/logging.js'
import * as awareness from './awareness.test.js'

import { isBrowser, isNode } from 'lib0/environment.js'

/* istanbul ignore if */
if (isBrowser) {
log.createVConsole(document.body)
}

runTests({
awareness
}).then(success => {
/* istanbul ignore next */
if (isNode) {
process.exit(success ? 0 : 1)
}
})

0 comments on commit 6f4d055

Please sign in to comment.