Skip to content

Instantly share code, notes, and snippets.

@tpoxa
Last active March 29, 2020 14:12
Show Gist options
  • Save tpoxa/a6af52836264b699ab0fb52a70553b0c to your computer and use it in GitHub Desktop.
Save tpoxa/a6af52836264b699ab0fb52a70553b0c to your computer and use it in GitHub Desktop.
This code helps to upload/download Google Cloud Objects of large size without dealing actually with object's bytes in Go
package main
import (
"bytes"
"cloud.google.com/go/storage"
"context"
"fmt"
"github.com/motemen/go-loghttp"
"github.com/pkg/errors"
"github.com/spf13/viper"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
htransport "google.golang.org/api/transport/http"
"io/ioutil"
"log"
"net/http"
"time"
)
var storageClient *http.Client
func initStorageClient() {
ctx := context.Background()
var err error
// obtain first JSON credential file for service account
storageClient, _, err = htransport.NewClient(ctx, option.WithScopes(storage.ScopeFullControl),
option.WithCredentialsFile(viper.GetString("GOOGLE_CREDENTIALS_FILE")))
if err != nil {
log.Fatalln(err)
}
// just for logs, wrapper could be removed
storageClient.Transport = &loghttp.Transport{
Transport: storageClient.Transport,
LogRequest: func(req *http.Request) {
log.Printf("--> %s %s", req.Method, req.URL)
},
}
}
// obtains url ready to send data
// save this url per each object for 1 week maximum
// anyone having this URL able to upload given object, so take care about security
func getResumableUploadUrl(bucket, object string) (*string, error) {
req, err := http.NewRequest("POST", fmt.Sprintf("https://storage.googleapis.com/upload/storage/v1/b/%s/o?uploadType=resumable&name=%s", bucket, object), bytes.NewBuffer(nil))
if err != nil {
return nil, err
}
resp, err := storageClient.Do(req)
if err != nil {
return nil, err
}
location := resp.Header.Get("Location")
if location == "" {
return nil, errors.New("no redirect url")
}
return &location, nil
}
// gets signed url to download object
func getDownloadUrl(bucket, object string) (*string, error) {
jsonKey, err := ioutil.ReadFile(viper.GetString("GOOGLE_CREDENTIALS_FILE"))
if err != nil {
return nil, fmt.Errorf("cannot read the JSON key file, err: %v", err)
}
conf, err := google.JWTConfigFromJSON(jsonKey)
if err != nil {
return nil, fmt.Errorf("google.JWTConfigFromJSON: %v", err)
}
opts := &storage.SignedURLOptions{
Scheme: storage.SigningSchemeV4,
Method: "GET",
GoogleAccessID: conf.Email,
PrivateKey: conf.PrivateKey,
Expires: time.Now().Add(15 * time.Minute),
}
u, err := storage.SignedURL(bucket, object, opts)
if err != nil {
return nil, fmt.Errorf("unable to generate a signed URL: %v", err)
}
return &u, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment