0.9.0 • Published 1 year ago

tus-node-server v0.9.0

Weekly downloads
3,242
License
MIT
Repository
github
Last release
1 year ago

tus-node-server

npm version Build Status

tus is a new open protocol for resumable uploads built on HTTP. This is the tus protocol 1.0.0 node.js server implementation.

Installation

$ npm install tus-node-server

Flexible Data Stores

  • Local File Storage

    server.datastore = new tus.FileStore({
        directory: './files'
    });
  • Google Cloud Storage

    server.datastore = new tus.GCSDataStore({
        projectId: 'project-id',
        keyFilename: 'path/to/your/keyfile.json',
        bucket: 'bucket-name',
    });
  • Amazon S3

    using Key/Secret

    server.datastore = new tus.S3Store({
        bucket: 'bucket-name',
        accessKeyId: 'access-key-id',
        secretAccessKey: 'secret-access-key',
        region: 'eu-west-1',
        partSize: 8 * 1024 * 1024, // each uploaded part will have ~8MB,
    });

    using credentials to fetch credentials inside a AWS container, such as an ECS container, which will inject the required environment variables. The credentials config is directly passed into the AWS SDK so you can refer to the AWS docs for the supported values for credentials.

    For example, with ECSCredentials:

    server.datastore = new tus.S3Store({
        path: '/files',
        bucket: 'bucket-name',
        credentials: new AWS.ECSCredentials({
            httpOptions: { timeout: 5000 },
            maxRetries: 10,
        }),
        region: 'eu-west-1',
        partSize: 8 * 1024 * 1024, // each uploaded part will have ~8MB,
        tmpDirPrefix: 'tus-s3-store',
    });

Quick Start

Use the tus-node-deploy Docker image

$ docker run -p 1080:8080 -d bhstahl/tus-node-deploy

Build a standalone server yourself

const tus = require('tus-node-server');

const server = new tus.Server({ path: '/files' });
server.datastore = new tus.FileStore({ directory: './files' });

const host = '127.0.0.1';
const port = 1080;
server.listen({ host, port }, () => {
    console.log(`[${new Date().toLocaleTimeString()}] tus server listening at http://${host}:${port}`);
});

Use tus-node-server as Express Middleware

const tus = require('tus-node-server');
const server = new tus.Server({ path: '/files' });
server.datastore = new tus.FileStore({ directory: './files' });

const express = require('express');
const app = express();
const uploadApp = express();
uploadApp.all('*', server.handle.bind(server));
app.use('/uploads', uploadApp);

const host = '127.0.0.1';
const port = 1080;
app.listen(port, host);

Use tus-node-server with Koa or plain Node server

const http = require('http');
const url = require('url');
const Koa = require('koa')
const tus = require('tus-node-server');

const tusServer = new tus.Server({ path: '/files' });
tusServer.datastore = new tus.FileStore({ directory: './files' });

const app = new Koa();
const appCallback = app.callback();
const port = 1080;


const server = http.createServer((req, res) => {
    const urlPath = url.parse(req.url).pathname;

    // handle any requests with the `/files/*` pattern
    if (/^\/files\/.+/.test(urlPath.toLowerCase())) {
        return tusServer.handle(req, res);
    }

    appCallback(req, res);
});

server.listen(port)

Use tus-node-server with Fastify

const tus = require('tus-node-server');
const tusServer = new tus.Server({ path: '/files' });
tusServer.datastore = new tus.FileStore({ directory: './files' });

const fastify = require('fastify')({ logger: true });

/**
 * add new content-type to fastify forewards request
 * without any parser to leave body untouched
 * @see https://www.fastify.io/docs/latest/Reference/ContentTypeParser/
 */
fastify.addContentTypeParser(
    'application/offset+octet-stream', (request, payload, done) => done(null)
);

/**
 * let tus handle preparation and filehandling requests
 * fastify exposes raw nodejs http req/res via .raw property
 * @see https://www.fastify.io/docs/latest/Reference/Request/
 * @see https://www.fastify.io/docs/latest/Reference/Reply/#raw
 */
fastify.all('/files', (req, res) => {
    tusServer.handle(req.raw, res.raw);
});
fastify.all('/files/*', (req, res) => {
    tusServer.handle(req.raw, res.raw);
});

fastify.listen(3000, (err) => {
    if (err) {
        fastify.log.error(err);
        process.exit(1);
    }
});

Features

Events:

Execute code when lifecycle events happen by adding event handlers to your server.

const tus = require('tus-node-server');
const EVENTS = require('tus-node-server').EVENTS;

const server = new tus.Server({ path: '/files' });
server.datastore = new tus.FileStore({ directory: './files' });

server.on(EVENTS.EVENT_UPLOAD_COMPLETE, (event) => {
    console.log(`Upload complete for file ${event.file.id}`);
});
  • EVENT_FILE_CREATED: Fired when a POST request successfully creates a new file

    Example payload:

    {
        file: {
            id: '7b26bf4d22cf7198d3b3706bf0379794',
            upload_length: '41767441',
            upload_metadata: 'filename NDFfbWIubXA0'
         }
    }
  • EVENT_ENDPOINT_CREATED: Fired when a POST request successfully creates a new upload endpoint

    Example payload:

    {
        url: 'http://localhost:1080/files/7b26bf4d22cf7198d3b3706bf0379794'
    }
  • EVENT_UPLOAD_COMPLETE: Fired when a PATCH request finishes writing the file

    Example payload:

    {
        file: {
            id: '7b26bf4d22cf7198d3b3706bf0379794',
            upload_length: '41767441',
            upload_metadata: 'filename NDFfbWIubXA0'
        }
    }
  • EVENT_FILE_DELETED: Fired when a DELETE request finishes deleting the file

    Example payload:

    {
        file_id: '7b26bf4d22cf7198d3b3706bf0379794'
    
    }

Custom GET handlers:

Add custom GET handlers to suit your needs, similar to Express routing.

const server = new tus.Server({ path: '/files' });
server.datastore = new tus.FileStore({ directory: './files' });

server.get('/uploads', (req, res) => {
    // Read from your DataStore
    fs.readdir(server.datastore.directory, (err, files) => {
        // Format the JSON response and send it
    }
});

Custom file names:

The default naming of files is a random crypto hex string. When using your own namingFunction, make sure to create URL friendly names such as removing spaces.

const crypto = require('crypto');

// req is http.IncomingMessage
const randomString = (req) => {
    // same as the default implementation
    return crypto.randomBytes(16).toString('hex');
}

const server = new tus.Server({
    path: '/files',
    namingFunction: randomString,
});

Development

Start the demo server using Local File Storage

$ npm run demo

Or start up the demo server using Google Cloud Storage

$ npm run gcs_demo

Then navigate to the demo (localhost:1080) which uses tus-js-client