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 Hapi Integration #212

Open
corusm opened this issue Mar 27, 2022 · 3 comments
Open

Add Hapi Integration #212

corusm opened this issue Mar 27, 2022 · 3 comments

Comments

@corusm
Copy link

corusm commented Mar 27, 2022

Is it possible to add Hapi integration similar to this?
The Code doesn't seem to work anymore. any ideas how to fix?

@Murderlon
Copy link
Member

It's not officially supported and I haven't researched Hapi to know what is required for the integration. PRs welcome :)

@deplorable
Copy link

@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!

@m4xleb
Copy link

m4xleb commented Jul 10, 2023

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants