# MinIO Package Usage Examples ## Basic Setup ```go package main import ( "context" "log" "path/to/pkg/minio" ) // Implement the Logger interface type SimpleLogger struct{} func (l *SimpleLogger) Info(message string, fields map[string]interface{}) { log.Printf("[INFO] %s: %+v", message, fields) } func (l *SimpleLogger) Error(message string, fields map[string]interface{}) { log.Printf("[ERROR] %s: %+v", message, fields) } func (l *SimpleLogger) Debug(message string, fields map[string]interface{}) { log.Printf("[DEBUG] %s: %+v", message, fields) } func (l *SimpleLogger) Warn(message string, fields map[string]interface{}) { log.Printf("[WARN] %s: %+v", message, fields) } func main() { // Create configuration config := minio.Config{ Endpoint: "localhost:9000", AccessKeyID: "minioadmin", SecretAccessKey: "minioadmin", UseSSL: false, DefaultBucket: "files", HierarchicalBucket: "documents", } // Create logger logger := &SimpleLogger{} // Create connection manager connManager, err := minio.NewConnectionManager(config, logger) if err != nil { log.Fatal("Failed to create connection manager:", err) } // Connect to MinIO if err := connManager.Connect(); err != nil { log.Fatal("Failed to connect to MinIO:", err) } defer connManager.Disconnect(context.Background()) // Create service service := minio.NewService(connManager, config, logger) // Use the service... } ``` ## Normal File Storage ### Upload an Image ```go func uploadImage(service *minio.Service) error { // Open image file file, err := os.Open("profile.jpg") if err != nil { return err } defer file.Close() // Upload to normal storage return service.Upload(context.Background(), "files", "images/profile.jpg", file, minio.UploadOptions{ ContentType: "image/jpeg", Metadata: map[string]string{ "user_id": "12345", "type": "profile_image", }, }) } ``` ### Download and Serve a File ```go func serveFile(service *minio.Service, w http.ResponseWriter, bucket, objectName string) error { // Download file reader, err := service.Download(context.Background(), bucket, objectName, minio.DownloadOptions{}) if err != nil { return err } defer reader.Close() // Get file info for headers info, err := service.GetInfo(context.Background(), bucket, objectName) if err != nil { return err } // Set response headers w.Header().Set("Content-Type", info.ContentType) w.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size)) // Copy file content to response _, err = io.Copy(w, reader) return err } ``` ### Upload with Stream Processing ```go func uploadWithProgress(service *minio.Service, file io.Reader, filename string) error { // Create a progress reader progressReader := &ProgressReader{ Reader: file, Total: 0, // Set total size if known Reporter: func(bytesRead int64) { log.Printf("Uploaded %d bytes", bytesRead) }, } return service.Upload(context.Background(), "files", "uploads/"+filename, progressReader, minio.UploadOptions{ ContentType: mime.TypeByExtension(filepath.Ext(filename)), }) } type ProgressReader struct { Reader io.Reader Total int64 Reporter func(bytesRead int64) } func (pr *ProgressReader) Read(p []byte) (int, error) { n, err := pr.Reader.Read(p) if n > 0 && pr.Reporter != nil { pr.Total += int64(n) pr.Reporter(pr.Total) } return n, err } ``` ## Hierarchical Document Storage ### Upload a Contract ```go func uploadContract(service *minio.Service) error { // Open contract file file, err := os.Open("contract.pdf") if err != nil { return err } defer file.Close() // Upload to hierarchical storage docPath, err := service.UploadDocument(context.Background(), file, "service_contract.pdf", minio.HierarchicalUploadOptions{ UploadOptions: minio.UploadOptions{ ContentType: "application/pdf", Metadata: map[string]string{ "contract_id": "CTR-2024-001", "client_id": "CLIENT-123", "value": "50000.00", "signed": "true", "department": "legal", }, }, Category: "contracts", SubCategory: "2024", Tags: []string{"legal", "service", "active"}, }) if err != nil { return err } log.Printf("Contract uploaded to: %s", docPath) // Output: contracts/2024/legal_service_active/1640995200/service_contract.pdf return nil } ``` ### List Documents by Category ```go func listContractsByYear(service *minio.Service, year string) error { result, err := service.ListDocuments(context.Background(), "contracts", year, minio.ListOptions{ MaxKeys: 50, }) if err != nil { return err } log.Printf("Found %d documents in contracts/%s", len(result.Objects), year) for _, doc := range result.Objects { log.Printf("- %s (%d bytes)", doc.Name, doc.Size) } return nil } ``` ### Search Documents ```go func searchLegalDocuments(service *minio.Service) error { result, err := service.SearchDocuments(context.Background(), "legal", "contracts", "2024", minio.ListOptions{ MaxKeys: 20, }) if err != nil { return err } log.Printf("Found %d legal documents", len(result.Objects)) return nil } ``` ## File Operations ### Copy Files Between Buckets ```go func backupFile(service *minio.Service, srcBucket, srcObject, destBucket, destObject string) error { return service.Copy(context.Background(), srcBucket, srcObject, destBucket, destObject) } ``` ### Generate Presigned URLs ```go func generateDownloadLink(service *minio.Service, bucket, objectName string) (string, error) { // Generate URL valid for 1 hour return service.GetPresignedURL(context.Background(), bucket, objectName, 3600) } ``` ### Check File Existence ```go func fileExists(service *minio.Service, bucket, objectName string) bool { exists, err := service.Exists(context.Background(), bucket, objectName) if err != nil { log.Printf("Error checking file existence: %v", err) return false } return exists } ``` ## Bucket Management ### Create Required Buckets ```go func ensureBucketsExist(connManager *minio.ConnectionManager) error { ctx := context.Background() // Create default bucket if err := connManager.CreateBucket(ctx, "files"); err != nil { return fmt.Errorf("failed to create files bucket: %w", err) } // Create hierarchical bucket if err := connManager.CreateBucket(ctx, "documents"); err != nil { return fmt.Errorf("failed to create documents bucket: %w", err) } return nil } ``` ### List All Buckets ```go func listAllBuckets(connManager *minio.ConnectionManager) error { buckets, err := connManager.ListBuckets(context.Background()) if err != nil { return err } log.Printf("Available buckets:") for _, bucket := range buckets { log.Printf("- %s", bucket) } return nil } ``` ## Error Handling ```go func handleUploadError(err error) { switch { case errors.Is(err, minio.ErrInvalidConfig): log.Println("Configuration error:", err) case errors.Is(err, minio.ErrNotConnected): log.Println("Connection error:", err) case errors.Is(err, minio.ErrUploadFailed): log.Println("Upload failed:", err) case errors.Is(err, minio.ErrFileTooLarge): log.Println("File too large:", err) case errors.Is(err, minio.ErrInvalidFileType): log.Println("Invalid file type:", err) default: log.Println("Unknown error:", err) } } ``` ## Integration with HTTP Handlers ### File Upload Handler ```go func uploadHandler(service *minio.Service) gin.HandlerFunc { return func(c *gin.Context) { // Get uploaded file file, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided"}) return } // Open uploaded file src, err := file.Open() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open file"}) return } defer src.Close() // Generate unique filename filename := fmt.Sprintf("%d_%s", time.Now().Unix(), file.Filename) objectName := fmt.Sprintf("uploads/%s", filename) // Upload file err = service.Upload(c.Request.Context(), "files", objectName, src, minio.UploadOptions{ ContentType: file.Header.Get("Content-Type"), Metadata: map[string]string{ "original_name": file.Filename, "uploaded_by": "user_id", // Get from context }, }) if err != nil { handleUploadError(err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Upload failed"}) return } c.JSON(http.StatusOK, gin.H{ "message": "File uploaded successfully", "filename": filename, "path": objectName, }) } } ``` ### Document Upload Handler ```go func uploadDocumentHandler(service *minio.Service) gin.HandlerFunc { return func(c *gin.Context) { // Get form data category := c.PostForm("category") subCategory := c.PostForm("subcategory") tags := c.PostFormArray("tags[]") // Get uploaded file file, err := c.FormFile("document") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No document provided"}) return } // Open document src, err := file.Open() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open document"}) return } defer src.Close() // Upload to hierarchical storage docPath, err := service.UploadDocument(c.Request.Context(), src, file.Filename, minio.HierarchicalUploadOptions{ UploadOptions: minio.UploadOptions{ ContentType: file.Header.Get("Content-Type"), Metadata: map[string]string{ "uploaded_by": "user_id", // Get from context "department": c.PostForm("department"), }, }, Category: category, SubCategory: subCategory, Tags: tags, }) if err != nil { handleUploadError(err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Document upload failed"}) return } c.JSON(http.StatusOK, gin.H{ "message": "Document uploaded successfully", "path": docPath, }) } } ``` ## Configuration Examples ### Development Configuration ```go config := minio.Config{ Endpoint: "localhost:9000", AccessKeyID: "minioadmin", SecretAccessKey: "minioadmin", UseSSL: false, Region: "us-east-1", DefaultBucket: "files", HierarchicalBucket: "documents", MaxFileSize: 50 * 1024 * 1024, // 50MB AllowedTypes: []string{"image/", "application/pdf", "text/"}, } ``` ### Production Configuration ```go config := minio.Config{ Endpoint: "minio.example.com:443", AccessKeyID: os.Getenv("MINIO_ACCESS_KEY"), SecretAccessKey: os.Getenv("MINIO_SECRET_KEY"), UseSSL: true, Region: "us-west-2", DefaultBucket: "production-files", HierarchicalBucket: "production-documents", MaxFileSize: 100 * 1024 * 1024, // 100MB AllowedTypes: []string{"image/jpeg", "image/png", "application/pdf"}, ConnectTimeout: 30 * time.Second, RequestTimeout: 60 * time.Second, } ```