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

md5_worker.js fails with 'require is not defined' #7

Closed
dvandegrift opened this issue Nov 6, 2017 · 10 comments
Closed

md5_worker.js fails with 'require is not defined' #7

dvandegrift opened this issue Nov 6, 2017 · 10 comments

Comments

@dvandegrift
Copy link

dvandegrift commented Nov 6, 2017

I cloned the repo and copied dist/* to my Angular 4.4.6 application (both under node_modules/ts-md5/dist and src/assets). Then attempted to md5sum a file per the following snippet.

import { Md5 } from 'ts-md5/dist/md5';
import { ParallelHasher } from 'ts-md5/dist/parallel_hasher';
...
    for (let i = 0; i < this.filesToUpload.length; i++) {
      const fileReader = new FileReader();
      fileReader.onload = function(e : ProgressEvent) {
        let hasher = new ParallelHasher('assets/md5_worker.js');
        hasher.hash(fileReader.result)
          .then(function(result) {
            console.log('hash: ' + result);
          });
        const md5 = new Md5();
         md5.appendByteArray(fileReader.result);
        console.log("hash: " + md5.end()); // this isn't correct. 
      };
      fileReader.readAsBinaryString(this.filesToUpload[i]);

When running the app, Chrome's console shows:
ErrorEvent {isTrusted: true, message: "Uncaught ReferenceError: require is not defined", filename: "http://localhost:4200/assets/md5_worker.js", lineno: 401, colno: 13, …}

Line 401 of md5_worker.js corresponds to this statement:
`var md5_1 = require("./md5");

Is RequireJS meant to be a prerequisite of ts-md5?

As a secondary but related issue:
I had first tried using the latest version (v1.2.2) of ts-md5 from NPM. But it also failed with:
ErrorEvent {isTrusted: true, message: "Uncaught TypeError: Md5.Md5 is not a constructor", filename: "http://localhost:4200/assets/md5_worker.js", lineno: 417, colno: 21, …} Uncaught TypeError: Md5.Md5 is not a constructor at Md5FileHasher.hash (md5_worker.js:417) at global.onmessage (md5_worker.js:502)

Line 417 of md5_worker.js corresponds to:

    Md5FileHasher.prototype.hash = function (blob) {
        var self = this;
        self._blob = blob;
        self._length = Math.ceil(blob.size / self._partSize);
        self._part = 0;
        self._md5 = new Md5.Md5();   <---  FAILS HERE
        self._processPart();
    };

So md5_worker.js doesn't work whether it's from
a. the head of git: "Uncaught ReferenceError: require is not defined"
b. or NPM: "Uncaught TypeError: Md5.Md5 is not a constructor"

And FYI, the version on NPM is a few months out-of-date compared to git.

I'd appreciate any help getting the file hashing feature of ts-md5 operational in my app.

Thanks,
David

(Sorry for the earlier, empty post. I accidentally hit Enter just as I had started composing this).

@dvandegrift dvandegrift changed the title md5_worker.js fails with 'require is not defined md5_worker.js fails with 'require is not defined' Nov 6, 2017
@santhosh-rajashekar
Copy link

santhosh-rajashekar commented Nov 20, 2017

Md5FileHasher.prototype.hash = function(blob) {
var self = this;
self._blob = blob;
self._length = Math.ceil(blob.size / self._partSize);
self._part = 0;
self._md5 = new Md5(); // changed from new Md5.Md5() to new Md5()
self._processPart();
};

above change worked for me..

I am looking if there is a better solution than giving the path of the file to ParallelHasher
let hasher = new ParallelHasher('assets/md5_worker.js');

since i do not prepfer to copy the 'md5_worker.js' from node_modules folder and copy it to 'assets' folder

@dvandegrift
Copy link
Author

I ended up doing this:

  onSubmit() {
    const fileHashPromises: Promise<any>[] = [];
    for (let i = 0; i < this.filesToUpload.length; i++) {
      fileHashPromises.push(this.hashFile(this.filesToUpload[i], formData));
    }

    Promise.all(fileHashPromises)
      .then(r => {
        this.myService.submitToServer(formData)
          .then(response => {
            console.log('success: ');
      })
      .catch(error => {
        // Failed to md5 hash one or more files.
        console.log(error);
      });
  }


  private hashFile(file: File, formData: FormData): Promise<any> {
    const chunkSize = 2097152; // Read files in chunks of 2MB
    return new Promise<any>(
      (resolve, reject) => {
        // console.log('Starting hash for ' + file.name);
        const chunks = Math.ceil(file.size / chunkSize);
        const md5 = new Md5();
        const fileReader = new FileReader();

        let currentChunk = 0;
        let start = currentChunk * chunkSize;
        let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

        fileReader.readAsArrayBuffer(file.slice(start, end));

        fileReader.onload = function (e: ProgressEvent) {
          md5.appendByteArray(new Uint8Array(fileReader.result));
          currentChunk++;
          if (currentChunk < chunks) {
            start = currentChunk * chunkSize;
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
            fileReader.readAsArrayBuffer(file.slice(start, end));
          } else {
            const md5sum = <string>md5.end(); // compute hash
            console.log(file.name + ' computed md5sum ' + md5sum);
            formData.append('files', file);
            formData.append('md5-' + file.webkitRelativePath, md5sum);
            resolve('success');
          }
        };

        fileReader.onerror = function (e: ErrorEvent) {
          console.error('Failed to calculate MD5 sum for ' + file.name, e);
          reject('Failed to calculate MD5 sum for ' + file.name + '. ' + e);
        };
      }
    );
  }

For a more generic solution, the promise could've returned the md5sum instead of appending to formData but the above suited my needs.

@zakhenry
Copy link

This is still an issue, however a previous commit does work so if you add the following to package.json you might get success

"ts-md5": "github:cotag/ts-md5#ed4ea0ef4b916922dfdf870030d6e144b4088fad",

@stakach
Copy link
Member

stakach commented Jan 15, 2018

Thanks, I've published a new version

@stakach stakach closed this as completed Jan 15, 2018
@zakhenry
Copy link

@stakach thanks for the new version, but the webworker still throws Uncaught TypeError: Md5.Md5 is not a constructor with the new version.

@stakach stakach reopened this Jan 15, 2018
@stakach
Copy link
Member

stakach commented Jan 15, 2018

If you change the line like this does it work?
self._md5 = new Md5();

The project that we built this library for hasn't required an update in awhile so whilst we still technically rely on this we're not actively using it at the moment.

@jgrtalk
Copy link

jgrtalk commented Jan 29, 2018

Same issue here :
Uncaught TypeError: Md5.Md5 is not a constructor

Changing the line from :
self._md5 = new Md5.Md5(); (md5_worker.js:417)
to :
self._md5 = new Md5();

do resolve the issue.

@stakach
Copy link
Member

stakach commented Jan 29, 2018

fixed in release 1.2.4

@stakach stakach closed this as completed Jan 29, 2018
@dvandegrift
Copy link
Author

Thanks for the fix! I downloaded 1.2.4 and successfully hashed files using the ParallelHasher. For example:

    let hasher = new ParallelHasher('assets/md5_worker.js');
    for (let i = 0; i < this.filesToUpload.length; i++) {
      const fileX = this.filesToUpload[i];
      hasher.hash(fileX)
        .then(function (result) {
          console.log(fileX.name + ' hash: ' + result);
        });
    }

Using ParallelHasher let me shrink my hashFile() method substantially as seen here versus my Nov 20th posting.

  onSubmit() {
    const fileHashPromises: Promise<any>[] = [];
    for (let i = 0; i < this.filesToUpload.length; i++) {
      fileHashPromises.push(this.hashFile(this.filesToUpload[i], formData));
    }

    Promise.all(fileHashPromises)
      .then(r => {
        this.myService.submitToServer(formData)
          .then(response => {
            console.log('success: ');
      })
      .catch(error => {
        // Failed to md5 hash one or more files.
        console.log(error);
      });
  }

  private hashFile(file: File, formData: FormData): Promise<any> {
    return new Promise<any>(
      (resolve, reject) => {
        const hasher = new ParallelHasher('assets/md5_worker.js');
        hasher.hash(file)
          .then(function (result) {
            console.log(file.name + '  ParallelHasher hash: ' + result);
            formData.append('files', file);
            formData.append('md5-' + file.webkitRelativePath, result);
            resolve('success');
          })
          .catch(error => {
            console.error('Failed to calculate MD5 sum for ' + file.name, error);
            reject('Failed to calculate MD5 sum for ' + file.name + '.');
          });
      }
    );
  }

BTW, I now see that my original code snippet from Nov 6th was flawed because hash() directly takes the File object (well a Blob object actually), not a FileReader result. Furthermore, that code was using onload when it should've used onloadend.

@stakach
Copy link
Member

stakach commented Feb 20, 2018

@dvandegrift glad to hear that it's working well for you!
ParallelHasher should also mean that the page doesn't hang during the processing too. Great result.

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

No branches or pull requests

5 participants