Skip to content

Commit

Permalink
chore: add try catch when parsing stream response (#1839)
Browse files Browse the repository at this point in the history
  • Loading branch information
Torres-ssf authored Mar 8, 2024
1 parent 950f9be commit 468b4cf
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 3 deletions.
6 changes: 6 additions & 0 deletions .changeset/brave-phones-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/account": patch
"@fuel-ts/errors": patch
---

Add try/catch block when parsing GraphQL stream data response
14 changes: 12 additions & 2 deletions packages/account/src/providers/fuel-graphql-subscriber.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FuelError } from '@fuel-ts/errors';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { DocumentNode } from 'graphql';
import { print } from 'graphql';

Expand Down Expand Up @@ -61,7 +61,17 @@ export class FuelGraphqlSubscriber implements AsyncIterator<unknown> {
continue;
}

const { data, errors } = JSON.parse(text.split('data:')[1]);
let data;
let errors;

try {
({ data, errors } = JSON.parse(text.replace(/^data:/, '')));
} catch (e) {
throw new FuelError(
ErrorCode.STREAM_PARSING_ERROR,
`Error while parsing stream data response: ${text}`
);
}

if (Array.isArray(errors)) {
throw new FuelError(
Expand Down
71 changes: 71 additions & 0 deletions packages/account/src/providers/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {
} from './transaction-request';
import { ScriptTransactionRequest, CreateTransactionRequest } from './transaction-request';
import { TransactionResponse } from './transaction-response';
import type { SubmittedStatus } from './transaction-summary/types';
import { sleep } from './utils';
import * as gasMod from './utils/gas';

Expand Down Expand Up @@ -1039,6 +1040,76 @@ describe('Provider', () => {
await Promise.all(promises);
});

it('should not throw if the subscription stream data string contains more than one "data:"', async () => {
const provider = await Provider.create(FUEL_NETWORK_URL);

vi.spyOn(global, 'fetch').mockImplementationOnce(() => {
const responseObject = {
data: {
submitAndAwait: {
type: 'SuccessStatus',
time: 'data: 4611686020137152060',
},
},
};
const streamedResponse = new TextEncoder().encode(
`data:${JSON.stringify(responseObject)}\n\n`
);
return Promise.resolve(
new Response(
new ReadableStream({
start: (controller) => {
controller.enqueue(streamedResponse);
controller.close();
},
})
)
);
});

for await (const { submitAndAwait } of provider.operations.submitAndAwait({
encodedTransaction: "it's mocked so doesn't matter",
})) {
expect(submitAndAwait.type).toEqual('SuccessStatus');
expect((<SubmittedStatus>submitAndAwait).time).toEqual('data: 4611686020137152060');
}
});

it('should throw if the subscription stream data string parsing fails for some reason', async () => {
const provider = await Provider.create(FUEL_NETWORK_URL);

const badResponse = 'data: whatever';
vi.spyOn(global, 'fetch').mockImplementationOnce(() => {
const streamResponse = new TextEncoder().encode(badResponse);
return Promise.resolve(
new Response(
new ReadableStream({
start: (controller) => {
controller.enqueue(streamResponse);
controller.close();
},
})
)
);
});

await expectToThrowFuelError(
async () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const { submitAndAwait } of provider.operations.submitAndAwait({
encodedTransaction: "it's mocked so doesn't matter",
})) {
// shouldn't be reached!
expect(true).toBeFalsy();
}
},
{
code: FuelError.CODES.STREAM_PARSING_ERROR,
message: `Error while parsing stream data response: ${badResponse}`,
}
);
});

test('requestMiddleware modifies the request before being sent to the node [sync]', async () => {
const fetchSpy = vi.spyOn(global, 'fetch');
await Provider.create(FUEL_NETWORK_URL, {
Expand Down
3 changes: 3 additions & 0 deletions packages/errors/src/error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export enum ErrorCode {
SCRIPT_REVERTED = 'script-reverted',
SCRIPT_RETURN_INVALID_TYPE = 'script-return-invalid-type',

// graphql
STREAM_PARSING_ERROR = 'stream-parsing-error',

// coder
// ...
}
2 changes: 1 addition & 1 deletion packages/fuel-gauge/src/transaction-response.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,5 +277,5 @@ describe('TransactionResponse', () => {
{ code: ErrorCode.TRANSACTION_SQUEEZED_OUT }
);
cleanup();
});
}, 7000);
});

0 comments on commit 468b4cf

Please sign in to comment.