Hub-Api/services/panel.go

273 lines
5.8 KiB
Go

package services
import (
"archive/zip"
"bytes"
"fmt"
"io"
"io/ioutil"
"netina/database"
"netina/models"
"os"
"path/filepath"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/labstack/echo/v4"
)
// ExtractZip extracts a zip file to a specified destination directory
func extractZip(zipPath string, destDir string) ([]string, error) {
r, err := zip.OpenReader(zipPath)
if err != nil {
return nil, err
}
defer r.Close()
var extractedFiles []string
for _, f := range r.File {
fPath := filepath.Join(destDir, f.Name)
if !strings.HasPrefix(fPath, filepath.Clean(destDir)+string(os.PathSeparator)) {
return nil, fmt.Errorf("illegal file path: %s", fPath)
}
extractedFiles = append(extractedFiles, fPath)
if f.FileInfo().IsDir() {
os.MkdirAll(fPath, os.ModePerm)
continue
}
if err := os.MkdirAll(filepath.Dir(fPath), os.ModePerm); err != nil {
return nil, err
}
dstFile, err := os.OpenFile(fPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return nil, err
}
defer dstFile.Close()
srcFile, err := f.Open()
if err != nil {
return nil, err
}
defer srcFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return nil, err
}
}
return extractedFiles, nil
}
func UpdatePanel(c echo.Context) error{
db := database.Db()
var stores []models.Store
if err := db.Where("is_removed = ?" , false).Find(&stores).Error;err != nil {
return err
}
var sess []session.Session
for _ , store := range stores {
ses , err := session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials(store.StorageApiKey , store.StorageSecret , ""),
Region: aws.String("ir-thr-at1"),
Endpoint: aws.String(store.StorageAddress),
})
if err != nil {
return err
}
sess = append(sess, *ses)
}
var svcs []s3.S3
for _ , i := range sess{
svc := s3.New(&i)
svcs = append(svcs, *svc)
}
for i:=0;i<len(svcs);i++ {
_ , err := svcs[i].HeadBucket(&s3.HeadBucketInput{
Bucket: aws.String(stores[i].StorageName),
})
if err != nil {
return err
}
}
// Track cleaned storages
cleanedStorages := make(map[string]bool)
for i := 0;i<len(svcs);i++ {
if !cleanedStorages[stores[i].StorageName] {
if err := deleteAllObjects(&svcs[i] , stores[i].StorageName); err != nil {
return err
}
cleanedStorages[stores[i].StorageName] = true
}
}
dir := "./uploads"
destDir := "extractedFiles"
// Find the ZIP file in the directory
files, err := os.ReadDir(dir)
if err != nil {
return err
}
var zipFilePath string
for _, file := range files {
if !file.IsDir() && strings.HasSuffix(file.Name(), ".zip") {
zipFilePath = filepath.Join(dir, file.Name())
break
}
}
if zipFilePath == "" {
fmt.Println("No ZIP file found in the directory")
return nil
}
// Extract the ZIP file
extractedFiles, err := extractZip(zipFilePath, destDir)
if err != nil {
return nil
}
// Upload extracted files to Arvan Cloud
for _, filePath := range extractedFiles {
key := filepath.Base(filePath)
for i := 0 ; i < len(stores) ; i++ {
err := uploadToArvanCloud(&sess[i] , stores[i].StorageName , filePath , key)
if err != nil {
return err
}
fmt.Printf("Successfully uploaded %s to Arvan Cloud , storage %s \n", filePath , stores[i].StorageAddress)
}
}
removeContents(dir)
removeContents("./extractedFiles")
return nil
}
func uploadToArvanCloud(sess *session.Session , bucket string , filePath string , key string)error{
file, err := ioutil.ReadFile(filePath)
if err != nil {
return err
}
uploder := s3manager.NewUploader(sess)
_,err = uploder.Upload(&s3manager.UploadInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: bytes.NewReader(file),
})
if err != nil {
return err
}
return nil
}
func removeContents(dir string) error {
// Read the directory contents
contents, err := ioutil.ReadDir(dir)
if err != nil {
return fmt.Errorf("failed to read directory: %w", err)
}
// Iterate through each item in the directory
for _, item := range contents {
// Construct the full path of the item
itemPath := filepath.Join(dir, item.Name())
// Remove the item (file or directory)
err = os.RemoveAll(itemPath)
if err != nil {
return fmt.Errorf("failed to remove %s: %w", itemPath, err)
}
}
return nil
}
func deleteAllObjects(svc *s3.S3, bucket string) error {
listObjectsInput := &s3.ListObjectsV2Input{
Bucket: aws.String(bucket),
}
for {
resp, err := svc.ListObjectsV2(listObjectsInput)
if err != nil {
return err
}
if len(resp.Contents) == 0 {
fmt.Println("No objects found in the bucket.")
break
}
var objectsToDelete []*s3.ObjectIdentifier
for _, item := range resp.Contents {
objectsToDelete = append(objectsToDelete, &s3.ObjectIdentifier{
Key: item.Key,
})
}
deleteObjectsInput := &s3.DeleteObjectsInput{
Bucket: aws.String(bucket),
Delete: &s3.Delete{
Objects: objectsToDelete,
Quiet: aws.Bool(true),
},
}
_, err = svc.DeleteObjects(deleteObjectsInput)
if err != nil {
return err
}
fmt.Printf("Deleted %d objects from bucket %s\n", len(objectsToDelete), bucket)
if !aws.BoolValue(resp.IsTruncated) {
break
}
listObjectsInput.ContinuationToken = resp.NextContinuationToken
}
fmt.Println("All objects deleted successfully.")
return nil
}