129 lines
2.8 KiB
Go
129 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
"github.com/schollz/progressbar/v3"
|
|
photosapi "gitlab.celogeek.com/photos/api/internal/photos/api"
|
|
)
|
|
|
|
type UploadCommand struct {
|
|
Url string `short:"u" long:"url" description:"Url of the instance" required:"true"`
|
|
Token string `short:"t" long:"token" description:"Token of the instance" required:"true"`
|
|
File string `short:"f" long:"file" description:"File to upload" required:"true"`
|
|
Workers uint32 `short:"w" long:"workers" description:"Number of workers for uploading chunks" default:"4"`
|
|
}
|
|
|
|
func (c *UploadCommand) Cli() *resty.Client {
|
|
return resty.New().SetBaseURL(c.Url).SetAuthScheme("Private").SetAuthToken(c.Token)
|
|
}
|
|
|
|
func (c *UploadCommand) Execute(args []string) error {
|
|
cli := c.Cli()
|
|
resp, err := cli.R().SetError(&photosapi.ErrorWithDetails{}).SetResult(&photosapi.Upload{}).Post("/upload")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resp.IsError() {
|
|
return resp.Error().(*photosapi.ErrorWithDetails)
|
|
}
|
|
uploadId := resp.Result().(*photosapi.Upload).Id
|
|
|
|
defer cli.R().SetPathParam("id", uploadId).Delete("/upload/{id}")
|
|
|
|
f, err := os.Open(c.File)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
st, err := f.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
progress := progressbar.DefaultBytes(st.Size(), fmt.Sprintf("Uploading %s", filepath.Base(c.File)))
|
|
defer progress.Close()
|
|
tee := io.TeeReader(f, progress)
|
|
|
|
b := make([]byte, photosapi.MaxUploadPartSize)
|
|
parts := 0
|
|
completesha256 := photosapi.NewChecksum()
|
|
for {
|
|
n, err := tee.Read(b)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
parts++
|
|
partsha256 := photosapi.NewChecksum()
|
|
partsha256.Write(b[:n])
|
|
completesha256.Write(b[:n])
|
|
|
|
resp, err := cli.
|
|
R().
|
|
SetError(&photosapi.ErrorWithDetails{}).
|
|
SetQueryParam("part", fmt.Sprint(parts)).
|
|
SetQueryParam("sha256", partsha256.String()).
|
|
SetBody(b[:n]).
|
|
SetPathParam("id", uploadId).
|
|
Put("/upload/{id}")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resp.IsError() {
|
|
return resp.Error().(*photosapi.ErrorWithDetails)
|
|
}
|
|
}
|
|
|
|
completeRequest := &photosapi.UploadCompleteRequest{
|
|
Sha256: completesha256.String(),
|
|
Parts: uint(parts),
|
|
Name: filepath.Base(c.File),
|
|
}
|
|
|
|
fmt.Printf(`Result:
|
|
- Upload ID: %s
|
|
- Name : %s
|
|
- Parts : %d
|
|
- SHA256 : %s
|
|
|
|
Committing...
|
|
`,
|
|
uploadId,
|
|
completeRequest.Name,
|
|
completeRequest.Parts,
|
|
completeRequest.Sha256,
|
|
)
|
|
|
|
resp, err = cli.
|
|
R().
|
|
SetError(&photosapi.ErrorWithDetails{}).
|
|
SetPathParam("id", uploadId).
|
|
SetBody(completeRequest).
|
|
Post("/upload/{id}")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resp.IsError() {
|
|
return resp.Error().(*photosapi.ErrorWithDetails)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
parser.AddCommand("upload", "Upload a file", "", &UploadCommand{})
|
|
}
|