Example #1
0
// Upload uploads a file to a B2 bucket. If mimeType is "", "b2/x-auto" will be used.
//
// Concurrent calls to Upload will use separate upload URLs, but consequent ones
// will attempt to reuse previously obtained ones to save b2_get_upload_url calls.
// Upload URL failures are handled transparently.
//
// Since the B2 API requires a SHA1 header, normally the file will first be read
// entirely into a memory buffer. Two cases avoid the memory copy: if r is a
// bytes.Buffer, the SHA1 will be computed in place; otherwise, if r implements io.Seeker
// (like *os.File and *bytes.Reader), the file will be read twice, once to compute
// the SHA1 and once to upload.
//
// If a file by this name already exist, a new version will be created.
func (b *Bucket) Upload(r io.Reader, name, mimeType string) (*FileInfo, error) {
	var body io.ReadSeeker
	switch r := r.(type) {
	case *bytes.Buffer:
		defer r.Reset() // we are expected to consume it
		body = bytes.NewReader(r.Bytes())
	case io.ReadSeeker:
		body = r
	default:
		b, err := ioutil.ReadAll(r)
		if err != nil {
			return nil, err
		}
		body = bytes.NewReader(b)
	}

	h := sha1.New()
	length, err := io.Copy(h, body)
	if err != nil {
		return nil, err
	}
	sha1Sum := hex.EncodeToString(h.Sum(nil))

	var fi *FileInfo
	for i := 0; i < 5; i++ {
		if _, err = body.Seek(0, io.SeekStart); err != nil {
			return nil, err
		}

		fi, err = b.UploadWithSHA1(body, name, mimeType, sha1Sum, length)
		if err == nil {
			break
		}
	}
	return fi, err
}