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{}) }