Skip to content

Commit

Permalink
[VBLOCKS-2054] Missing generated errors (#192)
Browse files Browse the repository at this point in the history
* feat: add errors and unit tests to check for missing errors

* docs: changelog entry

* fix: call hangup handler

* docs: update changelog

* feat: add error feature flag and handling

* chore: unit tests

* chore: update voice errors version

* feat: add new errors to generation scripts

* chore: commit generated errors

* fix: add error codes to feature flag set

* docs: update changelog entry

* docs: update docstring for option

* docs: less enthusiasm

* fix: rename variables and functions

* fix: rename test case
  • Loading branch information
mhuynh5757 committed Oct 3, 2023
1 parent 884aba3 commit 4d28678
Show file tree
Hide file tree
Showing 11 changed files with 1,023 additions and 52 deletions.
69 changes: 69 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,74 @@
:warning: **Important**: If you are upgrading to version 2.3.0 or later and have firewall rules or network configuration that blocks any unknown traffic by default, you need to update your configuration to allow connections to the new DNS names and IP addresses. Please refer to this [changelog](#230-january-23-2023) for more details.

2.8.0 (In Progress)
===================

New Features
------------

- Added a new feature flag `enableImprovedSignalingErrorPrecision` to enhance the precision of errors emitted by `Device` and `Call` objects.

```ts
const token = ...;
const device = new Device(token, {
enableImprovedSignalingErrorPrecision: true,
});
```

The default value of this option is `false`.

When this flag is enabled, some errors that would have been described with a generic error code are now described with a more precise error code. With this feature, the following errors now have their own error codes. Please see this [page](https://www.twilio.com/docs/api/errors) for more details about each error.

- Device Error Changes

```ts
const device = new Device(token, {
enableImprovedSignalingErrorPrecision: true,
});
device.on('error', (deviceError) => {
// the following table describes how deviceError will change with this feature flag
});
```

| Device Error Name | Device Error Code with Feature Flag Enabled | Device Error Code with Feature Flag Disabled |
| --- | --- | --- |
| `GeneralErrors.ApplicationNotFoundError` | `31001` | `53000` |
| `GeneralErrors.ConnectionDeclinedError` | `31002` | `53000` |
| `GeneralErrors.ConnectionTimeoutError` | `31003` | `53000` |
| `MalformedRequestErrors.MissingParameterArrayError` | `31101` | `53000` |
| `MalformedRequestErrors.AuthorizationTokenMissingError` | `31102` | `53000` |
| `MalformedRequestErrors.MaxParameterLengthExceededError` | `31103` | `53000` |
| `MalformedRequestErrors.InvalidBridgeTokenError` | `31104` | `53000` |
| `MalformedRequestErrors.InvalidClientNameError` | `31105` | `53000` |
| `MalformedRequestErrors.ReconnectParameterInvalidError` | `31107` | `53000` |
| `SignatureValidationErrors.AccessTokenSignatureValidationFailed` | `31202` | `53000` |
| `AuthorizationErrors.NoValidAccountError` | `31203` | `53000` |
| `AuthorizationErrors.JWTTokenExpirationTooLongError` | `31207` | `53000` |
| `ClientErrors.NotFound` | `31404` | `53000` |
| `ClientErrors.TemporarilyUnavilable` | `31480` | `53000` |
| `ClientErrors.BusyHere` | `31486` | `53000` |
| `SIPServerErrors.Decline` | `31603` | `53000` |

- Call Error Changes

```ts
const device = new Device(token, {
enableImprovedSignalingErrorPrecision: true,
});
const call = device.connect(...);
call.on('error', (callError) => {
// the following table describes how callError will change with this feature flag
});
```

| Call Error Name | Call Error Code with Feature Flag Enabled | Call Error Code with Feature Flag Disabled |
| --- | --- | --- |
| `GeneralErrors.ConnectionDeclinedError` | `31002` | `31005` |
| `AuthorizationErrors.InvalidJWTTokenError` | `31204` | `31005` |
| `AuthorizationErrors.JWTTokenExpiredError` | `31205` | `31005` |

_**IMPORTANT:** If your application logic currently relies on listening to the generic error code `53000` or `31005`, and you opt into enabling the feature flag, then your applicaton logic needs to be updated to anticipate the new error code when any of the above errors happen._

2.7.2 (September 21, 2023)
=========================

Expand Down
15 changes: 14 additions & 1 deletion lib/twilio/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Device from './device';
import DialtonePlayer from './dialtonePlayer';
import {
GeneralErrors,
getPreciseSignalingErrorByCode,
InvalidArgumentError,
InvalidStateError,
MediaErrors,
Expand Down Expand Up @@ -247,6 +248,7 @@ class Call extends EventEmitter {
*/
private _options: Call.Options = {
MediaHandler: PeerConnection,
enableImprovedSignalingErrorPrecision: false,
offerSdp: null,
shouldPlayDisconnect: () => true,
voiceEventSidGenerator: generateVoiceEventSid,
Expand Down Expand Up @@ -1208,7 +1210,16 @@ class Call extends EventEmitter {

this._log.info('Received HANGUP from gateway');
if (payload.error) {
const error = new GeneralErrors.ConnectionError('Error sent from gateway in HANGUP');
const code = payload.error.code;
const errorConstructor = getPreciseSignalingErrorByCode(
this._options.enableImprovedSignalingErrorPrecision,
code,
);
const error = typeof errorConstructor !== 'undefined'
? new errorConstructor(payload.error.message)
: new GeneralErrors.ConnectionError(
'Error sent from gateway in HANGUP',
);
this._log.error('Received an error from the gateway:', error);
this.emit('error', error);
}
Expand Down Expand Up @@ -1877,6 +1888,8 @@ namespace Call {
*/
dscp?: boolean;

enableImprovedSignalingErrorPrecision: boolean;

/**
* Experimental feature.
* Force Chrome's ICE agent to use aggressive nomination when selecting a candidate pair.
Expand Down
109 changes: 95 additions & 14 deletions lib/twilio/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {
AuthorizationErrors,
ClientErrors,
GeneralErrors,
getErrorByCode,
hasErrorByCode,
getPreciseSignalingErrorByCode,
InvalidArgumentError,
InvalidStateError,
NotSupportedError,
Expand Down Expand Up @@ -339,6 +338,7 @@ class Device extends EventEmitter {
closeProtection: false,
codecPreferences: [Call.Codec.PCMU, Call.Codec.Opus],
dscp: true,
enableImprovedSignalingErrorPrecision: false,
forceAggressiveIceNomination: false,
logLevel: LogLevels.ERROR,
maxCallSignalingTimeoutMs: 0,
Expand Down Expand Up @@ -554,10 +554,15 @@ class Device extends EventEmitter {
throw new InvalidStateError('A Call is already active');
}

const activeCall = this._activeCall = await this._makeCall(options.params || { }, {
rtcConfiguration: options.rtcConfiguration,
voiceEventSidGenerator: this._options.voiceEventSidGenerator,
});
const activeCall = this._activeCall = await this._makeCall(
options.params || { },
{
enableImprovedSignalingErrorPrecision:
!!this._options.enableImprovedSignalingErrorPrecision,
rtcConfiguration: options.rtcConfiguration,
voiceEventSidGenerator: this._options.voiceEventSidGenerator,
},
);

// Make sure any incoming calls are ignored
this._calls.splice(0).forEach(call => call.ignore());
Expand Down Expand Up @@ -1175,8 +1180,14 @@ class Device extends EventEmitter {
// Stop trying to register presence after token expires
this._stopRegistrationTimer();
twilioError = new AuthorizationErrors.AccessTokenExpired(originalError);
} else if (hasErrorByCode(code)) {
twilioError = new (getErrorByCode(code))(originalError);
} else {
const errorConstructor = getPreciseSignalingErrorByCode(
!!this._options.enableImprovedSignalingErrorPrecision,
code,
);
if (typeof errorConstructor !== 'undefined') {
twilioError = new errorConstructor(originalError);
}
}
}

Expand Down Expand Up @@ -1209,12 +1220,17 @@ class Device extends EventEmitter {

const customParameters = Object.assign({ }, queryToJson(callParameters.Params));

const call = await this._makeCall(customParameters, {
callParameters,
offerSdp: payload.sdp,
reconnectToken: payload.reconnect,
voiceEventSidGenerator: this._options.voiceEventSidGenerator,
});
const call = await this._makeCall(
customParameters,
{
callParameters,
enableImprovedSignalingErrorPrecision:
!!this._options.enableImprovedSignalingErrorPrecision,
offerSdp: payload.sdp,
reconnectToken: payload.reconnect,
voiceEventSidGenerator: this._options.voiceEventSidGenerator,
},
);

this._calls.push(call);

Expand Down Expand Up @@ -1717,6 +1733,71 @@ namespace Device {
*/
edge?: string[] | string;

/**
* Enhance the precision of errors emitted by `Device` and `Call` objects.
*
* The default value of this option is `false`.
*
* When this flag is enabled, some errors that would have been described
* with a generic error code, namely `53000` and `31005`, are now described
* with a more precise error code. With this feature, the following errors
* now have their own error codes. Please see this
* [page](https://www.twilio.com/docs/api/errors) for more details about
* each error.
*
* - Device Error Changes
*
* @example
* ```ts
* const device = new Device(token, {
* enableImprovedSignalingErrorPrecision: true,
* });
* device.on('error', (deviceError) => {
* // the following table describes how deviceError will change with this feature flag
* });
* ```
*
* | Device Error Name | Device Error Code with Feature Flag Enabled | Device Error Code with Feature Flag Disabled |
* | --- | --- | --- |
* | `GeneralErrors.ApplicationNotFoundError` | `31001` | `53000` |
* | `GeneralErrors.ConnectionDeclinedError` | `31002` | `53000` |
* | `GeneralErrors.ConnectionTimeoutError` | `31003` | `53000` |
* | `MalformedRequestErrors.MissingParameterArrayError` | `31101` | `53000` |
* | `MalformedRequestErrors.AuthorizationTokenMissingError` | `31102` | `53000` |
* | `MalformedRequestErrors.MaxParameterLengthExceededError` | `31103` | `53000` |
* | `MalformedRequestErrors.InvalidBridgeTokenError` | `31104` | `53000` |
* | `MalformedRequestErrors.InvalidClientNameError` | `31105` | `53000` |
* | `MalformedRequestErrors.ReconnectParameterInvalidError` | `31107` | `53000` |
* | `SignatureValidationErrors.AccessTokenSignatureValidationFailed` | `31202` | `53000` |
* | `AuthorizationErrors.NoValidAccountError` | `31203` | `53000` |
* | `AuthorizationErrors.JWTTokenExpirationTooLongError` | `31207` | `53000` |
* | `ClientErrors.NotFound` | `31404` | `53000` |
* | `ClientErrors.TemporarilyUnavilable` | `31480` | `53000` |
* | `ClientErrors.BusyHere` | `31486` | `53000` |
* | `SIPServerErrors.Decline` | `31603` | `53000` |
*
* - Call Error Changes
*
* @example
* ```ts
* const device = new Device(token, {
* enableImprovedSignalingErrorPrecision: true,
* });
* const call = device.connect(...);
* call.on('error', (callError) => {
* // the following table describes how callError will change with this feature flag
* });
* ```
*
* | Call Error Name | Call Error Code with Feature Flag Enabled | Call Error Code with Feature Flag Disabled |
* | --- | --- | --- |
* | `GeneralErrors.ConnectionDeclinedError` | `31002` | `31005` |
* | `AuthorizationErrors.InvalidJWTTokenError` | `31204` | `31005` |
* | `AuthorizationErrors.JWTTokenExpiredError` | `31205` | `31005` |
*
*/
enableImprovedSignalingErrorPrecision?: boolean;

/**
* Overrides the native MediaDevices.enumerateDevices API.
*/
Expand Down
Loading

0 comments on commit 4d28678

Please sign in to comment.