| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- package model
- import (
- "crypto/sha256"
- "encoding/hex"
- "fmt"
- "io"
- "mime"
- "os"
- "path/filepath"
- "time"
- )
- // File represents a file to be shared or received
- type File struct {
- ID string
- Name string
- Path string
- Size int64
- Type string
- SHA256 string
- LastModified int64
- }
- // NewFile creates a File instance from a file path
- func NewFile(path string) (*File, error) {
- info, err := os.Stat(path)
- if err != nil {
- return nil, err
- }
- fileType := determineFileType(path)
- file := &File{
- ID: generateID(path),
- Name: filepath.Base(path),
- Path: path,
- Size: info.Size(),
- Type: fileType,
- LastModified: info.ModTime().UnixMilli(),
- }
- // Calculate SHA-256 hash asynchronously for large files
- if file.Size < 50*1024*1024 { // Only pre-calculate for files < 50MB
- hash, err := calculateSHA256(path)
- if err == nil {
- file.SHA256 = hash
- }
- }
- return file, nil
- }
- // ToFileDto converts a File to a FileDto for API responses
- func (f *File) ToFileDto() FileDto {
- var sha256Ptr *string
- if f.SHA256 != "" {
- sha256Ptr = &f.SHA256 // Assign address if SHA256 is calculated
- }
- modTime := time.Unix(0, f.LastModified).Format(time.RFC3339)
- return FileDto{
- ID: f.ID,
- FileName: f.Name,
- Size: f.Size,
- FileType: f.Type,
- SHA256: sha256Ptr,
- Metadata: &FileMetadata{
- Modified: &modTime,
- },
- }
- }
- // generateID creates a unique ID for a file based on path and timestamp
- func generateID(path string) string {
- timestamp := time.Now().UnixNano()
- data := []byte(fmt.Sprintf("%s-%d", path, timestamp))
- hash := sha256.Sum256(data)
- return hex.EncodeToString(hash[:8]) // Use first 8 bytes for a shorter ID
- }
- // determineFileType attempts to determine the file type from extension or content
- func determineFileType(path string) string {
- ext := filepath.Ext(path)
- if mimeType := mime.TypeByExtension(ext); mimeType != "" {
- return mimeType
- }
- // Fallbacks if mime package doesn't know the extension
- switch ext {
- case ".md":
- return "text/markdown"
- case ".apk":
- return "application/vnd.android.package-archive"
- default:
- return "application/octet-stream"
- }
- }
- // calculateSHA256 calculates the SHA-256 hash of a file
- func calculateSHA256(path string) (string, error) {
- f, err := os.Open(path)
- if err != nil {
- return "", err
- }
- defer f.Close()
- h := sha256.New()
- if _, err := io.Copy(h, f); err != nil {
- return "", err
- }
- return hex.EncodeToString(h.Sum(nil)), nil
- }
|