Skip to content

Commit

Permalink
implement GET handler
Browse files Browse the repository at this point in the history
  • Loading branch information
mitjap committed Jun 12, 2021
1 parent 8bffceb commit e4c10dd
Show file tree
Hide file tree
Showing 8 changed files with 5,930 additions and 24 deletions.
17 changes: 4 additions & 13 deletions lib/Server.js
Expand Up @@ -10,6 +10,7 @@ const http = require('http');
const EventEmitter = require('events');

const DataStore = require('./stores/DataStore');
const GetHandler = require('./handlers/GetHandler');
const HeadHandler = require('./handlers/HeadHandler');
const OptionsHandler = require('./handlers/OptionsHandler');
const PatchHandler = require('./handlers/PatchHandler');
Expand Down Expand Up @@ -76,7 +77,7 @@ class TusServer extends EventEmitter {
// eg.
// const server = new tus.Server();
// server.get('/', (req, res) => { ... });
GET: {},
GET: new GetHandler(store),

// These methods are handled under the tus protocol
HEAD: new HeadHandler(store),
Expand All @@ -97,7 +98,7 @@ class TusServer extends EventEmitter {
get(path, callback) {

// Add this handler callback to the GET method handler list.
this.handlers.GET[path] = callback;
this.handlers.GET.registerPath(path, callback);
}

/**
Expand All @@ -119,17 +120,7 @@ class TusServer extends EventEmitter {


if (req.method === 'GET') {

// Check if this url has been added to allow GET requests, with an
// appropriate callback to handle the request
if (!(req.url in this.handlers.GET)) {
res.writeHead(404, {});
res.write('Not found\n');
return res.end();
}

// invoke the callback
return this.handlers.GET[req.url](req, res);
return this.handlers.GET.send(req, res);
}

// The Tus-Resumable header MUST be included in every request and
Expand Down
74 changes: 74 additions & 0 deletions lib/handlers/GetHandler.js
@@ -0,0 +1,74 @@
'use strict';

const stream = require('stream');

const BaseHandler = require('./BaseHandler');
const ERRORS = require('../constants').ERRORS;
const debug = require('debug');
const log = debug('tus-node-server:handlers:get');

class GetHandler extends BaseHandler {
constructor(store) {
super(store);

this.paths = new Map();
}

registerPath(path, handler) {
this.paths.set(path, handler);
}

/**
* Read data from the DataStore and send the stream.
*
* @param {object} req http.incomingMessage
* @param {object} res http.ServerResponse
* @return {function}
*/
send(req, res) {
// Check if this url has been added to allow GET requests, with an
// appropriate callback to handle the request
if (this.paths.has(req.url)) {
// invoke the callback
return this.paths.get(req.url)(req, res);
}

return Promise.resolve()
.then(() => {
if (!('read' in this.store)) {
return Promise.reject(ERRORS.FILE_NOT_FOUND);
}

const file_id = this.getFileIdFromRequest(req);
if (file_id === false) {
return Promise.reject(ERRORS.FILE_NOT_FOUND);
}

return this.store.getOffset(file_id)
.then((stats) => {
const upload_length = parseInt(stats.upload_length, 10);
if (stats.size !== upload_length) {
log(`[GetHandler] send: File is not yet fully uploaded (${stats.size}/${upload_length})`);
return Promise.reject(ERRORS.FILE_NOT_FOUND);
}

const file_stream = this.store.read(file_id);
const headers = {
'Content-Length': stats.size,
};
res.writeHead(200, headers);
return stream.pipeline(file_stream, res, (err) => {
// we have no need to handle streaming errors
});
});
})
.catch((error) => {
log('[GetHandler]', error);
const status_code = error.status_code || ERRORS.UNKNOWN_ERROR.status_code;
const body = error.body || `${ERRORS.UNKNOWN_ERROR.body}${error.message || ''}\n`;
return super.send(res, status_code, {}, body);
});
}
}

module.exports = GetHandler;
11 changes: 11 additions & 0 deletions lib/stores/FileStore.js
Expand Up @@ -91,6 +91,17 @@ class FileStore extends DataStore {
});
}

/** Get file from filesystem
*
* @param {string} file_id Name of the file
*
* @return {stream.Readable}
*/
read(file_id) {
const path = `${this.directory}/${file_id}`;
return fs.createReadStream(path);
}

/**
* Write to the file, starting at the provided offset
*
Expand Down
10 changes: 10 additions & 0 deletions lib/stores/GCSDataStore.js
Expand Up @@ -114,6 +114,16 @@ class GCSDataStore extends DataStore {
});
}

/** Get file from GCS storage
*
* @param {string} file_id Name of the file
*
* @return {stream.Readable}
*/
read(file_id) {
return this.bucket.file(file_id).createReadStream();
}

/**
* Get the file metatata from the object in GCS, then upload a new version
* passing through the metadata to the new version.
Expand Down

0 comments on commit e4c10dd

Please sign in to comment.