-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
156 lines (126 loc) · 3.52 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"strconv"
"sync"
"github.com/rs/cors"
)
func UploadHandler(w http.ResponseWriter, r *http.Request) {
// Parse the multipart form
err := r.ParseMultipartForm(10 << 20) // limit your max memory size
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Get the file data, and thread count from the request
file, fileHeader, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
threadCountStr := r.FormValue("threads")
threadCount, err := strconv.Atoi(threadCountStr)
if err != nil || threadCount <= 0 {
http.Error(w, "Invalid thread count", http.StatusBadRequest)
return
}
fileID := r.FormValue("fileID")
if fileID == "" {
http.Error(w, "FileId is missing", http.StatusBadRequest)
return
}
// Get the file size to determine chunk size
fileSize := r.ContentLength
chunkSize := fileSize / int64(threadCount)
var wg sync.WaitGroup
for i := 0; i < threadCount; i++ {
wg.Add(1)
go func(threadNum int) {
defer wg.Done()
// Determine the byte range for this chunk
startByte := int64(threadNum) * chunkSize
endByte := startByte + chunkSize - 1
if threadNum == threadCount-1 {
endByte = fileSize // ensure the last chunk goes to the end of the file
}
// Create a unique filename for this chunk
chunkFilename := fmt.Sprintf("%s-chunk%d", fileID, threadNum)
// Create a new file to store the chunk
dst, err := os.Create(chunkFilename)
if err != nil {
log.Println(err) // Log the error and continue
return
}
defer dst.Close()
// Seek to the start byte and read the chunk data from the file
sectionReader := io.NewSectionReader(file, startByte, endByte-startByte+1)
buf := make([]byte, endByte-startByte+1)
_, err = sectionReader.Read(buf)
if err != nil && err != io.EOF {
log.Println(err)
return
}
// Write the chunk data to the file
_, err = dst.Write(buf)
if err != nil {
log.Println(err)
return
}
}(i)
}
wg.Wait() // Wait for all goroutines to finish
StitchFile(fileID, threadCount, fileHeader.Filename)
fmt.Fprintf(w, "File %s uploaded and processed successfully with %d threads", fileID, threadCount)
}
func StitchFile(fileID string, threadCount int, fileName string) error {
// Create a new file to hold the stitched-together contents
outputFile, err := os.Create(fileName)
if err != nil {
return err
}
defer outputFile.Close()
// Iterate through each chunk
for i := 0; i < threadCount; i++ {
// Open the chunk file
chunkFilename := fmt.Sprintf("%s-chunk%d", fileID, i)
chunkFile, err := os.Open(chunkFilename)
if err != nil {
return err
}
// Read the chunk data
buf := make([]byte, 1024) // Adjust buffer size as needed
for {
n, err := chunkFile.Read(buf)
if err != nil {
break // Stop at EOF
}
// Write the chunk data to the output file
outputFile.Write(buf[:n])
}
if err := chunkFile.Close(); err != nil {
log.Println(err)
return err
}
}
return nil
}
func main() {
// Create a new router
router := http.NewServeMux()
// Register the chunk upload handler
router.HandleFunc("/upload", UploadHandler)
// Set up CORS middleware
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"}, // Allow all origins
AllowedMethods: []string{"POST"},
})
log.Println("Server is starting on Port 8080.....")
// Start the server with CORS middleware
handler := c.Handler(router)
http.ListenAndServe(":8080", handler)
}