This commit is contained in:
oneao committed 2026-04-24 17:28:11 +08:00
1 parent 07e0001b87
commit 46cbb2f50d
543 files changed
+32576 -4231

No files matched your search

@@ -6,18 +6,24 @@ import (
"allapp-go/internal/types"
"allapp-go/pkg/db"
"allapp-go/pkg/jwtx"
"allapp-go/pkg/requestx"
"allapp-go/pkg/s3store"
"allapp-go/pkg/uniqueid"
"allapp-go/pkg/wechat"
"fmt"
"net/url"
"path/filepath"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
"github.com/google/uuid"
)
// LoginQq ======================== QQ 登录 ========================
func LoginQq(c fiber.Ctx) error {
var req types.LoginQqDTO
vo := new(types.LoginVO)
var req types.LoginQqReq
vo := new(types.LoginResp)
if err := httpx.BindAndValidate(c, &req); err != nil {
return errors.WithStack(err)
@@ -28,8 +34,8 @@ func LoginQq(c fiber.Ctx) error {
// LoginWechat ======================== 微信登录 ========================
func LoginWechat(c fiber.Ctx) error {
var req types.LoginWechatDTO
vo := new(types.LoginVO)
var req types.LoginWechatReq
vo := new(types.LoginResp)
if err := httpx.BindAndValidate(c, &req); err != nil {
return errors.WithStack(err)
@@ -37,13 +43,13 @@ func LoginWechat(c fiber.Ctx) error {
openid, token, err := wechat.GetWechatAccess(req.Code)
if err != nil {
log.Errorw("wechat access failed", "code", req.Code, "error", err)
log.Errorw("微信获取Token失败", "code", req.Code, "error", err)
return httpx.Fail(c, "微信登录失败,请重试")
}
nickname, avatar, err := wechat.GetWechatUserInfo(token, openid)
if err != nil {
log.Errorw("wechat userinfo failed", "openid", openid, "error", err)
log.Errorw("微信获取用户信息系失败", "openid", openid, "error", err)
return httpx.Fail(c, "微信登录失败,请重试")
}
@@ -57,7 +63,7 @@ func handleThirdLogin(
nickname string,
avatar string,
loginType int16,
vo *types.LoginVO,
vo *types.LoginResp,
) error {
dbClient := db.New()
@@ -133,15 +139,58 @@ func registerUser(
c fiber.Ctx,
openid, nickname, avatar string,
loginType int16,
vo *types.LoginVO,
vo *types.LoginResp,
) error {
userId := uniqueid.NextId()
defaultAvatar := "https://default-avatar-url.com/default.png"
if nickname == "" {
nickname = fmt.Sprintf("用户_%d", userId)
}
if avatar == "" {
avatar = "https://default-avatar-url.com/default.png"
avatar = defaultAvatar
} else {
// 下载头像(流式)
stream, size, contentType, err := requestx.GetFileStream(c.Context(), avatar)
if err != nil {
avatar = defaultAvatar
} else {
defer func() {
_ = stream.Close()
}()
// ✅ 从 avatar URL 获取扩展名(简化版)
u, _ := url.Parse(avatar)
ext := filepath.Ext(u.Path)
if ext == "" {
ext = ".jpg" // 兜底
}
// 年月日 + uuid
now := time.Now()
key := fmt.Sprintf("%d/%02d/%02d/%s%s",
now.Year(),
now.Month(),
now.Day(),
uuid.NewString(),
ext,
)
// 上传到 S3
if err := s3store.UploadToRustFS(
c.Context(),
stream,
key,
size,
contentType,
); err != nil {
avatar = defaultAvatar
} else {
avatar = key
}
}
}
err := dbClient.WithTx(c.Context(), func(tx *db.Client) error {
+24 -18
View File
@@ -3,32 +3,18 @@ package handle
import (
"allapp-go/internal/errors"
"allapp-go/internal/httpx"
"allapp-go/internal/types"
"allapp-go/pkg/logger"
"allapp-go/pkg/s3store"
"fmt"
"path/filepath"
"time"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gofiber/fiber/v3"
"github.com/google/uuid"
"go.uber.org/zap"
)
func S3ListBuckets(c fiber.Ctx) error {
result, err := s3store.S3Client.ListBuckets(c.Context(), &s3.ListBucketsInput{})
if err != nil {
return errors.WithStack(err)
}
buckets := make([]string, 0, len(result.Buckets))
for _, b := range result.Buckets {
if b.Name != nil {
buckets = append(buckets, *b.Name)
}
}
return httpx.OK(c, buckets)
}
func S3UploadFile(c fiber.Ctx) error {
form, err := c.MultipartForm()
if err != nil {
@@ -64,8 +50,8 @@ func S3UploadFile(c fiber.Ctx) error {
err = s3store.UploadToRustFS(
c.Context(),
key,
file,
key,
fileHeader.Size,
contentType,
)
@@ -81,3 +67,23 @@ func S3UploadFile(c fiber.Ctx) error {
return httpx.OK(c, result)
}
func S3DeleteFile(c fiber.Ctx) error {
var req types.S3DeleteReq
if err := httpx.BindAndValidate(c, &req); err != nil {
return errors.WithStack(err)
}
log := logger.FromCtx(c.Context())
if err := s3store.DeleteBatch(c.Context(), req.Keys); err != nil {
log.Warn("S3 批量删除失败",
zap.Int("count", len(req.Keys)),
zap.Error(err),
)
// ❗仍然返回成功(符合你的要求)
}
return httpx.OK(c, nil)
}
@@ -20,8 +20,8 @@ func SetupRouter(app *fiber.App, cfg *config.Config) {
data.Post("/getUniqueId", handle.GetUniqueId)
s3 := api.Group("/s3", middleware.Auth())
s3.Post("/listBuckets", handle.S3ListBuckets)
s3.Post("/upload", handle.S3UploadFile)
s3.Post("/delete", handle.S3DeleteFile)
// ==================== auth ====================
api.Post("/auth/login/qq", handle.LoginQq)
@@ -1,16 +1,16 @@
package types
type LoginQqDTO struct {
type LoginQqReq struct {
Openid string `json:"openid" validate:"required"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
}
type LoginWechatDTO struct {
type LoginWechatReq struct {
Code string `json:"code" validate:"required"`
}
type LoginVO struct {
type LoginResp struct {
Token string `json:"token"`
UserId int64 `json:"userId"`
Nickname string `json:"nickname"`
@@ -0,0 +1,5 @@
package types
type S3DeleteReq struct {
Keys []string `json:"keys" validate:"required"`
}
@@ -2,6 +2,9 @@ package requestx
import (
"context"
"fmt"
"io"
"net/http"
"time"
"github.com/gofiber/fiber/v3/client"
@@ -97,3 +100,31 @@ func PostForm(url string, formData map[string]string, cfg client.Config) (string
}
return string(resp.Body()), resp.StatusCode(), nil
}
func GetFileStream(ctx context.Context, url string) (io.ReadCloser, int64, string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, 0, "", err
}
req.Header.Set("User-Agent", "Mozilla/5.0")
httpClient := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, 0, "", err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err := resp.Body.Close()
if err != nil {
return nil, 0, "", err
}
return nil, 0, "", fmt.Errorf("request failed: %d", resp.StatusCode)
}
return resp.Body, resp.ContentLength, resp.Header.Get("Content-Type"), nil
}
+45 -2
View File
@@ -4,11 +4,12 @@ import (
"allapp-go/internal/config"
"context"
"fmt"
"mime/multipart"
"io"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
)
var S3Client *s3.Client
@@ -39,7 +40,8 @@ func NewS3Client(cfg *config.Config) {
fmt.Println("S3 client and Presign client initialized successfully!")
}
func UploadToRustFS(ctx context.Context, key string, file multipart.File, size int64, contentType string) error {
// UploadToRustFS 上传
func UploadToRustFS(ctx context.Context, file io.Reader, key string, size int64, contentType string) error {
_, err := S3Client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
@@ -47,6 +49,47 @@ func UploadToRustFS(ctx context.Context, key string, file multipart.File, size i
ContentLength: aws.Int64(size),
ContentType: aws.String(contentType),
})
return err
}
// DeleteFromRustFS 删除
func DeleteFromRustFS(ctx context.Context, key string) error {
_, err := S3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
return err
}
func DeleteBatch(ctx context.Context, keys []string) error {
const maxBatch = 1000
for i := 0; i < len(keys); i += maxBatch {
end := i + maxBatch
if end > len(keys) {
end = len(keys)
}
var objects []types.ObjectIdentifier
for _, k := range keys[i:end] {
objects = append(objects, types.ObjectIdentifier{
Key: aws.String(k),
})
}
_, err := S3Client.DeleteObjects(ctx, &s3.DeleteObjectsInput{
Bucket: aws.String(bucket),
Delete: &types.Delete{
Objects: objects,
Quiet: aws.Bool(false), // 返回删除结果(建议保留)
},
})
if err != nil {
return err // 整批失败才返回
}
}
return nil
}