From 2e20eeb830029f58a294cf19c72502ebcf930eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Garapich?= Date: Wed, 8 Jun 2022 00:05:18 +0200 Subject: [PATCH 1/2] feat(*): add ChannelUpdate event --- src/channel-manager.ts | 11 +++++++- src/channel.ts | 63 +++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/channel-manager.ts b/src/channel-manager.ts index dd5ea90..78126af 100644 --- a/src/channel-manager.ts +++ b/src/channel-manager.ts @@ -121,7 +121,16 @@ export class ChannelManager { */ this.client.emit(EventNames.channelCreate, channel); } else { - channel.syncState(channelState); + const changes = channel.syncState(channelState); + if (Object.keys(changes).length > 0) { + /** + * Emitted when a channel is updated. + * @event Client#channelUpdate + * @property {Channel} channel The channel that was updated. + * @property {ChannelChanges} changes What changes were made to the channel. + */ + this.client.emit(EventNames.channelUpdate, channel, changes); + } } } diff --git a/src/channel.ts b/src/channel.ts index c22d4b2..70b4a72 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -1,4 +1,5 @@ import { ChannelState } from '@tf2pickup-org/mumble-protocol'; +import { Change } from './change'; import { Client } from './client'; import { createChannel, @@ -15,6 +16,15 @@ import { import { Permissions } from './permissions'; import { User } from './user'; +type ChannelChangeableProps = Pick< + Channel, + 'name' | 'parent' | 'temporary' | 'linkedChannels' +>; + +export type ChannelChanges = { + -readonly [P in keyof ChannelChangeableProps]?: Change; +}; + /** * Represents a single channel. */ @@ -39,26 +49,31 @@ export class Channel { /** * @internal */ - syncState(channelState: ChannelState) { - if (channelState.name !== undefined) { - this.name = channelState.name; - } + syncState(channelState: ChannelState): ChannelChanges { + const changes: ChannelChanges = {}; - if (channelState.parent !== undefined) { - this.parent = channelState.parent; - } + this.syncProperty('name', channelState.name, changes); + this.syncProperty('parent', channelState.parent, changes); + this.syncProperty('temporary', channelState.temporary, changes); + + if (channelState.linksAdd.length + channelState.linksRemove.length > 0) { + changes.linkedChannels = { + previousValue: [...this.linkedChannels], + currentValue: [], + }; + + this.links = [ + ...new Set([ + ...this.links, + ...channelState.links, + ...channelState.linksAdd, + ]), + ].filter(l => !channelState.linksRemove.includes(l)); - if (channelState.temporary !== undefined) { - this.temporary = channelState.temporary; + changes.linkedChannels.currentValue = this.linkedChannels; } - this.links = [ - ...new Set([ - ...this.links, - ...channelState.links, - ...channelState.linksAdd, - ]), - ].filter(l => !channelState.linksRemove.includes(l)); + return changes; } /** @@ -199,4 +214,20 @@ export class Channel { await unlinkChannels(this.client.socket, this.id, targetChannel.id); return this; } + + private syncProperty( + propertyName: R, + newValue: this[R] | undefined, + changes: ChannelChanges, + ) { + if (newValue === undefined) { + return; + } + + (changes[propertyName] as Change) = { + previousValue: this[propertyName], + currentValue: newValue, + }; + this[propertyName] = newValue; + } } From be8ad16e15501acc8c9c13de9eee69ebd7ede2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Garapich?= Date: Mon, 13 Jun 2022 01:44:47 +0200 Subject: [PATCH 2/2] add test --- src/channel.spec.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/channel.spec.ts b/src/channel.spec.ts index 7cbc275..1a3d841 100644 --- a/src/channel.spec.ts +++ b/src/channel.spec.ts @@ -48,26 +48,43 @@ describe('Channel', () => { expect(channel.name).toEqual('FAKE_CHANNEL_NAME'); }); - describe('sync()', () => { + describe('syncState()', () => { let channel: Channel; beforeEach(() => { channel = new Channel( client, - ChannelState.create({ channelId: 0 }) as ChannelState & { + ChannelState.create({ + channelId: 0, + name: 'FAKE_CHANNEL_NAME', + }) as ChannelState & { channelId: number; }, ); }); it('should update name', () => { - channel.syncState(ChannelState.create({ name: 'NEW_CHANNEL_NAME' })); + const changes = channel.syncState( + ChannelState.create({ name: 'NEW_CHANNEL_NAME' }), + ); expect(channel.name).toEqual('NEW_CHANNEL_NAME'); + expect(changes).toEqual({ + name: { + previousValue: 'FAKE_CHANNEL_NAME', + currentValue: 'NEW_CHANNEL_NAME', + }, + }); }); it('should update parent', () => { - channel.syncState(ChannelState.create({ parent: 10 })); + const changes = channel.syncState(ChannelState.create({ parent: 10 })); expect(channel.parent).toEqual(10); + expect(changes).toEqual({ + parent: { + previousValue: undefined, + currentValue: 10, + }, + }); }); });