whatsmeow icon indicating copy to clipboard operation
whatsmeow copied to clipboard

Upload without storing whole file in memory

Open biji opened this issue 3 years ago • 16 comments

Is it possible to Upload() big files like videos and documents without reading whole file to variable? Probably that will save some memory

Thanks

biji avatar Apr 20 '22 02:04 biji

Upload once and cache the upload result

serenity-77 avatar Apr 20 '22 04:04 serenity-77

Currently not possible, but files are also limited to 100mb so there's no problem just reading the whole file to memory.

tulir avatar May 10 '22 07:05 tulir

Upload once and cache the upload result

But it is limited in time, then you will need to upload again.

Duckduckgot avatar Jun 12 '22 03:06 Duckduckgot

Client.Upload encrypt whole []byte in code before uploaded.

https://github.com/tulir/whatsmeow/blob/be0edabb0bf3d3f6401d9e6d9922373ed58a3487/upload.go#L63-L134

Seems impossible to implement io Reader directly from path to avoid high memory usage.

mamur-rezeki avatar Jun 19 '23 02:06 mamur-rezeki

It's of course possible to implement, just requires a bunch of refactoring

tulir avatar Jun 19 '23 08:06 tulir

Alright, we will wait for it to be implement.

mamur-rezeki avatar Jun 19 '23 08:06 mamur-rezeki

Someone please help to realize this useful feature.

Duckduckgot avatar Aug 03 '23 18:08 Duckduckgot

Something's wrong. Download failure at the recipient

func EncryptStream(key, iv []byte, reader io.Reader, writer io.Writer) error {
	block, err := aes.NewCipher(key)
	if err != nil {
		return err
	}

	var stream cipher.Stream
	if iv != nil {
		stream = cipher.NewCFBEncrypter(block, iv)
	} else {
		iv = make([]byte, aes.BlockSize)
		if _, err := io.ReadFull(rand.Reader, iv); err != nil {
			return err
		}

		stream = cipher.NewCFBEncrypter(block, iv)
		writer.Write(iv)
	}

	writer = &cipher.StreamWriter{S: stream, W: writer}

	if _, err := io.Copy(writer, reader); err != nil {
		return err
	}

	return nil
}

Duckduckgot avatar Aug 06 '23 17:08 Duckduckgot

func encryptStream(key, iv, macKey []byte, reader io.Reader, writer io.Writer) ([]byte, []byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}
	h1 := sha256.New()
	if _, err := io.Copy(h1, reader); err != nil {
		return nil, nil, err
	}
	FileSHA256 := h1.Sum(nil)
	var buf bytes.Buffer
	stream := cipher.NewCFBEncrypter(block, iv)
	encWriter := &cipher.StreamWriter{S: stream, W: &buf}

	h := hmac.New(sha256.New, macKey)
	if _, err := io.Copy(h, reader); err != nil {
		return nil, nil, err
	}
	mac := h.Sum(nil)
	mac10 := mac[:10]

	h2 := sha256.New()
	if _, err := io.Copy(encWriter, reader); err != nil {
		return nil, nil, err
	}
	if _, err := writer.Write(mac10); err != nil {
		return nil, nil, err
	}
	if _, err := io.Copy(h2, &buf); err != nil {
		return nil, nil, err
	}
	FileEncSHA256 := h2.Sum(nil)

	return FileSHA256, FileEncSHA256, nil
}

Duckduckgot avatar Aug 13 '23 15:08 Duckduckgot

func encryptStream(key, iv, macKey []byte, reader io.Reader, writer io.Writer) ([]byte, []byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}
	h1 := sha256.New()
	if _, err := io.Copy(h1, reader); err != nil {
		return nil, nil, err
	}
	FileSHA256 := h1.Sum(nil)
	var buf bytes.Buffer
	stream := cipher.NewCFBEncrypter(block, iv)
	encWriter := &cipher.StreamWriter{S: stream, W: &buf}

	h := hmac.New(sha256.New, macKey)
	if _, err := io.Copy(h, reader); err != nil {
		return nil, nil, err
	}
	mac := h.Sum(nil)
	mac10 := mac[:10]

	h2 := sha256.New()
	if _, err := io.Copy(encWriter, reader); err != nil {
		return nil, nil, err
	}
	if _, err := writer.Write(mac10); err != nil {
		return nil, nil, err
	}
	if _, err := io.Copy(h2, &buf); err != nil {
		return nil, nil, err
	}
	FileEncSHA256 := h2.Sum(nil)

	return FileSHA256, FileEncSHA256, nil
}

you make it work?

ahmedRSA avatar Sep 12 '23 17:09 ahmedRSA

i can make it but it requires temporary file to place the enc data, if thats not a problem i'll do pull request

edit: ill find out to avoid that

arugaz avatar Nov 22 '23 16:11 arugaz

i can make it but it requires temporary file to place the enc data, if thats not a problem i'll do pull request

edit: ill find out to avoid that

Is there any progress?

Duckduckgot avatar Jan 08 '24 15:01 Duckduckgot

@Duckduckgot any progress?

gamersindo1223 avatar Mar 20 '24 02:03 gamersindo1223

According to @arugaz comment.

Temporarily storing plaintext and dataToUpload to disk for read-write may reduce RAM memory usage rather than use buffer variable like bytes.Reader or []byte to pass to the another func.

mamur-rezeki avatar Mar 29 '24 14:03 mamur-rezeki

yeah

gamersindo1223 avatar Mar 30 '24 11:03 gamersindo1223