From ae7f7c42a135a6fe30647f256345eb81408027e2 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 17:29:29 -0500 Subject: [PATCH 1/8] Add type definitions for node-ssdp --- types/node-ssdp/index.d.ts | 140 +++++++++++++++++++++++++++++ types/node-ssdp/node-ssdp-tests.ts | 73 +++++++++++++++ types/node-ssdp/tsconfig.json | 24 +++++ types/node-ssdp/tslint.json | 3 + 4 files changed, 240 insertions(+) create mode 100644 types/node-ssdp/index.d.ts create mode 100644 types/node-ssdp/node-ssdp-tests.ts create mode 100644 types/node-ssdp/tsconfig.json create mode 100644 types/node-ssdp/tslint.json diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts new file mode 100644 index 0000000000..40e874039e --- /dev/null +++ b/types/node-ssdp/index.d.ts @@ -0,0 +1,140 @@ +// Type definitions for node-ssdp v3.3.0 +// Project: https://github.com/diversario/node-ssdp +// Definitions by: Olivia Trewin +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +import * as events from 'events'; + +export interface SsdpHeaders { + [key: string]: string | number | boolean | null | undefined | symbol +} + +export interface SsdpOptions { + /** + * SSDP signature + * @default 'node.js/NODE_VERSION UPnP/1.1 node-ssdp/PACKAGE_VERSION' + */ + ssdpSig?: string; + /** + * SSDP multicast group + * @default '239.255.255.250' + */ + ssdpIp?: string; + /** + * Multicast TTL + * @default 4 + */ + ssdpTtl?: number; + /** + * SSDP port + * @default 1900 + */ + ssdpPort?: number; + /** Path to SSDP description file */ + description?: string; + /** Additional headers */ + headers?: SsdpHeaders; +} + +export interface ClientOptions extends SsdpOptions { + /** List of interfaces to explicitly bind. By default, bind to all available interfaces. */ + interfaces?: string[]; + /** Bind sockets to each discovered interface explicitly instead of relying on the system. Might help with issues with multiple NICs. */ + explicitSocketBind?: boolean; + /** A logger function to use instead of the default. The first argument to the function can contain a format string. */ + customLogger?: (format?: string) => void; + /** + * When true socket.bind() will reuse the address, even if another process has already bound a socket on it. + * @default true + */ + reuseAddr?: boolean; +} + +export interface ServiceDescriptionLocation { + /** + * Location protocol. + * @default 'http://' + */ + protocol?: string; + /** + * Location port. + */ + port: number; + /** + * Location path. + */ + path: string; +} + +export interface ServerOptions extends ClientOptions { + /** + * URL pointing to description of your service, or a function that returns that URL. + * For cases where there are multiple network interfaces or the IP of the host isn't known in advance, it's possible to specify location as an object. Host will be set to the IP of the responding interface. + */ + location?: string | ServiceDescriptionLocation; + /** + * SSDP Unique Device Name + * @default 'uuid:f40c2981-7329-40b7-8b04-27f187aecfb5' + */ + udn?: string; + /** + * Allow wildcards in M-SEARCH packets (non-standard) + * @default false + */ + allowWildcards?: boolean; + /** + * When true the SSDP server will not advertise the root device (i.e. the bare UDN). In some scenarios, this advertisement is not needed. + * @default false + */ + suppressRootDeviceAdvertisements?: boolean; + /** + * Interval at which to send out advertisement (ms) + * @default 10000 + */ + adInterval?: number; + /** + * Packet TTL + * @default 1800 + */ + ttl?: number; +} + +export abstract class Base extends events.EventEmitter { + constructor (opts: SsdpOptions); + + addUSN (device: string): void; +} + +export class Client extends Base { + constructor (opts: ClientOptions); + + /** + * Start the listener for multicast notifications from SSDP devices + * @param {(error: any) => void?} cb callback to socket.bind + * @returns {Promise} promise when socket.bind is ready + */ + start (cb?: (error: any) => void): Promise; + /** + * Close UDP socket. + */ + stop (): void; + search (serviceType: string): void | Promise; +} + +export class Server extends Base { + constructor (opts: ServerOptions); + + /** + * Binds UDP socket to an interface/port and starts advertising. + * @param {(error: any) => void?} cb callback to socket.bind + * @returns {void | Proimse} promise when socket.bind is ready + */ + start (cb?: (error: any) => void): void | Promise; + /** + * Advertise shutdown and close UDP socket. + */ + stop (): void; + advertise (alive?: boolean): void; +} diff --git a/types/node-ssdp/node-ssdp-tests.ts b/types/node-ssdp/node-ssdp-tests.ts new file mode 100644 index 0000000000..5cdff359f1 --- /dev/null +++ b/types/node-ssdp/node-ssdp-tests.ts @@ -0,0 +1,73 @@ +import { Client, Server } from 'node-ssdp'; + +// Taken from https://github.com/diversario/node-ssdp#usage---client + +const client = new Client({ + interfaces: [], + customLogger: format => {}, + explicitSocketBind: true, + reuseAddr: true, + ssdpPort: 0, + description: '', + headers: { + key: 'value' + }, + ssdpIp: '', + ssdpSig: '', + ssdpTtl: 0 +}); + +client.on('response', function (headers, statusCode, rinfo) { + console.log('Got a response to an m-search.'); +}); + +// search for a service type +client.search('urn:schemas-upnp-org:service:ContentDirectory:1'); + +// Or get a list of all services on the network + +client.search('ssdp:all'); + +const server = new Server({ + interfaces: [], + customLogger: format => {}, + explicitSocketBind: true, + reuseAddr:true, + ssdpPort: 0, + location: { + protocol: 'http://', + path: '', + port: 80 + }, + suppressRootDeviceAdvertisements: true, + adInterval: 0, + allowWildcards: false, + description: '', + headers: { + key: 'value' + }, + ssdpIp: '', + ssdpSig: '', + ssdpTtl: 0, + ttl: 0, + udn: '' +}); + +// Taken from https://github.com/diversario/node-ssdp#usage---server + +server.addUSN('upnp:rootdevice'); +server.addUSN('urn:schemas-upnp-org:device:MediaServer:1'); +server.addUSN('urn:schemas-upnp-org:service:ContentDirectory:1'); +server.addUSN('urn:schemas-upnp-org:service:ConnectionManager:1'); + +server.on('advertise-alive', function (headers) { + // Expire old devices from your cache. + // Register advertising device somewhere (as designated in http headers heads) +}); + +server.on('advertise-bye', function (headers) { + // Remove specified device from cache. +}); + +// start the server +server.start(); diff --git a/types/node-ssdp/tsconfig.json b/types/node-ssdp/tsconfig.json new file mode 100644 index 0000000000..6b7174caf2 --- /dev/null +++ b/types/node-ssdp/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "node-ssdp-tests.ts" + ] +} \ No newline at end of file diff --git a/types/node-ssdp/tslint.json b/types/node-ssdp/tslint.json new file mode 100644 index 0000000000..d88586e5bd --- /dev/null +++ b/types/node-ssdp/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} From 843bcce71803861b68e25ccfdb794484fc8f57c5 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 17:36:36 -0500 Subject: [PATCH 2/8] Made changes to fix linting errors --- types/node-ssdp/index.d.ts | 37 +++++++++++++++--------------- types/node-ssdp/node-ssdp-tests.ts | 8 +++---- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index 40e874039e..1ba2022723 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for node-ssdp v3.3.0 +// Type definitions for node-ssdp 3.3 // Project: https://github.com/diversario/node-ssdp // Definitions by: Olivia Trewin // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped @@ -8,7 +8,7 @@ import * as events from 'events'; export interface SsdpHeaders { - [key: string]: string | number | boolean | null | undefined | symbol + [key: string]: string | number | boolean | null | undefined | symbol; } export interface SsdpOptions { @@ -71,7 +71,8 @@ export interface ServiceDescriptionLocation { export interface ServerOptions extends ClientOptions { /** * URL pointing to description of your service, or a function that returns that URL. - * For cases where there are multiple network interfaces or the IP of the host isn't known in advance, it's possible to specify location as an object. Host will be set to the IP of the responding interface. + * For cases where there are multiple network interfaces or the IP of the host isn't known in advance, + * it's possible to specify location as an object. Host will be set to the IP of the responding interface. */ location?: string | ServiceDescriptionLocation; /** @@ -92,7 +93,7 @@ export interface ServerOptions extends ClientOptions { /** * Interval at which to send out advertisement (ms) * @default 10000 - */ + */ adInterval?: number; /** * Packet TTL @@ -102,39 +103,39 @@ export interface ServerOptions extends ClientOptions { } export abstract class Base extends events.EventEmitter { - constructor (opts: SsdpOptions); + constructor(opts: SsdpOptions); - addUSN (device: string): void; + addUSN(device: string): void; } export class Client extends Base { - constructor (opts: ClientOptions); + constructor(opts: ClientOptions); /** * Start the listener for multicast notifications from SSDP devices - * @param {(error: any) => void?} cb callback to socket.bind - * @returns {Promise} promise when socket.bind is ready + * @param cb callback to socket.bind + * @returns promise when socket.bind is ready */ - start (cb?: (error: any) => void): Promise; + start(cb?: (error: any) => void): Promise; /** * Close UDP socket. */ - stop (): void; - search (serviceType: string): void | Promise; + stop(): void; + search(serviceType: string): void | Promise; } export class Server extends Base { - constructor (opts: ServerOptions); + constructor(opts: ServerOptions); /** * Binds UDP socket to an interface/port and starts advertising. - * @param {(error: any) => void?} cb callback to socket.bind - * @returns {void | Proimse} promise when socket.bind is ready + * @param cb callback to socket.bind + * @returns promise when socket.bind is ready */ - start (cb?: (error: any) => void): void | Promise; + start(cb?: (error: any) => void): void | Promise; /** * Advertise shutdown and close UDP socket. */ - stop (): void; - advertise (alive?: boolean): void; + stop(): void; + advertise(alive?: boolean): void; } diff --git a/types/node-ssdp/node-ssdp-tests.ts b/types/node-ssdp/node-ssdp-tests.ts index 5cdff359f1..dbd2536e78 100644 --- a/types/node-ssdp/node-ssdp-tests.ts +++ b/types/node-ssdp/node-ssdp-tests.ts @@ -17,7 +17,7 @@ const client = new Client({ ssdpTtl: 0 }); -client.on('response', function (headers, statusCode, rinfo) { +client.on('response', (headers, statusCode, rinfo) => { console.log('Got a response to an m-search.'); }); @@ -32,7 +32,7 @@ const server = new Server({ interfaces: [], customLogger: format => {}, explicitSocketBind: true, - reuseAddr:true, + reuseAddr: true, ssdpPort: 0, location: { protocol: 'http://', @@ -60,12 +60,12 @@ server.addUSN('urn:schemas-upnp-org:device:MediaServer:1'); server.addUSN('urn:schemas-upnp-org:service:ContentDirectory:1'); server.addUSN('urn:schemas-upnp-org:service:ConnectionManager:1'); -server.on('advertise-alive', function (headers) { +server.on('advertise-alive', (headers) => { // Expire old devices from your cache. // Register advertising device somewhere (as designated in http headers heads) }); -server.on('advertise-bye', function (headers) { +server.on('advertise-bye', (headers) => { // Remove specified device from cache. }); From fa8e0df16ff7ebe2586ef823350329fa0f3fa7b7 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 17:57:44 -0500 Subject: [PATCH 3/8] Options argument should be optional --- types/node-ssdp/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index 1ba2022723..62d2c7c663 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -103,13 +103,13 @@ export interface ServerOptions extends ClientOptions { } export abstract class Base extends events.EventEmitter { - constructor(opts: SsdpOptions); + constructor(opts?: SsdpOptions); addUSN(device: string): void; } export class Client extends Base { - constructor(opts: ClientOptions); + constructor(opts?: ClientOptions); /** * Start the listener for multicast notifications from SSDP devices @@ -125,7 +125,7 @@ export class Client extends Base { } export class Server extends Base { - constructor(opts: ServerOptions); + constructor(opts?: ServerOptions); /** * Binds UDP socket to an interface/port and starts advertising. From 321b93721e683c5ef1f40a5776c085eec2f50ce7 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 18:55:47 -0500 Subject: [PATCH 4/8] Event types Added type information to 'on' and 'once' so that event listeners have real type information --- types/node-ssdp/index.d.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index 62d2c7c663..01025cefb4 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -6,8 +6,18 @@ /// import * as events from 'events'; +import * as dgram from 'dgram'; export interface SsdpHeaders { + /** + * Available while handling an SSDP response. A URL where the service description can be found. + */ + LOCATION?: string; + ST?: string; + /** + * Available while handling an SSDP response. The Unique Service Name (USN) of the responding device. + */ + USN?: string; [key: string]: string | number | boolean | null | undefined | symbol; } @@ -122,6 +132,10 @@ export class Client extends Base { */ stop(): void; search(serviceType: string): void | Promise; + + on(event: 'response', listener: (headers: SsdpHeaders, statusCode: number, rinfo: dgram.RemoteInfo) => void): this; + once(event: 'response', listener: (headers: SsdpHeaders, statusCode: number, rinfo: dgram.RemoteInfo) => void): this; + emit(event: 'response', headers: SsdpHeaders, statusCode: number, rinfo: dgram.RemoteInfo): boolean; } export class Server extends Base { @@ -138,4 +152,8 @@ export class Server extends Base { */ stop(): void; advertise(alive?: boolean): void; + + on(event: 'advertise-alive' | 'advertise-bye', listener: (headers: SsdpHeaders) => void): this; + once(event: 'advertise-alive' | 'advertise-bye', listener: (headers: SsdpHeaders) => void): this; + emit(event: 'advertise-alive' | 'advertise-bye', headers: SsdpHeaders): boolean; } From 2d5a526375eebe71d02dcb7eb898cf71eec1d131 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 19:17:22 -0500 Subject: [PATCH 5/8] Used dts-gen to generate --- types/node-ssdp/index.d.ts | 2 +- types/node-ssdp/tsconfig.json | 3 +-- types/node-ssdp/tslint.json | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index 01025cefb4..7818304364 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -1,5 +1,5 @@ // Type definitions for node-ssdp 3.3 -// Project: https://github.com/diversario/node-ssdp +// Project: https://github.com/diversario/node-ssdp#readme // Definitions by: Olivia Trewin // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped diff --git a/types/node-ssdp/tsconfig.json b/types/node-ssdp/tsconfig.json index 6b7174caf2..78d299d117 100644 --- a/types/node-ssdp/tsconfig.json +++ b/types/node-ssdp/tsconfig.json @@ -8,7 +8,6 @@ "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, - "strictFunctionTypes": true, "baseUrl": "../", "typeRoots": [ "../" @@ -21,4 +20,4 @@ "index.d.ts", "node-ssdp-tests.ts" ] -} \ No newline at end of file +} diff --git a/types/node-ssdp/tslint.json b/types/node-ssdp/tslint.json index d88586e5bd..3db14f85ea 100644 --- a/types/node-ssdp/tslint.json +++ b/types/node-ssdp/tslint.json @@ -1,3 +1 @@ -{ - "extends": "dtslint/dt.json" -} +{ "extends": "dtslint/dt.json" } From 51212aab94fa651ffd50db7297f7e03f82d4a5f5 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 19:18:21 -0500 Subject: [PATCH 6/8] Replace 'strictFunctionTypes' --- types/node-ssdp/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/types/node-ssdp/tsconfig.json b/types/node-ssdp/tsconfig.json index 78d299d117..a85ee0905f 100644 --- a/types/node-ssdp/tsconfig.json +++ b/types/node-ssdp/tsconfig.json @@ -8,6 +8,7 @@ "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, + "strictFunctionTypes": true, "baseUrl": "../", "typeRoots": [ "../" From 501576defc99c45922e28302d0f7534adf868f09 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 19:48:33 -0500 Subject: [PATCH 7/8] Corrected 'customLogger' definition --- types/node-ssdp/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index 7818304364..b460e68f71 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -45,7 +45,9 @@ export interface SsdpOptions { /** Path to SSDP description file */ description?: string; /** Additional headers */ - headers?: SsdpHeaders; + headers?: SsdpHeaders; + /** A logger function to use instead of the default. The first argument to the function can contain a format string. */ + customLogger?: (format: string, ...args: any[]) => void; } export interface ClientOptions extends SsdpOptions { @@ -53,8 +55,6 @@ export interface ClientOptions extends SsdpOptions { interfaces?: string[]; /** Bind sockets to each discovered interface explicitly instead of relying on the system. Might help with issues with multiple NICs. */ explicitSocketBind?: boolean; - /** A logger function to use instead of the default. The first argument to the function can contain a format string. */ - customLogger?: (format?: string) => void; /** * When true socket.bind() will reuse the address, even if another process has already bound a socket on it. * @default true From ab582a400bea826f1ef4c1c64d67ade215a6e4e8 Mon Sep 17 00:00:00 2001 From: Olivia Trewin Date: Fri, 8 Jun 2018 20:00:18 -0500 Subject: [PATCH 8/8] Added more specific types to error callbacks --- types/node-ssdp/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/node-ssdp/index.d.ts b/types/node-ssdp/index.d.ts index b460e68f71..3ae4da7643 100644 --- a/types/node-ssdp/index.d.ts +++ b/types/node-ssdp/index.d.ts @@ -126,7 +126,7 @@ export class Client extends Base { * @param cb callback to socket.bind * @returns promise when socket.bind is ready */ - start(cb?: (error: any) => void): Promise; + start(cb?: (error: Error) => void): Promise; /** * Close UDP socket. */ @@ -146,7 +146,7 @@ export class Server extends Base { * @param cb callback to socket.bind * @returns promise when socket.bind is ready */ - start(cb?: (error: any) => void): void | Promise; + start(cb?: (error: Error) => void): void | Promise; /** * Advertise shutdown and close UDP socket. */