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, } } func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) (*pb.UploadResponse, error) { var fileName, fileType, uploaderType string var uploaderID int32 var totalSize int64 var chunks [][]byte for { req, err := stream.Recv() if err == io.EOF { break } if err != nil { return nil, status.Errorf(codes.Internal, "receive chunk failed: %v", err) } if fileName == "" { fileName = req.FileName fileType = req.FileType uploaderType = "user" // Extract from context in production uploaderID = 1 // Extract from context in production totalSize = req.FileSize } 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 { return nil, status.Errorf(codes.Internal, "upload failed: %v", err) } return &pb.UploadResponse{ FileId: file.ID, FilePath: file.FilePath, FileUrl: file.FilePath, }, nil } 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 }