Skip to content

Commit fbad2aa

Browse files
committed
refactor, format
Signed-off-by: Abhishek Kumar <[email protected]>
1 parent d6c4fcc commit fbad2aa

File tree

2 files changed

+191
-115
lines changed

2 files changed

+191
-115
lines changed

cmd/api.go

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,8 @@
1818
package cmd
1919

2020
import (
21-
"bytes"
2221
"errors"
2322
"fmt"
24-
"io"
25-
"mime/multipart"
26-
"net/http"
27-
"os"
28-
"path/filepath"
29-
"reflect"
3023
"strings"
3124
)
3225

@@ -118,116 +111,9 @@ func init() {
118111

119112
if len(response) > 0 {
120113
printResult(r.Config.Core.Output, response, filterKeys, excludeKeys)
121-
if r.Config.HasShell {
122-
apiName := strings.ToLower(api.Name)
123-
if apiName == "getuploadparamsforiso" ||
124-
apiName == "getuploadparamsforvolume" ||
125-
apiName == "getuploadparamsfotemplate" {
126-
promptForFileUpload(r, apiName, response)
127-
}
128-
}
114+
PromptAndUploadFileIfNeeded(r, api.Name, response)
129115
}
130116
return nil
131117
},
132118
}
133119
}
134-
135-
func promptForFileUpload(r *Request, api string, response map[string]interface{}) {
136-
fmt.Print("Enter path of the file(s) to upload (comma-separated): ")
137-
var filePaths string
138-
fmt.Scanln(&filePaths)
139-
filePathsList := strings.FieldsFunc(filePaths, func(r rune) bool { return r == ',' })
140-
141-
var missingFiles []string
142-
var validFiles []string
143-
for _, filePath := range filePathsList {
144-
filePath = strings.TrimSpace(filePath)
145-
if filePath == "" {
146-
continue
147-
}
148-
if _, err := os.Stat(filePath); os.IsNotExist(err) {
149-
missingFiles = append(missingFiles, filePath)
150-
} else {
151-
validFiles = append(validFiles, filePath)
152-
}
153-
}
154-
if len(missingFiles) > 0 {
155-
fmt.Println("File(s) do not exist or are not accessible:", strings.Join(missingFiles, ", "))
156-
return
157-
}
158-
if len(validFiles) == 0 {
159-
fmt.Println("No valid files to upload.")
160-
return
161-
}
162-
paramsRaw, ok := response["getuploadparams"]
163-
if !ok || reflect.TypeOf(paramsRaw).Kind() != reflect.Map {
164-
fmt.Println("Invalid response format for getuploadparams.")
165-
return
166-
}
167-
params := paramsRaw.(map[string]interface{})
168-
requiredKeys := []string{"postURL", "metadata", "signature", "expires"}
169-
for _, key := range requiredKeys {
170-
if _, ok := params[key]; !ok {
171-
fmt.Printf("Missing required key '%s' in getuploadparams response.\n", key)
172-
return
173-
}
174-
}
175-
176-
postURL, _ := params["postURL"].(string)
177-
signature, _ := params["signature"].(string)
178-
expires, _ := params["expires"].(string)
179-
metadata, _ := params["metadata"].(string)
180-
181-
fmt.Println("Uploading files for", api, ":", validFiles)
182-
spinner := r.Config.StartSpinner("uploading files, please wait...")
183-
defer r.Config.StopSpinner(spinner)
184-
185-
for _, filePath := range validFiles {
186-
if err := uploadFile(postURL, filePath, signature, expires, metadata); err != nil {
187-
fmt.Println("Error uploading", filePath, ":", err)
188-
}
189-
}
190-
}
191-
192-
// uploadFile uploads a single file to the given postURL with the required headers.
193-
func uploadFile(postURL, filePath, signature, expires, metadata string) error {
194-
file, err := os.Open(filePath)
195-
if err != nil {
196-
return err
197-
}
198-
defer file.Close()
199-
200-
var body bytes.Buffer
201-
writer := multipart.NewWriter(&body)
202-
part, err := writer.CreateFormFile("file", filepath.Base(filePath))
203-
if err != nil {
204-
return err
205-
}
206-
if _, err := io.Copy(part, file); err != nil {
207-
return err
208-
}
209-
writer.Close()
210-
211-
req, err := http.NewRequest("POST", postURL, &body)
212-
if err != nil {
213-
return err
214-
}
215-
req.Header.Set("Content-Type", writer.FormDataContentType())
216-
req.Header.Set("x-signature", signature)
217-
req.Header.Set("x-expires", expires)
218-
req.Header.Set("x-metadata", metadata)
219-
220-
client := &http.Client{}
221-
resp, err := client.Do(req)
222-
if err != nil {
223-
return err
224-
}
225-
defer resp.Body.Close()
226-
227-
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
228-
respBody, _ := io.ReadAll(resp.Body)
229-
return fmt.Errorf("upload failed: %s", string(respBody))
230-
}
231-
fmt.Println("Upload successful for:", filePath)
232-
return nil
233-
}

cmd/fileupload.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmd
19+
20+
import (
21+
"bytes"
22+
"fmt"
23+
"io"
24+
"mime/multipart"
25+
"net/http"
26+
"os"
27+
"path/filepath"
28+
"reflect"
29+
"strings"
30+
31+
"github.com/briandowns/spinner"
32+
)
33+
34+
const (
35+
uploadingMessage = "Uploading files, please wait..."
36+
)
37+
38+
// PromptAndUploadFileIfNeeded prompts the user to provide file paths for upload and the API is getUploadParamsFor*
39+
func PromptAndUploadFileIfNeeded(r *Request, api string, response map[string]interface{}) {
40+
if !r.Config.HasShell {
41+
return
42+
}
43+
apiName := strings.ToLower(api)
44+
if apiName != "getuploadparamsforiso" &&
45+
apiName != "getuploadparamsforvolume" &&
46+
apiName != "getuploadparamsfotemplate" {
47+
return
48+
}
49+
fmt.Print("Enter path of the file(s) to upload (comma-separated): ")
50+
var filePaths string
51+
fmt.Scanln(&filePaths)
52+
filePathsList := strings.FieldsFunc(filePaths, func(r rune) bool { return r == ',' })
53+
54+
var missingFiles []string
55+
var validFiles []string
56+
for _, filePath := range filePathsList {
57+
filePath = strings.TrimSpace(filePath)
58+
if filePath == "" {
59+
continue
60+
}
61+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
62+
missingFiles = append(missingFiles, filePath)
63+
} else {
64+
validFiles = append(validFiles, filePath)
65+
}
66+
}
67+
if len(missingFiles) > 0 {
68+
fmt.Println("File(s) do not exist or are not accessible:", strings.Join(missingFiles, ", "))
69+
return
70+
}
71+
if len(validFiles) == 0 {
72+
fmt.Println("No valid files to upload.")
73+
return
74+
}
75+
paramsRaw, ok := response["getuploadparams"]
76+
if !ok || reflect.TypeOf(paramsRaw).Kind() != reflect.Map {
77+
fmt.Println("Invalid response format for getuploadparams.")
78+
return
79+
}
80+
params := paramsRaw.(map[string]interface{})
81+
requiredKeys := []string{"postURL", "metadata", "signature", "expires"}
82+
for _, key := range requiredKeys {
83+
if _, ok := params[key]; !ok {
84+
fmt.Printf("Missing required key '%s' in getuploadparams response.\n", key)
85+
return
86+
}
87+
}
88+
89+
postURL, _ := params["postURL"].(string)
90+
signature, _ := params["signature"].(string)
91+
expires, _ := params["expires"].(string)
92+
metadata, _ := params["metadata"].(string)
93+
94+
fmt.Println("Uploading files for", api, ":", validFiles)
95+
spinner := r.Config.StartSpinner(uploadingMessage)
96+
errored := 0
97+
for i, filePath := range validFiles {
98+
spinner.Suffix = fmt.Sprintf(" uploading %d/%d %s...", i+1, len(validFiles), filepath.Base(filePath))
99+
if err := uploadFile(postURL, filePath, signature, expires, metadata, spinner); err != nil {
100+
spinner.Stop()
101+
fmt.Println("Error uploading", filePath, ":", err)
102+
errored++
103+
spinner.Suffix = fmt.Sprintf(" %s", uploadingMessage)
104+
spinner.Start()
105+
}
106+
}
107+
r.Config.StopSpinner(spinner)
108+
if errored > 0 {
109+
fmt.Printf("🙈 %d out of %d files failed to upload.\n", errored, len(validFiles))
110+
} else {
111+
fmt.Println("All files uploaded successfully.")
112+
}
113+
}
114+
115+
type progressReader struct {
116+
file *os.File
117+
total int64
118+
read int64
119+
updateSuffix func(percent int)
120+
}
121+
122+
func (pr *progressReader) Read(p []byte) (int, error) {
123+
n, err := pr.file.Read(p)
124+
if n > 0 {
125+
pr.read += int64(n)
126+
percent := int(float64(pr.read) / float64(pr.total) * 100)
127+
pr.updateSuffix(percent)
128+
}
129+
return n, err
130+
}
131+
132+
// uploadFile uploads a single file to the given postURL with the required headers.
133+
func uploadFile(postURL, filePath, signature, expires, metadata string, spinner *spinner.Spinner) error {
134+
originalSuffix := spinner.Suffix
135+
file, err := os.Open(filePath)
136+
if err != nil {
137+
return err
138+
}
139+
defer file.Close()
140+
141+
fileInfo, err := file.Stat()
142+
if err != nil {
143+
return err
144+
}
145+
146+
var body bytes.Buffer
147+
writer := multipart.NewWriter(&body)
148+
part, err := writer.CreateFormFile("file", filepath.Base(filePath))
149+
if err != nil {
150+
return err
151+
}
152+
153+
pr := &progressReader{
154+
file: file,
155+
total: fileInfo.Size(),
156+
updateSuffix: func(percent int) {
157+
spinner.Suffix = fmt.Sprintf(" %s (%d%%)", originalSuffix, percent)
158+
},
159+
}
160+
if _, err := io.Copy(part, pr); err != nil {
161+
return err
162+
}
163+
writer.Close()
164+
165+
req, err := http.NewRequest("POST", postURL, &body)
166+
if err != nil {
167+
return err
168+
}
169+
req.Header.Set("Content-Type", writer.FormDataContentType())
170+
req.Header.Set("x-signature", signature)
171+
req.Header.Set("x-expires", expires)
172+
req.Header.Set("x-metadata", metadata)
173+
174+
client := &http.Client{}
175+
resp, err := client.Do(req)
176+
if err != nil {
177+
return err
178+
}
179+
defer resp.Body.Close()
180+
181+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
182+
respBody, _ := io.ReadAll(resp.Body)
183+
return fmt.Errorf("upload failed: %s", string(respBody))
184+
}
185+
spinner.Stop()
186+
fmt.Println("Upload successful for:", filePath)
187+
spinner.Suffix = fmt.Sprintf(" %s", uploadingMessage)
188+
spinner.Start()
189+
return nil
190+
}

0 commit comments

Comments
 (0)