package s3browser import ( "context" "fmt" "io" "log" "net/http" "path/filepath" "time" "github.com/graph-gophers/dataloader" "github.com/graphql-go/graphql" "github.com/graphql-go/handler" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) // AppConfig general config type AppConfig struct { S3Endoint string S3AccessKey string S3SecretKey string S3SSL bool S3Buket string CacheTTL time.Duration CacheCleanup time.Duration } // File represents a file with its metadata type File struct { ID string `json:"id"` Name string `json:"name"` Size int64 `json:"size"` ContentType string `json:"contentType"` ETag string `json:"etag"` } // Directory represents a directory with its metadata type Directory struct { ID string `json:"id"` Name string `json:"name"` Files []File `json:"files"` Directorys []Directory `json:"directorys"` } var bucketName = "dev" // initHttp setup and start the http server. Blocking func initHttp(schema graphql.Schema, s3Client *minio.Client, loaderMap map[string]*dataloader.Loader) { h := handler.New(&handler.Config{ Schema: &schema, Pretty: true, GraphiQL: false, Playground: true, }) resolveContext := context.WithValue(context.Background(), "s3Client", s3Client) resolveContext = context.WithValue(resolveContext, "loader", loaderMap) http.HandleFunc("/graphql", func(rw http.ResponseWriter, r *http.Request) { h.ContextHandler(resolveContext, rw, r) }) http.HandleFunc("/api/file", func(rw http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") objInfo, err := s3Client.StatObject(context.Background(), bucketName, id, minio.GetObjectOptions{}) if err != nil { rw.WriteHeader(500) return } reqEtag := r.Header.Get("If-None-Match") if reqEtag == objInfo.ETag { rw.WriteHeader(304) return } obj, err := s3Client.GetObject(context.Background(), bucketName, id, minio.GetObjectOptions{}) if err != nil { rw.WriteHeader(500) return } rw.Header().Set("Cache-Control", "must-revalidate") rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base((objInfo.Key)))) rw.Header().Set("Content-Type", objInfo.ContentType) rw.Header().Set("ETag", objInfo.ETag) io.Copy(rw, obj) }) http.ListenAndServe(":8080", nil) } // setupS3Client connect the s3Client func setupS3Client(config AppConfig) *minio.Client { minioClient, err := minio.New(config.S3Endoint, &minio.Options{ Creds: credentials.NewStaticV4(config.S3AccessKey, config.S3SecretKey, ""), Secure: config.S3SSL, }) if err != nil { log.Fatalln(err) } exists, err := minioClient.BucketExists(context.Background(), config.S3Buket) if err != nil { log.Fatalln(err) } if !exists { log.Fatalf("Bucket '%s' does not exist", config.S3Buket) } else { log.Print("S3 client connected") } return minioClient } // Start starts the app func Start(config AppConfig) { s3Client := setupS3Client(config) loader := createDataloader(config) graphqlTypes() schema, err := graphqlSchema() if err != nil { log.Panic(err) } initHttp(schema, s3Client, loader) }