diff --git a/docker/Dockerfile b/docker/Dockerfile index 1114987..0737cb4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ RUN chown -R node /usr/src/app RUN apk add --no-cache tini -RUN npm install -g npm && npm install -g wire.io@latest +RUN npm install -g npm && npm install -g wire.io@3.3.1 USER node diff --git a/src/__snapshots__/client.test.js.snap b/src/__snapshots__/client.test.js.snap index 77eaaef..a282deb 100644 --- a/src/__snapshots__/client.test.js.snap +++ b/src/__snapshots__/client.test.js.snap @@ -1,11 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Client should call remote first function 1`] = `undefined`; +exports[`Client should call remote first function 1`] = `"Function testrpc is not registered"`; -exports[`Client should call remote last function 1`] = `undefined`; +exports[`Client should call remote last function 1`] = `"Function testrpc is not registered"`; -exports[`Client should call remote random function 1`] = `undefined`; +exports[`Client should call remote random function 1`] = `"Function testrpc is not registered"`; -exports[`Client should not be able to register different function type 1`] = `undefined`; +exports[`Client should not be able to register different function type 1`] = `"Can't register a new function under the testrpc with this invoke value."`; -exports[`Client should not be able to register different function type 2`] = `undefined`; +exports[`Client should not be able to register different function type 2`] = `"Function testrpc already exists"`; + +exports[`Client should not be able to register different function type 3`] = `"Function testrpc is not registered"`; diff --git a/src/client.js b/src/client.js index 051890a..a5ea6d8 100644 --- a/src/client.js +++ b/src/client.js @@ -105,6 +105,7 @@ class Wire { */ async register(name, callback, { invoke = 'single' } = {}) { // Add to locally registered callback + this.registeredRPC[name] = callback; await this._callServerRPC('register', { @@ -114,8 +115,10 @@ class Wire { // Return unregister callback const unregisterCallback = () => { - delete this.registeredRPC[name]; - return this._callServerRPC('unregister', { name }); + if (this.registeredRPC[name] === callback) { + delete this.registeredRPC[name]; + return this._callServerRPC('unregister', { name }); + } }; this.toUnregister.push(unregisterCallback); diff --git a/src/client.test.js b/src/client.test.js index 9ba2141..988cc62 100644 --- a/src/client.test.js +++ b/src/client.test.js @@ -243,7 +243,7 @@ describe('Client', () => { retry(() => room3.call('testrpc')) .withTimeout(1000) .until((result) => expect(result).toEqual({})) - ).rejects.toThrowErrorMatchingSnapshot(); + ).rejects.toMatchSnapshot(); }); it('should call remote last function', async () => { @@ -292,7 +292,7 @@ describe('Client', () => { retry(() => room3.call('testrpc')) .withTimeout(1000) .until((result) => expect(result).toEqual({})) - ).rejects.toThrowErrorMatchingSnapshot(); + ).rejects.toMatchSnapshot(); }); it('should call remote random function', async () => { @@ -341,7 +341,7 @@ describe('Client', () => { retry(() => room3.call('testrpc')) .withTimeout(1000) .until((result) => expect(result).toEqual({})) - ).rejects.toThrowErrorMatchingSnapshot(); + ).rejects.toMatchSnapshot(); }); it('should not be able to register different function type', async () => { @@ -365,7 +365,7 @@ describe('Client', () => { }, { invoke: 'first' } ) - ).rejects.toThrowErrorMatchingSnapshot(); + ).rejects.toMatchSnapshot(); await unregister1(); @@ -377,10 +377,33 @@ describe('Client', () => { expect(result).toEqual({ answer: 46 }); await expect( - room1.register('testrpc', (params) => { + room2.register('testrpc', (params) => { return { answer: 47 }; }) - ).rejects.toThrowErrorMatchingSnapshot(); + ).rejects.toMatchSnapshot(); + + // We should be able to replace a single RPC from the registerer + const unregister2 = await room1.register('testrpc', (params) => { + return { answer: 47 }; + }); + + result = await room3.call('testrpc'); + expect(result).toEqual({ answer: 47 }); + + const unregister3 = await room1.register('testrpc', (params) => { + return { answer: 48 }; + }); + + // If we unregister after the function has been replaced it shouldn't unregister + // the existing function + await unregister2(); + + result = await room3.call('testrpc'); + expect(result).toEqual({ answer: 48 }); + + await unregister3(); + + await expect(room3.call('testrpc')).rejects.toMatchSnapshot(); }); it('should call onMaster callback on leave and disconnect', async () => { diff --git a/src/server.js b/src/server.js index 8727e1f..6253635 100644 --- a/src/server.js +++ b/src/server.js @@ -56,6 +56,7 @@ export const handleWire = ( */ const register = ({ name, invoke = 'single' }) => { const existingInvoke = rooms[roomName].rpc[name]?.invoke; + const existingCallbacks = rooms[roomName].rpc[name]?.callbacks || []; if (existingInvoke && invoke !== existingInvoke) { throw new Error( @@ -63,8 +64,9 @@ export const handleWire = ( ); } if ( - existingInvoke == 'single' && - rooms[roomName].rpc[name].callbacks.length >= 1 + existingInvoke === 'single' && + existingCallbacks.length >= 1 && + existingCallbacks[0] !== registeredRPCs[name] ) { throw new Error(`Function ${name} already exists`); }