Last active
March 29, 2020 14:12
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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