Add Hapi Integration
Is it possible to add Hapi integration similar to this? The Code doesn't seem to work anymore. any ideas how to fix?
It's not officially supported and I haven't researched Hapi to know what is required for the integration. PRs welcome :)
@corusm It's bad practice, but I've forked tus-node-server into hapi-tus-node-server, so anyone using Hapi can install hapi-tus-node-server and use it as a Hapi plugin. Feel free to give it a try if you like. Hat tip to everyone who posted in the thread TUS Resumable Uploads, and of course, all the awesome people who have brought us tus!
@corusm, I am trying also to implement with Hapi. I haven't use hapi-tus-node-server but I instead used the exemple in the Quick Guide and adapted it to work with Hapi.
The only issue I seem to have so fare is that the [file-id].info is empty on S3 and is not created in the file storage. I wonder if this a bug in the package or something wrong with Hapi but here's what I have came up with.
I you use hapi-cors, you have to add headers used by tus
await server.register({
plugin: require('hapi-cors'),
options: {
origins: ['*'],
headers: [
'Accept', 'Content-Type', 'Authorization',
/* EXTRA HEADERS */
'tus-resumable','upload-length','upload-metadata','x-http-method-override','upload-offset',
'x-requested-with', 'x-forwarded-host','x-forwarded-proto','Forwarded'
/* ****************** */
],
methods: ['POST, GET, PUT, DELETE, PATCH, HEAD']
}
});
Make sure to also add "PATCH and HEAD" in methods
These are the 3 routes I needed
const path = require('path');
const handlers = require(path.resolve('handlers/commons/media'));
const basic = '/api/v1/commons/media'
module.exports = [
{
method: 'PATCH',
path: basic + '/files/{any*}',
options: {
handler: handlers.uploadFiles,
description: 'Upload file',
auth: {
access: {
scope: ['clientscope:profile']
}
},
payload:{
maxBytes: 104857600,
output: 'stream',
parse: true,
multipart: true
},
tags: ['api', 'commons'],
}
},
{
method: '*',
path: basic + '/files/{any*}',
options: {
handler: handlers.uploadFiles,
description: 'Upload file',
auth: {
access: {
scope: ['clientscope:profile']
}
},
tags: ['api', 'commons'],
}
},
{
method: '*',
path: basic + '/files',
options: {
handler: handlers.uploadFiles,
description: 'Upload file',
auth: {
access: {
scope: ['clientscope:profile']
}
},
tags: ['api', 'commons'],
}
}
];
And here is my handler :
const path = require('path');
const {s3Config} = require(path.resolve("config/config"));
const {Server} = require('@tus/server')
const {S3Store} = require('@tus/s3-store')
const {FileStore} = require('@tus/file-store')
class media {
static async uploadFiles(request,h){
try{
// IF YOU WANT TO USE S3
const s3Store = new S3Store({
partSize: 8 * 2 ** 20, //If you want to use MultiParts
s3ClientConfig: s3Config,
})
// IF YOU WANT TO USE FileStore
const fileStore = new FileStore({ directory: './temp/files' })
const tusServer = new Server({
//PATH will be sent back to your frontend so make sure to set the same path as your route ex: basic + '/files/{any*}'
path: '/api/v1/commons/media/files',
datastore: s3Store, // Use fileStore if you want to use local upload
async onUploadCreate(req, res, upload) {
/*
DO YOUR STUFF HERE before it starts to upload
Eg: Save meta in DB before upload
*/
return res
},
async onUploadFinish(req, res, upload) {
/*
DO YOUR STUFF HERE after the upload is completed
Eg: Update status or do other actions
*/
return res
}
})
await tusServer.handle(request.raw.req, request.raw.res)
return h.response(); //Make sure to return a 204. you could also use h.response().code(204)
}catch (e) {
// Handle errors here
console.log(e);
return h.response().code(500)
}
}
}
module.exports = media;
I still have to figure out an issue which is an ERR_HTTP_HEADERS_SENT. I will come back it in a later time but if anyone have a fix it would be great. I hid it (FOR NOW ;) ) by adding :
process.on('unhandledRejection', (err) => {
if(err.code !== 'ERR_HTTP_HEADERS_SENT'){
console.log(err);
}
//process.exit(1);
});
in my unhandledRejection event in my app.js