From bb89f103894533ff0938a4e60b833aab6442ff84 Mon Sep 17 00:00:00 2001 From: Timo Bechtel Date: Sun, 15 May 2022 20:13:47 +0200 Subject: [PATCH] refactor: prefix socket events with a context adds a prefix to all socketevents to provide a context. this is a preparation to add more event types in the future, like "error" or "emit", besides "data" events BREAKING CHANGE: this breaks compatibility with previous versions. make sure to upgrade both client and server --- src/client.ts | 99 +++++++++++++++++++++++------------------- src/constants.ts | 10 +++++ src/server.ts | 87 ++++++++++++++++++++++--------------- test/client.test.ts | 103 ++++++++++++++++++++++++++------------------ test/server.test.ts | 63 ++++++++++++++++----------- 5 files changed, 214 insertions(+), 148 deletions(-) create mode 100644 src/constants.ts diff --git a/src/client.ts b/src/client.ts index f99ffa5..e3d667f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,5 +1,6 @@ import { createHooks, Hook } from 'krog'; import { createBatchedClient } from './batchedSocketEvents'; +import { DATA_CONTEXT, SOCKET_EVENTS } from './constants'; import { isNode, KeyValue, @@ -101,68 +102,78 @@ export function SocketDBClient({ const queueUpdate = createUpdateBatcher((diff) => { // not deep cloning diff (for perf.), because we do not need to // as diff will be cleared after sending update (see queue) - socketEvents.queue('update', { data: diff }); + socketEvents.queue(SOCKET_EVENTS.data.clientUpdate, { data: diff }); }, updateInterval); const subscriptions = { update: createSubscriptionManager({ createPathSubscription(path, notify) { if (isWildcardPath(path)) { - socketEvents.subscribe(path, ({ data: keys }: { data: string[] }) => { - notify(() => { - const update: { [key: string]: any } = {}; - keys.forEach((key) => (update[key] = null)); - return nodeify(update); - }); + socketEvents.subscribe( + `${DATA_CONTEXT}:${path}`, + ({ data: keys }: { data: string[] }) => { + notify(() => { + const update: { [key: string]: any } = {}; + keys.forEach((key) => (update[key] = null)); + return nodeify(update); + }); + } + ); + socketEvents.queue(SOCKET_EVENTS.data.requestKeysSubscription, { + path: trimWildcard(path), }); - socketEvents.queue('subscribeKeys', { path: trimWildcard(path) }); } else { - socketEvents.subscribe(path, ({ data }: { data: BatchedUpdate }) => { - data.delete?.forEach((path) => { - store.del(path); - subscriptions.update.notify(path, (path) => store.get(path), { - recursiveDown: true, - recursiveUp: true, + socketEvents.subscribe( + `${DATA_CONTEXT}:${path}`, + ({ data }: { data: BatchedUpdate }) => { + data.delete?.forEach((path) => { + store.del(path); + subscriptions.update.notify(path, (path) => store.get(path), { + recursiveDown: true, + recursiveUp: true, + }); }); - }); - if (data.change) { - const update = creatUpdate(path, data.change); - store.put(update); - traverseNode(update, (path, data) => { - subscriptions.update.notify(path, () => - deepClone(store.get(path)) - ); - if (isObject(data.value)) { - // with child paths, we need to notify all listeners for the wildcard path - subscriptions.update.notify(joinPath(path, '*'), () => - store.get(path) + if (data.change) { + const update = creatUpdate(path, data.change); + store.put(update); + traverseNode(update, (path, data) => { + subscriptions.update.notify(path, () => + deepClone(store.get(path)) ); - } else { - // notify all subscribers of all child paths that their data has been deleted - // this has the issue, that it notifies even if data has not changed (meaning it was already null) - // examples when this happens: - // - path '/a' is updated with value '1', path '/a/b' is subscribed -> will be notified with value 'null' - // - path '/a' is deleted (set to null), path '/a/b' is subscribed -> will be notified with value 'null' - subscriptions.update.notify(path, nodeify(null), { - excludeSelf: true, - recursiveDown: true, - }); - } - }); + if (isObject(data.value)) { + // with child paths, we need to notify all listeners for the wildcard path + subscriptions.update.notify(joinPath(path, '*'), () => + store.get(path) + ); + } else { + // notify all subscribers of all child paths that their data has been deleted + // this has the issue, that it notifies even if data has not changed (meaning it was already null) + // examples when this happens: + // - path '/a' is updated with value '1', path '/a/b' is subscribed -> will be notified with value 'null' + // - path '/a' is deleted (set to null), path '/a/b' is subscribed -> will be notified with value 'null' + subscriptions.update.notify(path, nodeify(null), { + excludeSelf: true, + recursiveDown: true, + }); + } + }); + } } - }); - socketEvents.queue('subscribe', { path }); + ); + socketEvents.queue(SOCKET_EVENTS.data.requestSubscription, { path }); } }, destroySubscription(path) { - socketEvents.unsubscribe(path); - socketEvents.queue('unsubscribe', { path }); + socketEvents.unsubscribe(`${DATA_CONTEXT}:${path}`); + socketEvents.queue(SOCKET_EVENTS.data.requestUnsubscription, { path }); }, restoreSubscription(path) { if (isWildcardPath(path)) { - socketEvents.queue('subscribeKeys', { path: trimWildcard(path) }); + socketEvents.queue(SOCKET_EVENTS.data.requestKeysSubscription, { + path: trimWildcard(path), + }); } else { - socketEvents.queue('subscribe', { path }); + socketEvents.queue(SOCKET_EVENTS.data.requestSubscription, { path }); } }, }), diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..5125461 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,10 @@ +export const DATA_CONTEXT = 'data' as const; + +export const SOCKET_EVENTS = { + data: { + clientUpdate: `${DATA_CONTEXT}:update`, + requestSubscription: `${DATA_CONTEXT}:subscribe`, + requestKeysSubscription: `${DATA_CONTEXT}:subscribeKeys`, + requestUnsubscription: `${DATA_CONTEXT}:unsubscribe`, + }, +} as const; diff --git a/src/server.ts b/src/server.ts index 99f4164..537aa2f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,5 +1,6 @@ import { createHooks, Hook } from 'krog'; import { createBatchedClient } from './batchedSocketEvents'; +import { DATA_CONTEXT, SOCKET_EVENTS } from './constants'; import { Node, traverseNode } from './node'; import { joinPath } from './path'; import { Plugin } from './plugin'; @@ -199,43 +200,59 @@ export function SocketDBServer({ { asRef: true } ); }); - socketEvents.subscribe('update', ({ data }: { data: BatchedUpdate }) => { - data.delete?.forEach((path) => del(path, clientContext)); - if (data.change) update(data.change, clientContext); - }); - socketEvents.subscribe('subscribe', ({ path, once }) => { - socketEvents.queue(path, { - // deepClone to only send the current snapshot, as data might change while queued - data: { change: deepClone(store.get(path)) }, - }); - if (once) return; - addSubscriber(id, path, (data) => { - socketEvents.queue(path, { data }); - }); - }); - socketEvents.subscribe('unsubscribe', ({ path }) => { - removeSubscriber(id, path); - }); - socketEvents.subscribe('subscribeKeys', ({ path }) => { - const data = store.get(path); - const wildcardPath = joinPath(path, '*'); - let keys: string[] = []; - if (isObject(data.value)) { - keys = Object.keys(data.value); - // destructure keys to only send the current keys, as they might change while queued - socketEvents.queue(wildcardPath, { data: [...keys] }); + socketEvents.subscribe( + SOCKET_EVENTS.data.clientUpdate, + ({ data }: { data: BatchedUpdate }) => { + data.delete?.forEach((path) => del(path, clientContext)); + if (data.change) update(data.change, clientContext); + } + ); + socketEvents.subscribe( + SOCKET_EVENTS.data.requestSubscription, + ({ path, once }) => { + socketEvents.queue(`${DATA_CONTEXT}:${path}`, { + // deepClone to only send the current snapshot, as data might change while queued + data: { change: deepClone(store.get(path)) }, + }); + if (once) return; + addSubscriber(id, path, (data) => { + socketEvents.queue(`${DATA_CONTEXT}:${path}`, { data }); + }); } - addSubscriber(id + 'wildcard', path, (data: BatchedUpdate) => { - if (data.change && isObject(data.change.value)) { - const newKeys = Object.keys(data.change.value).filter( - (key) => !keys.includes(key) - ); - if (newKeys.length > 0) - socketEvents.queue(wildcardPath, { data: newKeys }); - keys = [...keys, ...newKeys]; + ); + socketEvents.subscribe( + SOCKET_EVENTS.data.requestUnsubscription, + ({ path }) => { + removeSubscriber(id, path); + } + ); + socketEvents.subscribe( + SOCKET_EVENTS.data.requestKeysSubscription, + ({ path }) => { + const data = store.get(path); + const wildcardPath = joinPath(path, '*'); + let keys: string[] = []; + if (isObject(data.value)) { + keys = Object.keys(data.value); + // destructure keys to only send the current keys, as they might change while queued + socketEvents.queue(`${DATA_CONTEXT}:${wildcardPath}`, { + data: [...keys], + }); } - }); - }); + addSubscriber(id + 'wildcard', path, (data: BatchedUpdate) => { + if (data.change && isObject(data.change.value)) { + const newKeys = Object.keys(data.change.value).filter( + (key) => !keys.includes(key) + ); + if (newKeys.length > 0) + socketEvents.queue(`${DATA_CONTEXT}:${wildcardPath}`, { + data: newKeys, + }); + keys = [...keys, ...newKeys]; + } + }); + } + ); }); return api; } diff --git a/test/client.test.ts b/test/client.test.ts index 636d985..6b19fcd 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -1,4 +1,5 @@ import { SocketDBClient } from '../src/client'; +import { DATA_CONTEXT, SOCKET_EVENTS } from '../src/constants'; import { nodeify } from '../src/node'; import { SocketClient } from '../src/socketAdapter/socketClient'; import { createStore } from '../src/store'; @@ -18,7 +19,7 @@ test('throws error when using * as pathname', () => { test('emits update object for path', (done) => { const { socketClient } = mockSocketClient({ onSend(event, { data }) { - expect(event).toEqual('update'); + expect(event).toEqual(SOCKET_EVENTS.data.clientUpdate); expect(data).toEqual({ change: nodeify({ players: { @@ -42,7 +43,7 @@ test('deletes data and notifies local subscribers', (done) => { const { notify, socketClient } = mockSocketClient({ onSend(event, { data }: { data: BatchedUpdate }) { - if (event === 'update') { + if (event === SOCKET_EVENTS.data.clientUpdate) { if (data.change) { expect(data.change).toEqual( nodeify({ @@ -53,13 +54,13 @@ test('deletes data and notifies local subscribers', (done) => { }, }) ); - notify('players/1/name', { + notify(`${DATA_CONTEXT}:players/1/name`, { data: { change: nodeify('Patrick'), }, }); } else { - notify('players/1/name', { + notify(`${DATA_CONTEXT}:players/1/name`, { data: { delete: data.delete, }, @@ -105,7 +106,7 @@ test('should batch updates', (done) => { const { socketClient } = mockSocketClient({ onSend(event, { data }) { - expect(event).toEqual('update'); + expect(event).toEqual(SOCKET_EVENTS.data.clientUpdate); expect(data).toEqual({ change: nodeify({ players: { @@ -168,7 +169,7 @@ test('merges data on update', (done) => { updateCount++; }); - notify('players/1', { + notify(`${DATA_CONTEXT}:players/1`, { data: { change: nodeify({ name: 'Peter', @@ -179,7 +180,7 @@ test('merges data on update', (done) => { }), }, }); - notify('players/1', { + notify(`${DATA_CONTEXT}:players/1`, { data: { change: nodeify({ position: { @@ -193,12 +194,16 @@ test('merges data on update', (done) => { test('can subscribe to path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path, once }) { - expect(event).toEqual('subscribe'); + expect(event).toEqual(SOCKET_EVENTS.data.requestSubscription); expect(path).toBe('players/1'); expect(once).not.toBe(true); - notify('players/1', { data: { change: nodeify({ name: 'Thomas' }) } }); - notify('players/1', { data: { change: nodeify({ name: 'Thomas2' }) } }); - notify('players/1', { data: { delete: ['players/1'] } }); + notify(`${DATA_CONTEXT}:players/1`, { + data: { change: nodeify({ name: 'Thomas' }) }, + }); + notify(`${DATA_CONTEXT}:players/1`, { + data: { change: nodeify({ name: 'Thomas2' }) }, + }); + notify(`${DATA_CONTEXT}:players/1`, { data: { delete: ['players/1'] } }); }, }); @@ -228,18 +233,18 @@ test('can unsubscribe from path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event) { - if (event === 'subscribe') { + if (event === SOCKET_EVENTS.data.requestSubscription) { subscribeCount++; setTimeout(() => { - notify('players/1', { + notify(`${DATA_CONTEXT}:players/1`, { data: { change: nodeify({ name: 'Thomas' }) }, }); unsubscribe(); - notify('players/1', { + notify(`${DATA_CONTEXT}:players/1`, { data: { change: nodeify({ name: 'Thomas2' }) }, }); }, 10); - } else if (event === 'unsubscribe') { + } else if (event === SOCKET_EVENTS.data.requestUnsubscription) { unsubscribeCount++; } }, @@ -265,9 +270,11 @@ test('can unsubscribe from path', (done) => { test('can subscribe to path once', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path }) { - if (event === 'subscribe') { + if (event === SOCKET_EVENTS.data.requestSubscription) { expect(path).toBe('players/1'); - notify('players/1', { data: { change: nodeify('test') } }); + notify(`${DATA_CONTEXT}:players/1`, { + data: { change: nodeify('test') }, + }); } }, }); @@ -365,11 +372,13 @@ test('unsubscribing does not cancel other subscriptions', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { data }) { - if (event === 'update') { + if (event === SOCKET_EVENTS.data.clientUpdate) { expect(data).toEqual({ change: nodeify({ path: 'test' }), }); - notify('path', { data: { change: nodeify('test') } }); + notify(`${DATA_CONTEXT}:path`, { + data: { change: nodeify('test') }, + }); } }, }); @@ -398,9 +407,9 @@ test('unsubscribing does not cancel other subscriptions', (done) => { test('can subscribe to keys of path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path }) { - if (event === 'subscribeKeys') { + if (event === SOCKET_EVENTS.data.requestKeysSubscription) { expect(path).toBe('players'); - notify('players/*', { data: ['1', '2'] }); + notify(`${DATA_CONTEXT}:players/*`, { data: ['1', '2'] }); } }, }); @@ -423,9 +432,9 @@ test('can subscribe to keys of path', (done) => { test('can unsubscribe from keys of path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path }) { - if (event === 'subscribeKeys') { + if (event === SOCKET_EVENTS.data.requestKeysSubscription) { expect(path).toBe('players'); - notify('players/*', { data: ['1'] }); + notify(`${DATA_CONTEXT}:players/*`, { data: ['1'] }); } }, }); @@ -439,7 +448,7 @@ test('can unsubscribe from keys of path', (done) => { }); setTimeout(() => { unsubscribe(); - notify('players/*', { data: ['2', '3'] }); + notify(`${DATA_CONTEXT}:players/*`, { data: ['2', '3'] }); setTimeout(() => { expect(updateCount).toBe(1); done(); @@ -450,8 +459,10 @@ test('can unsubscribe from keys of path', (done) => { test('received data should not be passed as reference', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { data }) { - if (event === 'update') { - notify('data', { data: { change: data.change.value.data } }); + if (event === SOCKET_EVENTS.data.clientUpdate) { + notify(`${DATA_CONTEXT}:data`, { + data: { change: data.change.value.data }, + }); } }, }); @@ -481,8 +492,8 @@ test('also receives metadata', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event) { - if (event === 'subscribe') { - notify('players/1', { + if (event === SOCKET_EVENTS.data.requestSubscription) { + notify(`${DATA_CONTEXT}:players/1`, { data: { change: { meta: metaExample, value: 'Thomas' } }, }); } @@ -526,8 +537,10 @@ test('allows setting metadata', (done) => { test('on/once always receives data on first call', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event) { - if (event === 'subscribe') { - notify('players/1', { data: { change: nodeify({ name: 'Thomas' }) } }); + if (event === SOCKET_EVENTS.data.requestSubscription) { + notify(`${DATA_CONTEXT}:players/1`, { + data: { change: nodeify({ name: 'Thomas' }) }, + }); client .get('players') .get('1') @@ -554,7 +567,7 @@ test('on/once always receives data on first call', (done) => { test('only subscribes once for every root path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event) { - if (event === 'subscribe') { + if (event === SOCKET_EVENTS.data.requestSubscription) { subscriptionCount++; } }, @@ -589,7 +602,9 @@ test('only subscribes once for every root path', (done) => { expect(subscriptionCount).toBe(1); // we don't have data yet expect(updateCount).toBe(0); - notify('players', { data: { change: nodeify({ 1: { name: 'Paul' } }) } }); + notify(`${DATA_CONTEXT}:players`, { + data: { change: nodeify({ 1: { name: 'Paul' } }) }, + }); setTimeout(() => { expect(updateCount).toBe(4); @@ -601,12 +616,12 @@ test('only subscribes once for every root path', (done) => { test('always subscribe to highest level path', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path }) { - if (event === 'subscribe') { + if (event === SOCKET_EVENTS.data.requestSubscription) { subscriptionCount++; if (subscriptionCount === 2) { expect(path).toBe('players'); } - } else if (event === 'unsubscribe') { + } else if (event === SOCKET_EVENTS.data.requestUnsubscription) { unsubscriptionCount++; } }, @@ -646,7 +661,7 @@ test('always subscribe to highest level path', (done) => { }); updateReceivedCount++; }); - notify('players', { + notify(`${DATA_CONTEXT}:players`, { data: { change: nodeify({ 1: { @@ -701,15 +716,15 @@ test('always subscribe to highest level path', (done) => { test('does not resubscribe to keys if higher level path is already subscribed', (done) => { const { socketClient, notify } = mockSocketClient({ onSend(event, { path }) { - if (event === 'subscribeKeys') { + if (event === SOCKET_EVENTS.data.requestKeysSubscription) { fail('should not subscribe to keys'); } - if (event === 'subscribe') { + if (event === SOCKET_EVENTS.data.requestSubscription) { expect(path).toBe('players'); // simulate coming from server + make sure, "each" is called before // checks if each will receive updates coming from server setTimeout(() => { - notify('players', { + notify(`${DATA_CONTEXT}:players`, { data: { change: nodeify({ 1: 'test1', 2: 'test2' }) }, }); }, 10); @@ -735,8 +750,8 @@ test('does not resubscribe to keys if higher level path is already subscribed', test('if data is null, should notify every subpath', (done) => { const { socketClient, notify } = mockSocketClient({ - onSend(event, { path }) { - if (event === 'subscribe') { + onSend(event) { + if (event === SOCKET_EVENTS.data.requestSubscription) { subscriptionCount++; } }, @@ -773,7 +788,7 @@ test('if data is null, should notify every subpath', (done) => { testString += 'd'; }); - notify('players', { data: { change: nodeify(null) } }); + notify(`${DATA_CONTEXT}:players`, { data: { change: nodeify(null) } }); setTimeout(() => { expect(subscriptionCount).toBe(1); @@ -787,11 +802,13 @@ test('subscribes again after reconnect', (done) => { const { socketClient, notify, disconnect, reconnect } = mockSocketClient({ onSend(event, { path, once }) { subscribeCount++; - expect(event).toEqual('subscribe'); + expect(event).toEqual(SOCKET_EVENTS.data.requestSubscription); expect(path).toBe('players/1'); expect(once).not.toBe(true); if (subscribeCount === 1) { - notify('players/1', { data: { change: nodeify({ name: 'Thomas' }) } }); + notify(`${DATA_CONTEXT}:players/1`, { + data: { change: nodeify({ name: 'Thomas' }) }, + }); disconnect(); reconnect(); } else { diff --git a/test/server.test.ts b/test/server.test.ts index a4e0924..c3ed479 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -1,3 +1,4 @@ +import { DATA_CONTEXT, SOCKET_EVENTS } from '../src/constants'; import { nodeify } from '../src/node'; import { SocketDBServer } from '../src/server'; import { createStore } from '../src/store'; @@ -32,7 +33,7 @@ test('updates data on socket request', () => { SocketDBServer({ store, socketServer }); const { notify } = connectClient(); - notify('update', { + notify(SOCKET_EVENTS.data.clientUpdate, { data: { change: nodeify({ players: { @@ -58,7 +59,7 @@ test('deletes data on socket request', (done) => { SocketDBServer({ store, socketServer }); const { notify } = connectClient(); - notify('update', { + notify(SOCKET_EVENTS.data.clientUpdate, { data: { change: nodeify({ players: { @@ -72,7 +73,7 @@ test('deletes data on socket request', (done) => { }); setTimeout(() => { expect(store.get('players/1')).toEqual(nodeify({ x: 0, y: 1 })); - notify('update', { + notify(SOCKET_EVENTS.data.clientUpdate, { data: { delete: ['players/1'], }, @@ -104,14 +105,14 @@ test('sends data on first subscribe', (done) => { const { notify } = connectClient({ id: '1', onSend(event, { data }) { - if (event === 'players/1') { + if (event === `${DATA_CONTEXT}:players/1`) { expect(data).toEqual({ change: nodeify({ name: 'Ralph' }) }); done(); } }, }); - notify('subscribe', { path: 'players/1' }); + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'players/1' }); }); test('emits updates to subscriber', (done) => { @@ -123,12 +124,12 @@ test('emits updates to subscriber', (done) => { let count = 1; const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players/1') { + if (event === `${DATA_CONTEXT}:players/1`) { if (count === 1) { expect(data).toEqual({ change: nodeify(null) }); count++; setTimeout(() => { - notify('update', { + notify(SOCKET_EVENTS.data.clientUpdate, { data: { change: nodeify({ players: { @@ -154,7 +155,7 @@ test('emits updates to subscriber', (done) => { }, }); - notify('subscribe', { path: 'players/1' }); + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'players/1' }); }); test('only emits changed values', (done) => { @@ -177,7 +178,7 @@ test('only emits changed values', (done) => { const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players/1') { + if (event === `${DATA_CONTEXT}:players/1`) { if (updateCount === 0) { updateCount++; expect(data).toEqual({ change: nodeify({ name: 'Peter' }) }); @@ -196,8 +197,8 @@ test('only emits changed values', (done) => { }, }); - notify('subscribe', { path: 'players/1' }); - notify('update', { + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'players/1' }); + notify(SOCKET_EVENTS.data.clientUpdate, { data: { change: nodeify({ players: { @@ -233,7 +234,7 @@ test('emits updates to all subscribers', async () => { await new Promise((resolve) => { const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players') { + if (event === `${DATA_CONTEXT}:players`) { expect(data).toEqual({ change: nodeify({ 1: { @@ -245,18 +246,21 @@ test('emits updates to all subscribers', async () => { } }, }); - notify('subscribe', { path: 'players', once: true }); + notify(SOCKET_EVENTS.data.requestSubscription, { + path: 'players', + once: true, + }); }); await new Promise((resolve) => { const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players/1/name') { + if (event === `${DATA_CONTEXT}:players/1/name`) { expect(data).toEqual({ change: nodeify('Peter') }); resolve(); } }, }); - notify('subscribe', { path: 'players/1/name' }); + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'players/1/name' }); }); }); @@ -281,11 +285,11 @@ test('sends keys when entries are added or removed', async () => { let count = 0; const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players/*') { + if (event === `${DATA_CONTEXT}:players/*`) { if (count === 0) { expect(data).toEqual(['1']); setTimeout(() => { - notify('update', { + notify(SOCKET_EVENTS.data.clientUpdate, { data: { change: nodeify({ players: { @@ -309,7 +313,10 @@ test('sends keys when entries are added or removed', async () => { } }, }); - notify('subscribeKeys', { path: 'players', flat: true }); + notify(SOCKET_EVENTS.data.requestKeysSubscription, { + path: 'players', + flat: true, + }); }); }); @@ -324,14 +331,14 @@ test('only send data if client is subscribed', (done) => { const { notify } = connectClient({ onSend(event, { data }) { - if (event === 'players/1') { + if (event === `${DATA_CONTEXT}:players/1`) { receivedCount++; } }, }); - notify('subscribe', { path: 'players/1' }); - notify('unsubscribe', { path: 'players/1' }); + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'players/1' }); + notify(SOCKET_EVENTS.data.requestUnsubscription, { path: 'players/1' }); server.update( nodeify({ players: { @@ -357,7 +364,7 @@ test('should batch updates', (done) => { let receivedCount = 0; const { notify } = connectClient({ - onSend(event, { data }) { + onSend(_, { data }) { if (receivedCount === 0) { expect(data).toEqual({ change: nodeify(null) }); } @@ -368,11 +375,15 @@ test('should batch updates', (done) => { }, }); - notify('subscribe', { path: 'player' }); + notify(SOCKET_EVENTS.data.requestSubscription, { path: 'player' }); - notify('update', { data: { change: nodeify({ player: 'a' }) } }); - notify('update', { data: { change: nodeify({ player: 'b' }) } }); - notify('update', { data: { delete: ['player/a'] } }); + notify(SOCKET_EVENTS.data.clientUpdate, { + data: { change: nodeify({ player: 'a' }) }, + }); + notify(SOCKET_EVENTS.data.clientUpdate, { + data: { change: nodeify({ player: 'b' }) }, + }); + notify(SOCKET_EVENTS.data.clientUpdate, { data: { delete: ['player/a'] } }); setTimeout(() => { // first: null, second: 'b'