Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File scoped functions (#2) #2

Merged
merged 3 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 69 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,75 @@ Here’s how you can get involved:
```
make test
```
4. To start application run:
```
make start
```

## Usage
```go
import(
"github.com/gin-gonic/gin"
"github.com/Nicolas-ggd/filestream"
)

func Upload(c *gin.Context) {
// Retrieve the uploaded file
uploadFile, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to get file"})
return
}

// Open the uploaded file
file, err := uploadFile.Open()
if err != nil {
fmt.Println("Error opening uploaded file:", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to open uploaded file"})
return
}

defer file.Close()


// Construct the FileRequest
fileReq := fstream.RFileRequest{
File: file,
UploadFile: uploadFile,
MaxRange: rangeMax,
FileSize: fileSize,
UploadDirectory: "uploads/",
FileUniqueName: true, // remember that if you set true here, you will receive unique name file
}


// Call StoreChunk to handle the uploaded chunk
prFile, err := fstream.StoreChunk(&fileReq)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to store chunk"})
return
}

// You can write your own if statement to check whatever you want
if isLast {
// You can perform your own logic here, before return 200 status,
// it's better to remove chunks which is uploaded and doesn't use anymore
fstream.RemoveUploadedFile(&fileReq)
}

c.JSON(http.StatusOK, gin.H{"message": "file chunk processed"})
}
```

`fstream` offers extension check, all you need is that to provide which extension do you want to allow

```go
import(
"github.com/Nicolas-ggd/filestream"
)

// Declare extension slice, slice contains all file extension which is ok for you to allow in your system
var allowExtensions = []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"}

// This function is very simple, but save your time to compare extension and current file to known if it's valid for you
fstream.IsAllowExtension(allowExtensions, "filename.png")
```

## License
FileStream is open-source software licensed under the MIT License.
Expand Down
49 changes: 0 additions & 49 deletions cmd/app/app.go

This file was deleted.

15 changes: 0 additions & 15 deletions cmd/app/config.go

This file was deleted.

7 changes: 0 additions & 7 deletions cmd/filestream/main.go

This file was deleted.

43 changes: 26 additions & 17 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type File struct {
// Original uploaded file name
FileName string
// FileUniqueName is unique name
FileUniqueName string
FileUniqueName *string
// Uploaded file path
FilePath string
// Uploaded file extension
Expand All @@ -43,21 +43,25 @@ type RFileRequest struct {
FileUniqueName bool
}

// generateUuidUniqueName function generates unique string using UUID
func (r *File) generateUuidUniqueName(request *RFileRequest) {
// uniqueName function generates unique string using UUID
func uniqueName(request *RFileRequest) string {
ext := filepath.Ext(request.UploadFile.Filename)

id, err := uuid.NewUUID()
if err != nil {
log.Fatalln(err)
}

r.FileUniqueName = fmt.Sprintf("%s%s", id.String(), ext)
return fmt.Sprintf("%s%s", id.String(), ext)
}

// RemoveUploadedFile function removes uploaded file from uploaded directory, it takes param and returns nothing:
//
// RFileRequest struct
// Takes:
//
// - RFileRequest struct
//
// Use this function in your handler after file is uploaded
func RemoveUploadedFile(r *RFileRequest) {
filePath := filepath.Join(r.UploadDirectory, r.UploadFile.Filename)

Expand All @@ -83,11 +87,11 @@ func prettyByteSize(b int) string {

// StoreChunk cares slice of chunks and returns final results and error
//
// File - struct is final version about file information
// - File - struct is final version about file information
//
// error - functions cares about errors and returns error
// - error - functions cares about occurred errors and returns it.
//
// function creates new directory for chunks if it doesn't exist, if directory already exists it appends received chunks in current chunks and if entire file is uploaded then File struct is returned
// Function creates new directory for chunks if it doesn't exist, if directory already exists it appends received chunks in current chunks and if entire file is uploaded then File struct is returned
func StoreChunk(r *RFileRequest) (*File, error) {
var rFile *File

Expand All @@ -114,7 +118,7 @@ func StoreChunk(r *RFileRequest) (*File, error) {
}()

// Copy the chunk data to the file
if _, err := io.Copy(f, r.File); err != nil {
if _, err = io.Copy(f, r.File); err != nil {
return nil, fmt.Errorf("failed to copying file: %v", err)
}

Expand All @@ -128,13 +132,18 @@ func StoreChunk(r *RFileRequest) (*File, error) {
// Calculate file size in bytes
size := prettyByteSize(int(fileInfo.Size()))

// Check if FileUniqueName field is true to generate unique name for file
if r.FileUniqueName {
uName := uniqueName(r)
rFile.FileUniqueName = &uName
}

// Bind File struct and return
rFile = &File{
FileName: r.UploadFile.Filename,
FileUniqueName: r.UploadFile.Filename,
FilePath: filePath,
FileExtension: filepath.Ext(r.UploadFile.Filename),
FileSize: size,
FileName: r.UploadFile.Filename,
FilePath: filePath,
FileExtension: filepath.Ext(r.UploadFile.Filename),
FileSize: size,
}
}

Expand All @@ -143,13 +152,13 @@ func StoreChunk(r *RFileRequest) (*File, error) {

// IsAllowExtension function checks if file extension is allowed to upload, it takes following params
//
// fileExtensions - array of strings, which is looks like: []string{".jpg", ".jpeg"}, note that this is fileExtensions which is allowed to receive
// - fileExtensions - array of strings, which is looks like: []string{".jpg", ".jpeg"}, note that this is fileExtensions which is allowed to receive
//
// fileName - string, this parameter is file name which is like ".jpeg", ".jpg"
// - fileName - string, this parameter is file name which is like ".jpeg", ".jpg"
//
// Returns:
//
// bool - function returns false if extension isn't allowed to receive, it returns true if extension is allowed to receive
// - bool - function returns false if extension isn't allowed to receive, it returns true if extension is allowed to receive
func IsAllowExtension(fileExtensions []string, fileName string) bool {
ext := strings.ToLower(filepath.Ext(fileName))

Expand Down
8 changes: 8 additions & 0 deletions file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fstream

import "testing"

func FuzzStoreChunk(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
})
}
Binary file removed filestream
Binary file not shown.
Loading