2026-03-29 11:55:53 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"io"
|
|
|
|
|
|
|
|
|
|
"github.com/cloudprint/cloudprint-backend/internal/service"
|
|
|
|
|
pb "github.com/cloudprint/cloudprint-backend/proto/generated"
|
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type FileServiceServer struct {
|
|
|
|
|
pb.UnimplementedFileServiceServer
|
|
|
|
|
fileService *service.FileService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewFileServiceServer(fileService *service.FileService) *FileServiceServer {
|
|
|
|
|
return &FileServiceServer{
|
|
|
|
|
fileService: fileService,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 20:26:52 +08:00
|
|
|
func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) error {
|
2026-03-29 11:55:53 +08:00
|
|
|
var fileName, fileType, uploaderType string
|
|
|
|
|
var uploaderID int32
|
|
|
|
|
var chunks [][]byte
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
req, err := stream.Recv()
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2026-04-28 20:26:52 +08:00
|
|
|
return status.Errorf(codes.Internal, "receive chunk failed: %v", err)
|
2026-03-29 11:55:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fileName == "" {
|
|
|
|
|
fileName = req.FileName
|
|
|
|
|
fileType = req.FileType
|
|
|
|
|
uploaderType = "user" // Extract from context in production
|
|
|
|
|
uploaderID = 1 // Extract from context in production
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunks = append(chunks, req.Data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Concatenate chunks
|
|
|
|
|
var data []byte
|
|
|
|
|
for _, chunk := range chunks {
|
|
|
|
|
data = append(data, chunk...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file, err := s.fileService.Upload(stream.Context(), fileName, fileType, uploaderType, uploaderID, data)
|
|
|
|
|
if err != nil {
|
2026-04-28 20:26:52 +08:00
|
|
|
return status.Errorf(codes.Internal, "upload failed: %v", err)
|
2026-03-29 11:55:53 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 20:26:52 +08:00
|
|
|
return stream.SendAndClose(&pb.UploadResponse{
|
2026-03-29 11:55:53 +08:00
|
|
|
FileId: file.ID,
|
|
|
|
|
FilePath: file.FilePath,
|
|
|
|
|
FileUrl: file.FilePath,
|
2026-04-28 20:26:52 +08:00
|
|
|
})
|
2026-03-29 11:55:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *FileServiceServer) GetFile(req *pb.GetFileRequest, stream pb.FileService_GetFileServer) error {
|
|
|
|
|
file, err := s.fileService.GetFile(stream.Context(), req.FileId)
|
|
|
|
|
if err != nil || file == nil {
|
|
|
|
|
return status.Errorf(codes.NotFound, "file not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reader, err := s.fileService.GetFileReader(stream.Context(), file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return status.Errorf(codes.Internal, "read file failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
defer reader.Close()
|
|
|
|
|
|
|
|
|
|
buf := make([]byte, 4096)
|
|
|
|
|
for {
|
|
|
|
|
n, err := reader.Read(buf)
|
|
|
|
|
if n > 0 {
|
|
|
|
|
if err := stream.Send(&pb.FileData{Data: buf[:n], IsLast: false}); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream.Send(&pb.FileData{IsLast: true})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *FileServiceServer) DeleteFile(ctx context.Context, req *pb.DeleteFileRequest) (*pb.Empty, error) {
|
|
|
|
|
err := s.fileService.DeleteFile(ctx, req.FileId, "user", 1)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, status.Errorf(codes.Internal, "delete file failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &pb.Empty{}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *FileServiceServer) AddWatermark(ctx context.Context, req *pb.WatermarkRequest) (*pb.WatermarkResponse, error) {
|
|
|
|
|
file, err := s.fileService.AddWatermark(ctx, req.FileId, req.Text, req.Opacity, int(req.Position), int(req.FontSize))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, status.Errorf(codes.Internal, "add watermark failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &pb.WatermarkResponse{
|
|
|
|
|
FileId: file.ID,
|
|
|
|
|
FilePath: file.FilePath,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *FileServiceServer) GetFileList(ctx context.Context, req *pb.GetFileListRequest) (*pb.FileListResponse, error) {
|
|
|
|
|
files, total, err := s.fileService.GetFileList(ctx, req.UploaderType, req.UploaderId, int(req.Page), int(req.PageSize))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, status.Errorf(codes.Internal, "get file list failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pbFiles := make([]*pb.FileInfo, 0, len(files))
|
|
|
|
|
for _, f := range files {
|
|
|
|
|
pbFiles = append(pbFiles, &pb.FileInfo{
|
|
|
|
|
Id: f.ID,
|
|
|
|
|
FileName: f.FileName,
|
|
|
|
|
FilePath: f.FilePath,
|
|
|
|
|
FileType: f.FileType,
|
|
|
|
|
FileSize: f.FileSize,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &pb.FileListResponse{
|
|
|
|
|
Files: pbFiles,
|
|
|
|
|
Total: int32(total),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|