c85c66e43a
- replace UserSetColor/UserSetPronouns with single UserUpdateProfile that dynamically builds one UPDATE query from UserProfileUpdateList - add getConnectionWithResponseOnFail helper to deduplicate connection ID parsing and validation across handlers - rename file.go to attachmentFile.go and update handler names - GetDownloadUrlAndMetadata now fetches object metadata via StatObject and returns it alongside the presigned URL - file download endpoint returns JSON with url and originalName - add description field to user and DB schema - remove unused ConnectionState variants (GroupFellow, GroupFriend) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package minio
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"mime"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go-socket/packages/globals"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
)
|
|
|
|
var minClient *minio.Client
|
|
|
|
type DataType uint8
|
|
|
|
const (
|
|
File DataType = iota
|
|
UserAvatar
|
|
UserProfileBg
|
|
)
|
|
|
|
func GetKey(connectionId uuid.UUID, mimeType string, uploadType DataType) string {
|
|
extensions, err := mime.ExtensionsByType(mimeType)
|
|
if err != nil || len(extensions) == 0 {
|
|
extensions = []string{".unknown"}
|
|
}
|
|
|
|
key := connectionId.String() + "/" + strconv.FormatInt(time.Now().UnixMilli(), 10) + extensions[0]
|
|
|
|
if uploadType == UserAvatar {
|
|
return "userAvatar/" + key
|
|
} else if uploadType == UserProfileBg {
|
|
return "userProfileBg/" + key
|
|
}
|
|
return "upload/" + key
|
|
}
|
|
|
|
func Init(ctx context.Context) {
|
|
var err error
|
|
minClient, err = minio.New("localhost:9000", &minio.Options{
|
|
Creds: credentials.NewStaticV4("root", "change_to_env", ""),
|
|
Secure: false,
|
|
}) // TODO change for production
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
exists, err := minClient.BucketExists(ctx, globals.FileStorageBucketName)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if !exists {
|
|
err = minClient.MakeBucket(ctx, globals.FileStorageBucketName, minio.MakeBucketOptions{})
|
|
if err != nil {
|
|
exists, checkErr := minClient.BucketExists(ctx, globals.FileStorageBucketName)
|
|
if checkErr != nil || !exists {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func Upload(ctx context.Context, key string, body io.Reader, size int64, contentType string, metadata map[string]string) error {
|
|
opt := minio.PutObjectOptions{
|
|
ContentType: contentType,
|
|
PartSize: globals.FileProcessingPartSize,
|
|
NumThreads: globals.FileProcessingThreads,
|
|
UserMetadata: metadata,
|
|
}
|
|
opt.SetMatchETagExcept("*")
|
|
|
|
_, err := minClient.PutObject(ctx, globals.FileStorageBucketName, key, body, size, opt)
|
|
return err
|
|
}
|
|
|
|
func GetDownloadUrlAndMetadata(ctx context.Context, key string) (*url.URL, map[string]string, error) {
|
|
info, err := minClient.StatObject(ctx, globals.FileStorageBucketName, key, minio.StatObjectOptions{})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
u, err := minClient.PresignedGetObject(ctx, globals.FileStorageBucketName, key, globals.FileDownloadLinkTtl, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return u, info.UserMetadata, nil
|
|
}
|
|
|
|
func DoesExist(ctx context.Context, key string) bool {
|
|
_, err := minClient.StatObject(ctx, globals.FileStorageBucketName, key, minio.StatObjectOptions{})
|
|
return err == nil
|
|
}
|