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

Stream file in UploadImage to reduce memory usage #1469

Open
manish-baghel opened this issue Dec 19, 2023 · 0 comments
Open

Stream file in UploadImage to reduce memory usage #1469

manish-baghel opened this issue Dec 19, 2023 · 0 comments

Comments

@manish-baghel
Copy link

manish-baghel commented Dec 19, 2023

Current cloudflare-go version

latest

Description

Just wondering if the idea of streaming multipart file for uploading images has been explored or discussed before.
As far as my understanding goes, currently the UploadImage function expects a *multipart.File and reads it into memory which might become an issue for applications with large amount of traffic.
Instead of loading the file into memory, it can be streamed by streaming the file io.Reader to a io.Writer which can be piped to the request body
Please refer to my code below and sorry for my messy error handling.

Use cases

  • Save precious memory by streaming the file.
  • Better scalability

Potential cloudflare-go usage

func (c *CloudflareService) UploadImageStreamed(ctx context.Context, file io.Reader, filename string) (*cloudflare.Image, error) {
	url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/images/v1", config.GetCloudflareAccountIdentifier().Identifier)

	// Prepare the pipe and multipart writer
	pr, pw := io.Pipe()
	writer := multipart.NewWriter(pw)

	req, err := http.NewRequestWithContext(ctx, "POST", url, pr)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.GetCloudflareToken()))
	req.Header.Set("Content-Type", writer.FormDataContentType())

	// Write to the pipe in a goroutine
	errChan := make(chan error, 1)
	go func() {
		defer pw.Close()
		part, err := writer.CreateFormFile("file", filename)
		if err != nil {
			errChan <- err
			return
		}
		if _, err = io.Copy(part, file); err != nil {
			errChan <- err
			return
		}
		errChan <- writer.Close()
	}()

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if err := <-errChan; err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to upload to Cloudflare: %s", resp.Status)
	}

	var cfRes cloudflare.ImageDetailsResponse
	if err = json.NewDecoder(resp.Body).Decode(&cfRes); err != nil {
		return nil, err
	}

	return &cfRes.Result, nil
}

References

No response

@manish-baghel manish-baghel changed the title UploadImage in streaming fashion Stream file in UploadImage to save memory Dec 19, 2023
@manish-baghel manish-baghel changed the title Stream file in UploadImage to save memory Stream file in UploadImage to reduce memory usage Dec 19, 2023
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

1 participant