Skip to content

Commit

Permalink
alexa: fix potential response race
Browse files Browse the repository at this point in the history
  • Loading branch information
koush committed Nov 28, 2023
1 parent 126c489 commit dab5be1
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 43 deletions.
4 changes: 2 additions & 2 deletions plugins/alexa/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/alexa/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@scrypted/alexa",
"version": "0.2.9",
"version": "0.2.10",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
"prescrypted-setup-project": "scrypted-package-json",
Expand Down
72 changes: 32 additions & 40 deletions plugins/alexa/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
if (status === DeviceMixinStatus.Setup)
await this.syncEndpoints();

if (status === DeviceMixinStatus.Setup || status === DeviceMixinStatus.AlreadySetup) {
if (status === DeviceMixinStatus.Setup || status === DeviceMixinStatus.AlreadySetup) {

if (!this.devices.has(eventSource.id)) {
this.devices.set(eventSource.id, eventSource);
Expand Down Expand Up @@ -142,7 +142,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
await this.syncEndpoints();
}

async deviceListen(eventSource: ScryptedDevice | undefined, eventDetails: EventDetails, eventData: any) : Promise<void> {
async deviceListen(eventSource: ScryptedDevice | undefined, eventDetails: EventDetails, eventData: any): Promise<void> {
if (!eventSource)
return;

Expand Down Expand Up @@ -194,14 +194,14 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi

// nothing to report
if (data.context === undefined && data.event.payload === undefined)
return;
return;

data = await this.addAccessToken(data);

await this.postEvent(data);
}

private async addAccessToken(data: any) : Promise<any> {
private async addAccessToken(data: any): Promise<any> {
const accessToken = await this.getAccessToken();

if (data.event === undefined)
Expand Down Expand Up @@ -232,7 +232,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
'api.fe.amazonalexa.com'
];

async getAlexaEndpoint() : Promise<string> {
async getAlexaEndpoint(): Promise<string> {
if (this.storageSettings.values.apiEndpoint)
return this.storageSettings.values.apiEndpoint;

Expand Down Expand Up @@ -276,15 +276,15 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
});
}

async getEndpoints() : Promise<DiscoveryEndpoint[]> {
async getEndpoints(): Promise<DiscoveryEndpoint[]> {
const endpoints: DiscoveryEndpoint[] = [];

for (const id of Object.keys(systemManager.getSystemState())) {
const device = systemManager.getDeviceById(id);

if (!device.mixins?.includes(this.id))
continue;

const endpoint = await this.getEndpointForDevice(device);
if (endpoint)
endpoints.push(endpoint);
Expand Down Expand Up @@ -319,7 +319,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
const endpoints = await this.getEndpoints();

if (!endpoints.length)
return [];
return [];

const accessToken = await this.getAccessToken();
const data = {
Expand Down Expand Up @@ -448,7 +448,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
self.console.warn(error?.response?.data);
self.log.a(error?.response?.data?.error_description);
break;

case 'expired_token':
self.console.warn(error?.response?.data);
self.log.a(error?.response?.data?.error_description);
Expand Down Expand Up @@ -480,9 +480,14 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
this.storageSettings.values.tokenInfo = grant;
this.storageSettings.values.apiEndpoint = undefined;
this.accessToken = undefined;

const self = this;
let accessToken = await this.getAccessToken().catch(reason => {
let accessToken: any;

try {
accessToken = await this.getAccessToken();
}
catch (reason) {
self.console.error(`Failed to handle the AcceptGrant directive because ${reason}`);

this.storageSettings.values.tokenInfo = undefined;
Expand All @@ -491,36 +496,23 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi

response.send(authErrorResponse("ACCEPT_GRANT_FAILED", `Failed to handle the AcceptGrant directive because ${reason}`, directive));

return undefined;
});

if (accessToken !== undefined) {
this.log.clearAlerts();

try {
response.send({
"event": {
"header": {
"namespace": "Alexa.Authorization",
"name": "AcceptGrant.Response",
"messageId": createMessageId(),
"payloadVersion": "3"
},
"payload": {}
}
});
} catch (error) {
this.console.error(`AcceptGrant.Response failed because ${error}`);

this.storageSettings.values.tokenInfo = undefined;
this.storageSettings.values.apiEndpoint = undefined;
this.accessToken = undefined;
throw error;
return;
};
this.log.clearAlerts();
response.send({
"event": {
"header": {
"namespace": "Alexa.Authorization",
"name": "AcceptGrant.Response",
"messageId": createMessageId(),
"payloadVersion": "3"
},
"payload": {}
}
}
});
}

async getEndpointForDevice(device: ScryptedDevice) : Promise<DiscoveryEndpoint> {
async getEndpointForDevice(device: ScryptedDevice): Promise<DiscoveryEndpoint> {
if (!device)
return;

Expand All @@ -545,7 +537,7 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
};

let supportedEndpointHealths: any[] = [];

if (device.interfaces.includes(ScryptedInterface.Online)) {
supportedEndpointHealths.push({
"name": "connectivity"
Expand Down

0 comments on commit dab5be1

Please sign in to comment.