Search code examples
javascriptblobnodeschunksadonis.js

How to load a large file into Adonis JS divided into chunks?


I'm doing the server side of the site on the Adonis JS framework. I have been tasked with loading large files, to solve this problem I decided to use file loading by chunks. I have found some client-side code and it seems to work.

Here is the code on client side: https://codepen.io/chaly7500/pen/YzQyZNR

The code on the server side:

//routes.ts.

apiGroup('v1', 'files', Route.group(async () => {
  Route.post('upload', 'Files/UploadController.index')
}))
//UploadController.ts.
'use strict'
import {HttpContextContract} from "@ioc:Adonis/Core/HttpContext";
import MediaRepositories from "App/Repositories/MediaRepositories";

export default class UploadController {
   public async index({request}:HttpContextContract){

     const file = request.file('file')
     // console.log(file)
     return await MediaRepositories.createMedia(file)
   }
}

//MediaRepositories.ts

'use strict'
Import Application from "@ioc:Adonis/Core/Application";


export default class MediaRepositories {


  static async createMedia(file) {
    await file.move(Application.publicPath('media/transientmodels'))
  }

  static async updateMediaById(){

  }

  static async updateMediaByIds(){

  }
}

After uploading to the server, I have a blob file And when I change the blob file to blob.png the image breaks

Has anyone implemented uploading large files using AdonisJS?

Or how to correctly convert blob file to image or video?

Main question: How to upload big files to adonis and not get request timeout error ?


Solution

  • I was able to solve the loading problem with this library https://www.npmjs.com/package/file-chunked

    //UploadController.ts
    'use strict'
    import {HttpContextContract} from "@ioc:Adonis/Core/HttpContext";
    import parseJson from "parse-json";
    import MediaRepositories from "App/Repositories/MediaRepositories";
    export default class UploadController {
      public async index({request}:HttpContextContract){
        
        const file = await request.file('file')
        const chunkMetaDataStr = await request.input('chunkMetadata');
        const chunkMetaData = await parseJson(chunkMetaDataStr);
        return await MediaRepositories.createMedia(file, chunkMetaData)
    
      }
    }
    
    
    // MediaRepositories.ts
    'use strict'
    import Application from "@ioc:Adonis/Core/Application";
    import FileChunked from "file-chunked";
    import * as fs from "fs";
    import Media from "App/Models/Media";
    import Env from '@ioc:Adonis/Core/Env'
    
    export default class MediaRepositories {
    
    
      static async createMedia(file, chunkMetaData) {
    
        await file?.move(Application.publicPath('media/transientmodels/' + chunkMetaData.FileGuid + '/tmp_chunks'));
    
        await FileChunked.upload({
          chunkStorage: Application.publicPath('media/transientmodels/' + chunkMetaData.FileGuid), // where the uploaded file(chunked file in this case) are saved
          uploadId: chunkMetaData.FileGuid,
          chunkIndex: chunkMetaData.Index,
          totalChunksCount: chunkMetaData.TotalCount,
          filePath: file?.filePath,
        });
    
        if (chunkMetaData.Index == (chunkMetaData.TotalCount - 1)) {
         
            fs.copyFileSync(Application.publicPath('media/transientmodels/' + chunkMetaData.FileGuid + '/tmp_chunks/' + file.clientName),
              Application.publicPath('media/transientmodels/' + chunkMetaData.FileGuid + '/tmp_chunks/' + chunkMetaData.FileName));
    
     
        }
    
        
      }
    }