Skip to content

Commit 6c00cc4

Browse files
committed
Fix duplicate devices listed in quick-pick on Windows
The bonjour backend used on Windows was not properly filtering duplicate notifications on the same network adapter properly, resulting in each device being listed more than once. The logic for ignoring duplicates is similar to the macOS (dnssd) backend. Also, there was a bug introduced by switching to === that caused the network adapter name to not be shown in the quick-pick on Windows too (because bClient.iface was string instead of number). This was fixed as a side-effect of fixing the duplicates.
1 parent b9f4bd0 commit 6c00cc4

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
55

66
## Unreleased
77
### Fixed
8+
- Duplicate listed devices in quick-pick on Windows
89
- SSH terminal not working
910

1011
## 1.0.0 - 2019-01-31

src/dnssd/bonjour.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,29 @@ class BonjourClient extends events.EventEmitter implements dnssd.Client {
3939
// interface (actually, each address of each interface, which could be
4040
// more than one).
4141
private updateInterfaces() {
42-
const newAddresses = new Array<string>();
42+
type Address = { iface: number, address: string };
43+
const newAddresses = new Array<Address>();
4344
const ifaces = os.networkInterfaces();
4445
for (let i in ifaces) {
46+
// on Windows, only the local link address has a scopeid that matches
47+
// the index of the network interface.
48+
const localLinkAddr = ifaces[i].find(v => v.address.startsWith('fe80:'));
49+
if (!localLinkAddr) {
50+
continue;
51+
}
52+
const ifaceIndex = (<os.NetworkInterfaceInfoIPv6>localLinkAddr).scopeid;
53+
4554
// only supporting IPv6 for now
46-
const addresses = ifaces[i].filter(v => v.family === 'IPv6').map(v =>
55+
const addresses = ifaces[i].filter(v => v.internal === false && v.family === 'IPv6').map(v =>
4756
`${v.address}%${process.platform === 'win32' ? (<os.NetworkInterfaceInfoIPv6>v).scopeid : i}`);
48-
newAddresses.push(...addresses);
57+
newAddresses.push(...addresses.map(v => <Address>{ iface: ifaceIndex, address: v }));
4958
}
50-
const added = newAddresses.filter(a => this.ifaceAddresses.indexOf(a) === -1);
51-
const removed = this.ifaceAddresses.filter(a => newAddresses.indexOf(a) === -1);
59+
const added = newAddresses.filter(a => this.ifaceAddresses.indexOf(a.address) === -1);
60+
const removed = this.ifaceAddresses.filter(a => newAddresses.findIndex(v => v.address === a) === -1);
5261
if (added.length) {
5362
for (const a of added) {
54-
this.ifaceAddresses.push(a);
55-
this.createClient(a);
63+
this.ifaceAddresses.push(a.address);
64+
this.createClient(a.iface, a.address);
5665
}
5766
}
5867
if (removed.length) {
@@ -66,17 +75,18 @@ class BonjourClient extends events.EventEmitter implements dnssd.Client {
6675

6776
/**
6877
* Asyncronusly create an new bonjour.Bonjour client object
78+
* @param ifaceIndex the index of the network interface
6979
* @param ifaceAddress the IP address
7080
*/
71-
private createClient(ifaceAddress: string): void {
81+
private createClient(ifaceIndex: number, ifaceAddress: string): void {
7282
// work around bonjour issue where error is not handled
7383
new Promise<bonjour.Bonjour>((resolve, reject) => {
7484
const bClient = bonjour(<any> {
7585
type: 'udp6',
7686
ip: 'ff02::fb',
7787
interface: ifaceAddress
7888
});
79-
(<any>bClient)['iface'] = ifaceAddress.split('%')[1];
89+
(<any>bClient)['iface'] = ifaceIndex;
8090
(<any> bClient)._server.mdns.on('ready', () => resolve(bClient));
8191
(<any> bClient)._server.mdns.on('error', (err: any) => reject(err));
8292
}).then(bClient => {
@@ -94,7 +104,7 @@ class BonjourClient extends events.EventEmitter implements dnssd.Client {
94104
// we are bound or the interface goes away.
95105
setTimeout(() => {
96106
if (this.ifaceAddresses.indexOf(ifaceAddress) >= 0) {
97-
this.createClient(ifaceAddress);
107+
this.createClient(ifaceIndex, ifaceAddress);
98108
}
99109
}, 500);
100110
}
@@ -143,6 +153,15 @@ class BonjourBrowser extends events.EventEmitter implements dnssd.Browser {
143153
const services = new Array<BonjourService>();
144154
browser.on('up', s => {
145155
(<any>s)['iface'] = (<any>bClient)['iface'];
156+
for (const b of this.browsers) {
157+
for (const bs of b.services) {
158+
const bss = bs.bService;
159+
if ((<any>s)['iface'] === (<any>bss)['iface'] && s.name === bs.name && s.type === bss.type && s.fqdn === bss.fqdn.replace(/\.$/, '')) {
160+
// ignore duplicates
161+
return;
162+
}
163+
}
164+
}
146165
const service = new BonjourService(s);
147166
services.push(service);
148167
this.emit('added', service, false);

0 commit comments

Comments
 (0)