Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to abort async operations #667

Merged
merged 3 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ export function fileTypeStream(webStream: AnyWebReadableStream<Uint8Array>, opti
export declare class FileTypeParser {
detectors: Iterable<Detector>;

constructor(options?: {customDetectors?: Iterable<Detector>});
constructor(options?: {customDetectors?: Iterable<Detector>; abortSignal: AbortSignal});
Borewit marked this conversation as resolved.
Show resolved Hide resolved

/**
Works the same way as {@link fileTypeFromBuffer}, additionally taking into account custom detectors (if any were provided to the constructor).
Expand Down
8 changes: 5 additions & 3 deletions core.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ export async function fileTypeStream(webStream, options) {
export class FileTypeParser {
constructor(options) {
this.detectors = options?.customDetectors;

this.tokenizerOptions = {
abortSignal: options?.abortSignal,
};
this.fromTokenizer = this.fromTokenizer.bind(this);
this.fromBuffer = this.fromBuffer.bind(this);
this.parse = this.parse.bind(this);
Expand Down Expand Up @@ -92,15 +94,15 @@ export class FileTypeParser {
return;
}

return this.fromTokenizer(strtok3.fromBuffer(buffer));
return this.fromTokenizer(strtok3.fromBuffer(buffer, this.tokenizerOptions));
}

async fromBlob(blob) {
return this.fromStream(blob.stream());
}

async fromStream(stream) {
const tokenizer = await strtok3.fromWebStream(stream);
const tokenizer = await strtok3.fromWebStream(stream, this.tokenizerOptions);
try {
return await this.fromTokenizer(tokenizer);
} finally {
Expand Down
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {FileTypeParser, reasonableDetectionSizeInBytes} from './core.js';

export class NodeFileTypeParser extends FileTypeParser {
async fromStream(stream) {
const tokenizer = await (stream instanceof WebReadableStream ? strtok3.fromWebStream(stream) : strtok3.fromStream(stream));
const tokenizer = await (stream instanceof WebReadableStream ? strtok3.fromWebStream(stream, this.tokenizerOptions) : strtok3.fromStream(stream, this.tokenizerOptions));
try {
return super.fromTokenizer(tokenizer);
} finally {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@
],
"dependencies": {
"get-stream": "^9.0.1",
"strtok3": "^8.1.0",
"strtok3": "^9.0.0",
"token-types": "^6.0.0",
"uint8array-extras": "^1.3.0"
},
Expand Down
16 changes: 16 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,22 @@ const fileType = await parser.fromBuffer(buffer);
console.log(fileType);
```

## Abort signal

Some asynchronous operations can be aborted by passing the [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) interface to the `FileTypeParser` constructor.

```js
import {FileTypeParser} from 'file-type'; // or `NodeFileTypeParser` in Node.js

const abortController = new AbortController()

const parser = new FileTypeParser({abortSignal: abortController.signal});

const promise = parser.fromStream(blob.stream());

abortController.abort(); // Abort file-type reading from the Blob stream.
```

## Supported file types

- [`3g2`](https://en.wikipedia.org/wiki/3GP_and_3G2#3G2) - Multimedia container format defined by the 3GPP2 for 3G CDMA2000 multimedia services
Expand Down
20 changes: 20 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,26 @@ test('.fileTypeStream() method - sampleSize option', async t => {
t.is(stream.fileType.mime, 'video/ogg');
});

test('.fileTypeFromStream() method - be able to abort operation', async t => {
const bufferA = new Uint8Array([0, 1, 0, 1]);
class MyStream extends stream.Readable {
_read() {
setTimeout(() => {
this.push(bufferA);
this.push(null);
}, 500);
}
}

const shortStream = new MyStream();
const abortController = new AbortController();
const parser = new NodeFileTypeParser({abortSignal: abortController.signal});
const promiseFileType = parser.fromStream(shortStream);
abortController.abort(); // Abort asynchronous operation: reading from shortStream
const error = await t.throwsAsync(promiseFileType);
t.is(error.message, 'Stream closed');
});

test('supportedExtensions.has', t => {
t.true(supportedExtensions.has('jpg'));
t.false(supportedExtensions.has('blah'));
Expand Down