Skip to content
This repository was archived by the owner on May 2, 2025. It is now read-only.

Commit a3b6d4d

Browse files
committed
chore: convert to LF line ending
1 parent d41e244 commit a3b6d4d

File tree

13 files changed

+326
-326
lines changed

13 files changed

+326
-326
lines changed

Readme.md

Lines changed: 149 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,149 @@
1-
![Travis CI Status](https://travis-ci.com/SukantGujar/express-partial-content.svg?branch=master)
2-
3-
# About
4-
5-
A HTTP 206 Partial Content handler to serve any readable stream partially in Express.
6-
7-
Based on this blog post: https://www.codeproject.com/Articles/813480/HTTP-Partial-Content-In-Node-js.
8-
9-
# Installation
10-
11-
`yarn add express-partial-content`
12-
13-
OR
14-
15-
`npm install express-partial-content`
16-
17-
> Note: `Express` package is a peer dependency for `express-partial-content` and must be present in dependencies of the host package.
18-
19-
# Usage
20-
21-
From the `express-file-server` example:
22-
23-
1. Implement a `ContentProvider` function which prepares and returns a `Content` object:
24-
25-
import { promisify } from "util";
26-
import fs from "fs";
27-
import { Range, ContentDoesNotExistError, ContentProvider } from "express-partial-content";
28-
import {logger} from "./logger";
29-
30-
const statAsync = promisify(fs.stat);
31-
const existsAsync = promisify(fs.exists);
32-
33-
export const fileContentProvider: ContentProvider = async (req: Request) => {
34-
// Read file name from route params.
35-
const fileName = req.params.name;
36-
const file = `${__dirname}/files/${fileName}`;
37-
if (!(await existsAsync(file))) {
38-
throw new ContentDoesNotExistError(`File doesn't exist: ${file}`);
39-
}
40-
const stats = await statAsync(file);
41-
const totalSize = stats.size;
42-
const mimeType = "application/octet-stream";
43-
const getStream = (range?: Range) => {
44-
if (!range) {
45-
// Request if for complete content.
46-
return fs.createReadStream(file);
47-
}
48-
// Partial content request.
49-
const { start, end } = range;
50-
logger.debug(`start: ${start}, end: ${end}`);
51-
return fs.createReadStream(file, { start, end });
52-
};
53-
return {
54-
fileName,
55-
totalSize,
56-
mimeType,
57-
getStream
58-
};
59-
};
60-
61-
2. In your express code, use `createPartialContentHandler` factory method to generate an express handler for serving partial content for the route of your choice:
62-
63-
import {createPartialContentHandler} from "express-partial-content";
64-
import {logger} from "./logger";
65-
66-
const handler = createPartialContentHandler(fileContentProvider, logger);
67-
68-
const app = express();
69-
const port = 8080;
70-
71-
// File name is a route param.
72-
app.get("/files/:name", handler);
73-
74-
app.listen(port, () => {
75-
logger.debug("Server started!");
76-
});
77-
78-
3. Run your server and use a multi-part/multi-connection download utility like [aria2c](https://aria2.github.io/) to test it:
79-
80-
aria -x5 -k1M http://localhost:8080/files/readme.txt
81-
82-
# Examples
83-
84-
There one examples in the `src/examples` folder:
85-
86-
1. `express-file-server`: Implements a file based `ContentProvider`.
87-
88-
## Running the examples:
89-
90-
1. `express-file-server`: Run the following commands, the server will listen on http://localhost:8080/.
91-
92-
yarn build:dev
93-
yarn copy-assets
94-
yarn run:examples:file
95-
96-
## Connecting to the running server:
97-
98-
Browse to `https://localhost:8080/files/readme.txt`
99-
100-
# Reference
101-
102-
## createPartialContentHandler function:
103-
104-
This is a factory method which generates a partial content handler for express routes.
105-
106-
### Arguments:
107-
108-
- `contentProvider`: An `async` function which returns a Promise resolved to a `Content` object (see below).
109-
- `logger`: Any logging implementation which has a `debug(message:string, extra: any)` method. Either `winston` or `bunyan` loggers should work.
110-
111-
### Returns:
112-
113-
- Express Route Handler: `createPartialContentHandler` returns an express handler which can be mapped to an Express route to serve partial content.
114-
115-
## ContentProvider function:
116-
117-
This function _needs to be implemented by you_. It's purpose is to fetch and return `Content` object containing necessary metadata and methods to stream the content partially. This method is invoked by the express handler (returned by `createPartialContentHandler`) on each request.
118-
119-
### Arguments:
120-
121-
- `Request`: It receives the `Request` object as it's only input. Use the information available in `Request` to find the requested content, e.g. through `Request.params` or query string, headers etc.
122-
123-
### Returns:
124-
125-
- `Promise<Content>`: See below.
126-
127-
### Throws:
128-
129-
- `ContentDoesNotExistError`: Throw this to indicate that the content doesn't exist. The generated express handler will return a 404 in this case.
130-
> Note: Any message provided to the `ContentDoesNotExistError` object is returned to the client.
131-
132-
## Content object:
133-
134-
This object contains metadata and methods which describe the content. The `ContentProvider` method builds and returns it.
135-
136-
### Properties:
137-
138-
All the properties of this object are used to return content metadata to the client as various `Response` headers.
139-
140-
- `fileName`: Used as the `Content-Disposition` header's `filename` value.
141-
- `mimeType`: Used as the `Content-Type` header value.
142-
- `totalSize`: Used as the `Content-Length` header value.
143-
144-
### Methods:
145-
146-
- `getStream(range?: Range)`: This method should return a readable stream initialized to the provided `range` (optional). You need to handle two cases:
147-
148-
- range is `null`: When `range` is not-specified, the client is requesting the full content. In this case, return the stream as it is.
149-
- range is `{start, end}`: When client requests partial content, the `start` and `end` values will point to the corresponding byte positions (0 based and inclusive) of the content. You need to return stream limited to these positions.
1+
![Travis CI Status](https://travis-ci.com/SukantGujar/express-partial-content.svg?branch=master)
2+
3+
# About
4+
5+
A HTTP 206 Partial Content handler to serve any readable stream partially in Express.
6+
7+
Based on this blog post: https://www.codeproject.com/Articles/813480/HTTP-Partial-Content-In-Node-js.
8+
9+
# Installation
10+
11+
`yarn add express-partial-content`
12+
13+
OR
14+
15+
`npm install express-partial-content`
16+
17+
> Note: `Express` package is a peer dependency for `express-partial-content` and must be present in dependencies of the host package.
18+
19+
# Usage
20+
21+
From the `express-file-server` example:
22+
23+
1. Implement a `ContentProvider` function which prepares and returns a `Content` object:
24+
25+
import { promisify } from "util";
26+
import fs from "fs";
27+
import { Range, ContentDoesNotExistError, ContentProvider } from "express-partial-content";
28+
import {logger} from "./logger";
29+
30+
const statAsync = promisify(fs.stat);
31+
const existsAsync = promisify(fs.exists);
32+
33+
export const fileContentProvider: ContentProvider = async (req: Request) => {
34+
// Read file name from route params.
35+
const fileName = req.params.name;
36+
const file = `${__dirname}/files/${fileName}`;
37+
if (!(await existsAsync(file))) {
38+
throw new ContentDoesNotExistError(`File doesn't exist: ${file}`);
39+
}
40+
const stats = await statAsync(file);
41+
const totalSize = stats.size;
42+
const mimeType = "application/octet-stream";
43+
const getStream = (range?: Range) => {
44+
if (!range) {
45+
// Request if for complete content.
46+
return fs.createReadStream(file);
47+
}
48+
// Partial content request.
49+
const { start, end } = range;
50+
logger.debug(`start: ${start}, end: ${end}`);
51+
return fs.createReadStream(file, { start, end });
52+
};
53+
return {
54+
fileName,
55+
totalSize,
56+
mimeType,
57+
getStream
58+
};
59+
};
60+
61+
2. In your express code, use `createPartialContentHandler` factory method to generate an express handler for serving partial content for the route of your choice:
62+
63+
import {createPartialContentHandler} from "express-partial-content";
64+
import {logger} from "./logger";
65+
66+
const handler = createPartialContentHandler(fileContentProvider, logger);
67+
68+
const app = express();
69+
const port = 8080;
70+
71+
// File name is a route param.
72+
app.get("/files/:name", handler);
73+
74+
app.listen(port, () => {
75+
logger.debug("Server started!");
76+
});
77+
78+
3. Run your server and use a multi-part/multi-connection download utility like [aria2c](https://aria2.github.io/) to test it:
79+
80+
aria -x5 -k1M http://localhost:8080/files/readme.txt
81+
82+
# Examples
83+
84+
There one examples in the `src/examples` folder:
85+
86+
1. `express-file-server`: Implements a file based `ContentProvider`.
87+
88+
## Running the examples:
89+
90+
1. `express-file-server`: Run the following commands, the server will listen on http://localhost:8080/.
91+
92+
yarn build:dev
93+
yarn copy-assets
94+
yarn run:examples:file
95+
96+
## Connecting to the running server:
97+
98+
Browse to `https://localhost:8080/files/readme.txt`
99+
100+
# Reference
101+
102+
## createPartialContentHandler function:
103+
104+
This is a factory method which generates a partial content handler for express routes.
105+
106+
### Arguments:
107+
108+
- `contentProvider`: An `async` function which returns a Promise resolved to a `Content` object (see below).
109+
- `logger`: Any logging implementation which has a `debug(message:string, extra: any)` method. Either `winston` or `bunyan` loggers should work.
110+
111+
### Returns:
112+
113+
- Express Route Handler: `createPartialContentHandler` returns an express handler which can be mapped to an Express route to serve partial content.
114+
115+
## ContentProvider function:
116+
117+
This function _needs to be implemented by you_. It's purpose is to fetch and return `Content` object containing necessary metadata and methods to stream the content partially. This method is invoked by the express handler (returned by `createPartialContentHandler`) on each request.
118+
119+
### Arguments:
120+
121+
- `Request`: It receives the `Request` object as it's only input. Use the information available in `Request` to find the requested content, e.g. through `Request.params` or query string, headers etc.
122+
123+
### Returns:
124+
125+
- `Promise<Content>`: See below.
126+
127+
### Throws:
128+
129+
- `ContentDoesNotExistError`: Throw this to indicate that the content doesn't exist. The generated express handler will return a 404 in this case.
130+
> Note: Any message provided to the `ContentDoesNotExistError` object is returned to the client.
131+
132+
## Content object:
133+
134+
This object contains metadata and methods which describe the content. The `ContentProvider` method builds and returns it.
135+
136+
### Properties:
137+
138+
All the properties of this object are used to return content metadata to the client as various `Response` headers.
139+
140+
- `fileName`: Used as the `Content-Disposition` header's `filename` value.
141+
- `mimeType`: Used as the `Content-Type` header value.
142+
- `totalSize`: Used as the `Content-Length` header value.
143+
144+
### Methods:
145+
146+
- `getStream(range?: Range)`: This method should return a readable stream initialized to the provided `range` (optional). You need to handle two cases:
147+
148+
- range is `null`: When `range` is not-specified, the client is requesting the full content. In this case, return the stream as it is.
149+
- range is `{start, end}`: When client requests partial content, the `start` and `end` values will point to the corresponding byte positions (0 based and inclusive) of the content. You need to return stream limited to these positions.

src/Content.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import { Range } from "./Range";
2-
import { Stream } from "stream";
3-
export interface Content {
4-
/**
5-
* Returns a readable stream based on the provided range (optional).
6-
* @param {Range} range The start-end range of stream data.
7-
* @returns {Stream} A readable stream
8-
*/
9-
getStream(range?: Range): Stream;
10-
/**
11-
* Total size of the content
12-
*/
13-
readonly totalSize: number;
14-
/**
15-
* Mime type to be sent in Content-Type header
16-
*/
17-
readonly mimeType: string;
18-
/**
19-
* File name to be sent in Content-Disposition header
20-
*/
21-
readonly fileName: string;
22-
};
1+
import { Range } from "./Range";
2+
import { Stream } from "stream";
3+
export interface Content {
4+
/**
5+
* Returns a readable stream based on the provided range (optional).
6+
* @param {Range} range The start-end range of stream data.
7+
* @returns {Stream} A readable stream
8+
*/
9+
getStream(range?: Range): Stream;
10+
/**
11+
* Total size of the content
12+
*/
13+
readonly totalSize: number;
14+
/**
15+
* Mime type to be sent in Content-Type header
16+
*/
17+
readonly mimeType: string;
18+
/**
19+
* File name to be sent in Content-Disposition header
20+
*/
21+
readonly fileName: string;
22+
};

src/ContentDoesNotExistError.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export class ContentDoesNotExistError extends Error {
2-
}
1+
export class ContentDoesNotExistError extends Error {
2+
}

src/ContentProvider.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Request } from "express";
2-
import { Content } from "./Content";
3-
/**
4-
* @type {function (Request): Promise<Content>}
5-
*/
6-
export type ContentProvider = (req: Request) => Promise<Content>;
1+
import { Request } from "express";
2+
import { Content } from "./Content";
3+
/**
4+
* @type {function (Request): Promise<Content>}
5+
*/
6+
export type ContentProvider = (req: Request) => Promise<Content>;

src/Logger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export interface Logger {
2-
debug(message: string, extra?: any): void;
3-
}
1+
export interface Logger {
2+
debug(message: string, extra?: any): void;
3+
}

src/RangeParserError.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export class RangeParserError extends Error {
2-
constructor(start: any, end: any) {
3-
super(`Invalid start and end values: ${start}-${end}.`);
4-
}
5-
}
1+
export class RangeParserError extends Error {
2+
constructor(start: any, end: any) {
3+
super(`Invalid start and end values: ${start}-${end}.`);
4+
}
5+
}

0 commit comments

Comments
 (0)