github.com/l3x/learn-fp-go@v0.0.0-20171228022418-7639825d0b71/2-design-patterns/ch06-onion-arch/04_onion/src/infrastructure/gcphandler.go (about) 1 package infrastructure 2 3 import ( 4 "cloud.google.com/go/storage" 5 "context" 6 "google.golang.org/api/option" 7 "domain" 8 "google.golang.org/api/iterator" 9 . "utils" 10 "io/ioutil" 11 "os" 12 "io" 13 "interfaces" 14 "usecases" 15 "github.com/pkg/errors" 16 ) 17 18 type GcpHandler struct { 19 Client *storage.Client 20 } 21 22 var GcpInteractor *usecases.GcpInteractor 23 24 func NewGcpHandler(keyFile string) (gcpHandler *GcpHandler, err error) { 25 ctx := context.Background() 26 client, err := storage.NewClient(ctx, option.WithServiceAccountFile(keyFile)) 27 if err != nil { 28 return nil, errors.Wrap(err, "unable to create a new storage client") 29 } 30 gcpHandler = new(GcpHandler) 31 gcpHandler.Client = client 32 return 33 } 34 35 func (handler *GcpHandler) ListBuckets(flowType domain.FlowType, projectId string) (buckets []domain.Bucket, err error) { 36 Debug.Printf("Running: ListBuckets(%v, %v)", flowType, projectId) 37 client := handler.Client 38 ctx := context.Background() 39 it := client.Buckets(ctx, projectId) 40 for { 41 battrs, err := it.Next() 42 if err == iterator.Done { 43 break 44 } 45 if err != nil { 46 return nil, errors.Wrap(err, "bucket iterator error") 47 } 48 buckets = append(buckets, domain.Bucket{battrs.Name}) 49 } 50 return 51 } 52 53 func (handler *GcpHandler) FileExists(fileName string) (fileExists bool, err error) { 54 ctx := context.Background() 55 bucketName := Config.SourceBucketName 56 newFile := domain.NewFile(fileName) 57 fullPath := newFile.FullHostPath(Config.GcpSourceDir) 58 Debug.Printf("fullPath: %s", fullPath) 59 br, err := handler.Client.Bucket(bucketName).Object(fullPath).NewReader(ctx) 60 if err != nil { 61 return false, errors.Wrapf(err, "bucket reader error for %s", fullPath) 62 } else { 63 data, err := ioutil.ReadAll(br) 64 defer br.Close() 65 if err != nil { 66 return false, errors.Wrapf(err, "ioutil.ReadAll error for %s", fullPath) 67 } else if len(data) == 0 { 68 return false, errors.Wrapf(err, "File size must be greater than 0 for %s", fullPath) 69 } 70 } 71 return true, err 72 } 73 74 func (handler *GcpHandler) GetBucketObject(flowType domain.FlowType, projectId string, bucketName string, fileName string) storage.ObjectHandle { 75 client := handler.Client 76 fileObject := client.Bucket(bucketName).Object(fileName) 77 return *fileObject 78 } 79 80 func (handler *GcpHandler) DownloadFile(fileName string) (success bool, err error) { 81 newFile := domain.NewFile(fileName) 82 fullFilePath := newFile.FullHostPath(Config.GcpSourceDir) 83 Debug.Printf("fullFilePath: %s", fullFilePath) 84 ctx := context.Background() 85 86 Debug.Printf("Config.GcpSourceProjectId: %s", Config.GcpSourceProjectId) 87 Debug.Printf("Config.SourceBucketName: %s", Config.SourceBucketName) 88 Debug.Printf("fullFilePath: %s", fullFilePath) 89 90 91 bucketObject := handler.GetBucketObject(domain.SourceFlow, Config.GcpSourceProjectId, Config.SourceBucketName, fullFilePath) 92 fr, err := bucketObject.NewReader(ctx) 93 if err != nil { 94 return false, errors.Wrapf(err, "unable to get file (%s) from bucket(%s)", fullFilePath, Config.SourceBucketName) 95 } 96 defer fr.Close() 97 fileBytes, err := ioutil.ReadAll(fr) 98 if err != nil { 99 return false, errors.Wrap(err, "ioutil.ReadAll failed") 100 } 101 logFiles, err := newFile.Parse(fileBytes) 102 if err != nil { 103 return false, errors.Wrap(err, "newFile.Parse failed") 104 } 105 success = true 106 var logFileName string 107 var cachedLogFiles []string 108 for i, logFile := range *logFiles { 109 logFileName = newFile.FullParsedFileName(i) 110 Info.Println("Encoding, caching and saving logFileName: "+logFileName) 111 logFileJson, err := logFile.ToJson() 112 if err != nil { 113 Error.Printf("Unable to encode logFileName (%s) - ERROR: %v", logFileName, err) 114 break 115 } 116 cachedLogFiles = append(cachedLogFiles, logFileJson) 117 logFile.Write(logFileName, logFileJson) 118 } 119 return 120 } 121 122 func (handler *GcpHandler) UploadFile(fileName string) (success bool, err error) { 123 ctx := context.Background() 124 newFile := domain.NewFile(fileName) 125 newFullPath := newFile.FullLocalPath() 126 f, err := os.Open(newFullPath) 127 if err != nil { 128 return false, errors.Wrapf(err, "unable to open local file: %s", newFullPath) 129 } 130 defer f.Close() 131 bucketObject := handler.GetBucketObject(domain.SinkFlow, Config.GcpSinkProjectId, Config.SinkBucketName, newFile.FullHostPath(Config.GcpSinkDir)) 132 wc := bucketObject.NewWriter(ctx) 133 if _, err = io.Copy(wc, f); err != nil { 134 return false, errors.Wrapf(err, "io.Copy failed for %s", newFullPath) 135 } 136 if err := wc.Close(); err != nil { 137 return false, errors.Wrapf(err, "io.Close failed for %s", newFullPath) 138 } 139 success = true 140 return 141 } 142 143 func GetGcpInteractor() (gcpInteractor *usecases.GcpInteractor, err error) { 144 if GcpInteractor == nil { 145 sourceHandler, err := NewGcpHandler(Config.GcpSourceKeyFile) 146 if err != nil { 147 return nil, errors.Wrap(err, "unable to create new source gcp handler") 148 } 149 sinkHandler, err := NewGcpHandler(Config.GcpSinkKeyFile) 150 if err != nil { 151 return nil, errors.Wrap(err, "unable to create new sink gcp handler") 152 } 153 handlers := make(map[string] interfaces.GcpHandler) 154 handlers["SourceBucketRepo"] = sourceHandler 155 handlers["SinkBucketRepo"] = sinkHandler 156 gcpInteractor = new(usecases.GcpInteractor) 157 gcpInteractor.SourceBucketRepository = interfaces.NewSourceBucketRepo(handlers) 158 gcpInteractor.SinkBucketRepository = interfaces.NewSinkBucketRepo(handlers) 159 GcpInteractor = gcpInteractor 160 } 161 return GcpInteractor, err 162 } 163 164 165 166 type List interface { 167 Cons(val interface{}) List 168 ForEach(f func(interface{})) 169 Head() interface{} 170 IsNil() bool 171 Reverse() List 172 Size() int 173 Tail() List 174 } 175 176 type Map interface { 177 Delete(key string) Map 178 ForEach(f func(key string, val interface{})) 179 IsNil() bool 180 Keys() []string 181 Lookup(key string) (interface{}, bool) 182 Set(key string, value interface{}) Map 183 Size() int 184 String() string 185 UnsafeMutableSet(key string, value interface{}) Map 186 }