first commit
This commit is contained in:
138
backend/internal/service/transfer_service.go
Normal file
138
backend/internal/service/transfer_service.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"filefast/backend/internal/model"
|
||||
"filefast/backend/internal/store"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type TransferService struct {
|
||||
store *store.MemoryStore
|
||||
}
|
||||
|
||||
type CreateTransferInput struct {
|
||||
SessionID string `json:"session_id"`
|
||||
Kind string `json:"kind" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
SizeBytes int64 `json:"size_bytes"`
|
||||
SenderDeviceID string `json:"sender_device_id" binding:"required"`
|
||||
ReceiverDeviceID string `json:"receiver_device_id" binding:"required"`
|
||||
}
|
||||
|
||||
type UpdateTransferStatusInput struct {
|
||||
CurrentChannel string `json:"current_channel"`
|
||||
FinalStatus string `json:"final_status"`
|
||||
FallbackReason string `json:"fallback_reason"`
|
||||
}
|
||||
|
||||
func NewTransferService(store *store.MemoryStore) *TransferService {
|
||||
return &TransferService{store: store}
|
||||
}
|
||||
|
||||
func (s *TransferService) Create(input CreateTransferInput) (model.Transfer, error) {
|
||||
switch input.Kind {
|
||||
case "file":
|
||||
if input.Name == "" {
|
||||
return model.Transfer{}, errors.New("file name is required")
|
||||
}
|
||||
if input.SizeBytes <= 0 {
|
||||
return model.Transfer{}, errors.New("file size must be greater than zero")
|
||||
}
|
||||
case "text":
|
||||
if input.Content == "" {
|
||||
return model.Transfer{}, errors.New("text content is required")
|
||||
}
|
||||
if input.Name == "" {
|
||||
input.Name = "text-message"
|
||||
}
|
||||
default:
|
||||
return model.Transfer{}, errors.New("unsupported transfer kind")
|
||||
}
|
||||
|
||||
runtime := s.store.RuntimeConfig()
|
||||
now := time.Now()
|
||||
fallbackAllowed := input.Kind == "file" && runtime.MinIOFallbackEnabled
|
||||
strategy := "p2p_turn"
|
||||
if fallbackAllowed {
|
||||
strategy = "p2p_turn_minio"
|
||||
}
|
||||
|
||||
transfer := model.Transfer{
|
||||
ID: uuid.NewString(),
|
||||
SessionID: input.SessionID,
|
||||
Kind: input.Kind,
|
||||
Name: input.Name,
|
||||
Content: input.Content,
|
||||
SizeBytes: input.SizeBytes,
|
||||
SenderDeviceID: input.SenderDeviceID,
|
||||
ReceiverDeviceID: input.ReceiverDeviceID,
|
||||
TransferStrategy: strategy,
|
||||
CurrentChannel: model.ChannelP2P,
|
||||
FallbackAllowed: fallbackAllowed,
|
||||
FinalStatus: model.TransferPending,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
return s.store.UpsertTransfer(transfer), nil
|
||||
}
|
||||
|
||||
func (s *TransferService) UpdateStatus(transferID string, input UpdateTransferStatusInput) (model.Transfer, error) {
|
||||
transfer, ok := s.store.GetTransfer(transferID)
|
||||
if !ok {
|
||||
return model.Transfer{}, errors.New("transfer not found")
|
||||
}
|
||||
|
||||
if input.CurrentChannel != "" {
|
||||
transfer.CurrentChannel = input.CurrentChannel
|
||||
}
|
||||
if input.FinalStatus != "" {
|
||||
transfer.FinalStatus = input.FinalStatus
|
||||
}
|
||||
if input.FallbackReason != "" {
|
||||
transfer.FallbackReason = input.FallbackReason
|
||||
}
|
||||
|
||||
transfer.UpdatedAt = time.Now()
|
||||
return s.store.UpsertTransfer(transfer), nil
|
||||
}
|
||||
|
||||
func (s *TransferService) PrepareFallback(transferID string) (model.Transfer, model.FallbackObject, error) {
|
||||
transfer, ok := s.store.GetTransfer(transferID)
|
||||
if !ok {
|
||||
return model.Transfer{}, model.FallbackObject{}, errors.New("transfer not found")
|
||||
}
|
||||
if !transfer.FallbackAllowed {
|
||||
return model.Transfer{}, model.FallbackObject{}, errors.New("transfer cannot use minio fallback")
|
||||
}
|
||||
if object, ok := s.store.GetFallbackObject(transfer.ID); ok && object.CleanedAt == nil && object.ExpiresAt.After(time.Now()) {
|
||||
return transfer, object, nil
|
||||
}
|
||||
|
||||
runtime := s.store.RuntimeConfig()
|
||||
now := time.Now()
|
||||
expireAt := now.Add(time.Duration(runtime.MinIORetentionHours) * time.Hour)
|
||||
objectKey := fmt.Sprintf("fallback/%s/%d-%s", now.Format("20060102"), now.Unix(), transfer.ID)
|
||||
|
||||
transfer.ObjectKey = objectKey
|
||||
transfer.ExpiresAt = &expireAt
|
||||
transfer.UpdatedAt = now
|
||||
transfer = s.store.UpsertTransfer(transfer)
|
||||
|
||||
object := model.FallbackObject{
|
||||
TransferID: transfer.ID,
|
||||
ObjectKey: objectKey,
|
||||
SizeBytes: transfer.SizeBytes,
|
||||
CreatedAt: now,
|
||||
ExpiresAt: expireAt,
|
||||
CleanupState: "uploading",
|
||||
}
|
||||
object = s.store.SaveFallbackObject(object)
|
||||
return transfer, object, nil
|
||||
}
|
||||
Reference in New Issue
Block a user