Skip to content

Commit 2607d0a

Browse files
committedDec 26, 2020
fix: Fix resubscription for events
1 parent b5a55ae commit 2607d0a

File tree

4 files changed

+43
-43
lines changed

4 files changed

+43
-43
lines changed
 

‎.eslintignore

-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
examples/*
2-
src/generator/*
3-
src/musicservices/*
42
tests/helpers/legacy-helpers.js

‎src/musicservices/smapi-client.ts

+39-38
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import ArrayHelper from '../helpers/array-helper';
1717
* @param {string} householdId HouseholdId is used from authentication, take from DevicePropertiesService.GetHouseholdID().CurrentHouseholdID
1818
* @param {string} key private key is used for authentication (not sure how to fetch this from sonos)
1919
* @param {string} authToken authToken is used for authentication (not sure how to fetch from sonos)
20-
*
20+
*
2121
* @export
2222
* @interface SmapiClientOptions
2323
*/
@@ -31,10 +31,10 @@ export interface SmapiClientOptions {
3131
householdId?: string;
3232
key?: string;
3333
authToken?: string;
34-
saveNewAccount?: saveNemAccountHandler;
34+
saveNewAccount?: SaveNemAccountHandler;
3535
}
3636

37-
declare type saveNemAccountHandler = (serviceId: number, key: string, token: string) => void;
37+
declare type SaveNemAccountHandler = (serviceId: number, key: string, token: string) => void;
3838

3939
export interface MediaList {
4040
index: number;
@@ -100,12 +100,12 @@ export enum SmapiClientErrors {
100100
* @class SmapiClient
101101
*/
102102
export class SmapiClient {
103-
104103
private readonly options: SmapiClientOptions;
105104

106105
private debugger?: Debugger;
107106

108107
private key?: string;
108+
109109
private authToken?: string;
110110

111111
protected get debug(): Debugger {
@@ -143,9 +143,9 @@ export class SmapiClient {
143143
*/
144144
public async GetAppLink(): Promise<AppLinkResponse> {
145145
return await this.SoapRequestWithBody<any, AppLinkResponse>('getAppLink',
146-
{
147-
householdId: this.getHouseholdIdOrThrow()
148-
});
146+
{
147+
householdId: this.getHouseholdIdOrThrow(),
148+
});
149149
}
150150

151151
/**
@@ -157,12 +157,12 @@ export class SmapiClient {
157157
*/
158158
public async GetDeviceAuthToken(linkCode: string): Promise<DeviceAuthResponse> {
159159
return await this.SoapRequestWithBody<any, DeviceAuthResponse>('getDeviceAuthToken',
160-
{
161-
householdId: this.getHouseholdIdOrThrow(),
162-
linkCode: linkCode,
163-
linkDeviceId: this.options.deviceId
164-
})
165-
.then(async data => {
160+
{
161+
householdId: this.getHouseholdIdOrThrow(),
162+
linkCode,
163+
linkDeviceId: this.options.deviceId,
164+
})
165+
.then(async (data) => {
166166
if (this.options.saveNewAccount !== undefined) { // Save the account by the library provided way.
167167
await this.options.saveNewAccount(this.options.serviceId, data.privateKey, data.authToken);
168168
}
@@ -172,9 +172,9 @@ export class SmapiClient {
172172

173173
public async GetDeviceLinkCode(): Promise<DeviceLink> {
174174
return await this.SoapRequestWithBody<any, DeviceLink>('getDeviceLinkCode',
175-
{
176-
householdId: this.getHouseholdIdOrThrow()
177-
});
175+
{
176+
householdId: this.getHouseholdIdOrThrow(),
177+
});
178178
}
179179

180180
/**
@@ -219,11 +219,13 @@ export class SmapiClient {
219219

220220
if (input.mediaMetadata !== undefined) {
221221
result.mediaMetadata = ArrayHelper.ForceArray<MediaMetadata>(input.mediaMetadata);
222-
result.mediaMetadata.forEach((m) => {
223-
if (m.itemType === 'stream') m.trackUri = `x-sonosapi-stream:${m.id}?sid=${this.options.serviceId}`;
222+
result.mediaMetadata = result.mediaMetadata.map((m) => {
223+
const withTrack = m;
224+
if (m.itemType === 'stream') withTrack.trackUri = `x-sonosapi-stream:${m.id}?sid=${this.options.serviceId}`;
225+
return withTrack;
224226
});
225227
}
226-
228+
227229
if (input.mediaCollection !== undefined) {
228230
result.mediaCollection = ArrayHelper.ForceArray<MediaItem>(input.mediaCollection);
229231
}
@@ -232,34 +234,31 @@ export class SmapiClient {
232234
}
233235

234236
// #region Private server stuff
235-
private async SoapRequest<TResponse>(action: string, isRetryWithNewCredentials: boolean = false): Promise<TResponse> {
237+
private async SoapRequest<TResponse>(action: string, isRetryWithNewCredentials = false): Promise<TResponse> {
236238
this.debug('%s()', action);
237239
try {
238240
return await this.handleRequestAndParseResponse<TResponse>(this.generateRequest<undefined>(action, undefined), action);
239-
}
240-
catch(err) {
241-
if(err instanceof SmapiError && err.Fault.faultstring == SmapiClientErrors.TokenRefreshRequiredError && !isRetryWithNewCredentials) {
241+
} catch (err) {
242+
if (err instanceof SmapiError && (err.Fault as any).faultstring === SmapiClientErrors.TokenRefreshRequiredError && !isRetryWithNewCredentials) {
242243
return await this.SoapRequest<TResponse>(action, true);
243244
}
244245
throw err;
245246
}
246247
}
247248

248-
private async SoapRequestWithBody<TBody, TResponse>(action: string, body: TBody, isRetryWithNewCredentials: boolean = false): Promise<TResponse> {
249+
private async SoapRequestWithBody<TBody, TResponse>(action: string, body: TBody, isRetryWithNewCredentials = false): Promise<TResponse> {
249250
this.debug('%s(%o)', action, body);
250251
try {
251252
return await this.handleRequestAndParseResponse<TResponse>(this.generateRequest<TBody>(action, body), action);
252-
}
253-
catch(err) {
254-
if(err instanceof SmapiError && err.Fault.faultstring == SmapiClientErrors.TokenRefreshRequiredError && !isRetryWithNewCredentials) {
253+
} catch (err) {
254+
if (err instanceof SmapiError && (err.Fault as any).faultstring === SmapiClientErrors.TokenRefreshRequiredError && !isRetryWithNewCredentials) {
255255
return await this.SoapRequestWithBody<TBody, TResponse>(action, body, true);
256256
}
257257
throw err;
258258
}
259-
260259
}
261260

262-
private async handleRequestAndParseResponse<TResponse>(request: Request, action: string, isRetryWithNewCredentials: boolean = false): Promise<TResponse> {
261+
private async handleRequestAndParseResponse<TResponse>(request: Request, action: string, isRetryWithNewCredentials = false): Promise<TResponse> {
263262
const response = await fetch(request);
264263
// if (!response.ok) {
265264
// this.debug('handleRequest error %d %s', response.status, response.statusText);
@@ -273,7 +272,7 @@ export class SmapiClient {
273272
}
274273
if (typeof result.Envelope.Body.Fault !== 'undefined') {
275274
const fault = result.Envelope.Body.Fault;
276-
if(!isRetryWithNewCredentials && fault.faultstring === 'tokenRefreshRequired') {
275+
if (!isRetryWithNewCredentials && fault.faultstring === 'tokenRefreshRequired') {
277276
this.debug('Saving new tokens');
278277
// Set new tokens, maybe result in event?
279278
this.authToken = fault.detail?.refreshAuthTokenResult?.authToken;
@@ -284,12 +283,12 @@ export class SmapiClient {
284283
if (this.options.saveNewAccount !== undefined && this.key && this.authToken) {
285284
this.options.saveNewAccount(this.options.serviceId, this.key, this.authToken);
286285
}
287-
}
286+
}
288287
this.debug('Soap error %s %o', action, fault);
289288
throw new SmapiError(this.options.name, action, fault);
290289
}
291290
this.debug('handleRequest success');
292-
const body = result.Envelope.Body[`${action}Response`]
291+
const body = result.Envelope.Body[`${action}Response`];
293292
return body[`${action}Result`] ?? body;
294293
}
295294

@@ -323,25 +322,27 @@ export class SmapiClient {
323322
private generateSoapBody<TBody>(action: string, body: TBody): string {
324323
let messageBody = `<soap:Body>\r\n<s:${action}>`;
325324
if (body) {
326-
for (const [key, value] of Object.entries(body)) {
325+
Object.entries(body).forEach((v) => {
326+
// Deconstruct v into key and value.
327+
const [key, value] = v;
327328
if (typeof value === 'boolean') messageBody += `<s:${key}>${value === true ? '1' : '0'}</s:${key}>`;
328329
else messageBody += `<s:${key}>${value}</s:${key}>`;
329-
}
330+
});
330331
}
331332
messageBody += `</s:${action}>\r\n</soap:Body>`;
332333
return messageBody;
333334
}
334335

335336
private getHouseholdIdOrThrow(): string {
336-
if(this.options.householdId === undefined){
337-
throw new Error("options.householdId is undefined, fetch from DevicePropertiesService.GetHouseholdID");
337+
if (this.options.householdId === undefined) {
338+
throw new Error('options.householdId is undefined, fetch from DevicePropertiesService.GetHouseholdID');
338339
}
339340
return this.options.householdId;
340341
}
341342

342343
private generateCredentialHeader(options: { deviceId?: string; deviceCert?: string; zonePlayerId?: string;} = {}): string {
343-
let header = ' <s:credentials>\r\n'
344-
344+
let header = ' <s:credentials>\r\n';
345+
345346
if (options.deviceId !== undefined) {
346347
header += ` <s:deviceId>${options.deviceId}</s:deviceId>\r\n`;
347348
}

‎src/musicservices/smapi-error.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @extends {Error}
77
*/
88
export default class SmapiError extends Error {
9-
constructor(public readonly ServiceName: string, public readonly Action: string, public readonly Fault: any) {
9+
constructor(public readonly ServiceName: string, public readonly Action: string, public readonly Fault: unknown) {
1010
super(`Sonos music API error for ${Action} ${ServiceName}`);
1111
this.name = 'SmapiError';
1212
}

‎src/sonos-device.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,9 @@ export default class SonosDevice extends SonosDeviceBase {
542542
this.debug('Listener removed');
543543
const events = this.Events.eventNames().filter((e) => e !== 'removeListener' && e !== 'newListener');
544544
if (events.length === 0) {
545-
this.AVTransportService.Events.removeListener(ServiceEvents.LastChange, this.boundHandleAvTransportEvent);
546-
this.RenderingControlService.Events.removeListener(ServiceEvents.LastChange, this.boundHandleRenderingControlEvent);
545+
this.AVTransportService.Events.removeListener(ServiceEvents.ServiceEvent, this.boundHandleAvTransportEvent);
546+
this.RenderingControlService.Events.removeListener(ServiceEvents.ServiceEvent, this.boundHandleRenderingControlEvent);
547+
this.isSubscribed = false;
547548
}
548549
});
549550
this.events.on('newListener', () => {

0 commit comments

Comments
 (0)
Please sign in to comment.