package penadisk import ( "bytes" "encoding/json" "fmt" "github.com/minio/minio-go/v7" "io" "mime/multipart" "net/http" "net/url" "os" "strconv" "strings" ) const ( DEFAULT_FOLDER = "templategen" DEFAULT_TEMPLATE_FOLDER = DEFAULT_FOLDER + "/templates" DEFAULT_SAVE_FOLDER = DEFAULT_FOLDER + "/saved" ) var ( URL = "" V1_DISK_API = URL + "/api/v1/" ) func init() { URL = os.Getenv("PENADISK_URL") V1_DISK_API = URL + "api/v1/" } type Client struct { userID string } func NewClient(userID string) *Client { return &Client{userID: userID} } func (c *Client) GetDisk() (*BucketWithStats, error) { req, err := http.NewRequest("GET", V1_DISK_API+"bucket", nil) if err != nil { return nil, err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } if err = checkError(resp); err != nil { return nil, err } var r BucketWithStats err = json.NewDecoder(resp.Body).Decode(&r) return &r, err } func (c *Client) SetBucketQuota(size uint64) error { data := url.Values{} data.Set("size", strconv.FormatUint(size, 10)) req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/quota/set?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) UnsetBucketQuota() error { req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/quota/unset", nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) EnableBucketVersioning() error { req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/versioning/enable", nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) SuspendBucketVersioning() error { req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/versioning/suspend", nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } // GetResources - получить информацию о ресурсах func (c *Client) GetResources(path string, recursive, withVersion bool) ([]minio.ObjectInfo, error) { data := url.Values{} data.Set("path", path) if recursive { data.Set("recursive", "true") } if withVersion { data.Set("with_versions", "true") } req, err := http.NewRequest("GET", V1_DISK_API+"resources?"+data.Encode(), nil) if err != nil { return nil, err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } if err = checkError(resp); err != nil { return nil, err } var r []minio.ObjectInfo err = json.NewDecoder(resp.Body).Decode(&r) return r, err } // PutResources - создать папку func (c *Client) PutResources(path string) error { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("PUT", V1_DISK_API+"resources?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) UploadResources(path, filename string, overwrite bool, file io.Reader) (fullPath string, exportUrl string, err error) { buf := new(bytes.Buffer) bw := multipart.NewWriter(buf) defer bw.Close() if !strings.HasSuffix(path, "/") { path += "/" } fmt.Println("UploadResources",path, filename, overwrite) if err := bw.WriteField("path", path); err != nil { fmt.Println("UploadResources1", err) return "", "", err } if overwrite { if err := bw.WriteField("overwrite", "true"); err != nil { fmt.Println("UploadResources2", err) return "", "", err } } fw, err := bw.CreateFormFile("file", filename) if err != nil { fmt.Println("UploadResources3", err) return "", "", err } _, err = io.Copy(fw, file) if err != nil { fmt.Println("UploadResources4", err) return "", "", err } req, err := http.NewRequest("POST", V1_DISK_API+"resources/upload", buf) fmt.Println("UploadResources5",req, err, V1_DISK_API+"resources/upload") c.setHeaders(req) req.Header.Set("Content-Type", bw.FormDataContentType()) resp, err := http.DefaultClient.Do(req) fmt.Println("UploadResources6", resp, err) if err != nil { return "", "", err } if err = checkError(resp); err != nil { fmt.Println("UploadResources7", resp, err) return "", "", err } fullPath = path + filename exportUrl, err = c.GetPublicDownloadURL(fullPath) fmt.Println("UploadResources8", exportUrl, err) return fullPath, exportUrl, err } // GetPublicDownloadURL - получить публичную ссылку для скачивания файла. Ссылка живет 30 минут func (c *Client) GetPublicDownloadURL(path string) (href string, err error) { data := url.Values{} data.Set("path", path) // Получаем публичную ссылку на файл живущую 30 минут req, err := http.NewRequest("GET", V1_DISK_API+"resources/download?"+data.Encode(), nil) if err != nil { return "", err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } err = checkError(resp) if err != nil { return "", err } var r RespDownloadResources err = json.NewDecoder(resp.Body).Decode(&r) return r.Href, err } func (c *Client) DownloadResource(path, downloadPath string) error { href, err := c.GetPublicDownloadURL(path) if err != nil { return err } resp, err := http.Get(href) defer resp.Body.Close() if err != nil { return err } err = checkError(resp) if err != nil { return err } if err = checkError(resp); err != nil { return err } // Create the file out, err := os.Create(downloadPath) if err != nil { return err } defer out.Close() // Write the body to file _, err = io.Copy(out, resp.Body) return err } func (c *Client) DownloadResourceBytes(path string) ([]byte, error) { href, err := c.GetPublicDownloadURL(path) if err != nil { return nil, err } resp, err := http.Get(href) defer resp.Body.Close() if err != nil { return nil, err } err = checkError(resp) if err != nil { return nil, err } if err = checkError(resp); err != nil { return nil, err } return io.ReadAll(resp.Body) } func (c *Client) CopyResources(from, path string, overwrite bool) error { data := url.Values{} data.Set("from", from) data.Set("path", path) if overwrite { data.Set("overwrite", "true") } req, err := http.NewRequest("PUT", V1_DISK_API+"resources/copy?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) MoveResources(from, path string, overwrite bool) error { data := url.Values{} data.Set("from", from) data.Set("path", path) if overwrite { data.Set("overwrite", "true") } req, err := http.NewRequest("PUT", V1_DISK_API+"resources/move?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) DeleteResources(path string, permanently bool) error { data := url.Values{} data.Set("path", path) if permanently { data.Set("permanently", "true") } req, err := http.NewRequest("DELETE", V1_DISK_API+"resources?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) PublishResources(path string) (href string, err error) { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("PUT", V1_DISK_API+"resources/publish?"+data.Encode(), nil) if err != nil { return "", err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } if err = checkError(resp); err != nil { return "", err } var r RespPublishResources err = json.NewDecoder(resp.Body).Decode(&r) return r.Href, err } func (c *Client) UnpublishResources(path string) error { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("PUT", V1_DISK_API+"resources/unpublish?"+data.Encode(), nil) if err != nil { return err } c.setHeaders(req) resp, err := http.DefaultClient.Do(req) if err != nil { return err } return checkError(resp) } func (c *Client) setHeaders(req *http.Request) { req.Header.Set("LocalUserID", c.userID) req.Header.Set("Content-Type", "application/json") } func checkError(resp *http.Response) error { switch resp.StatusCode { case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: return nil } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return err } return fmt.Errorf(fmt.Sprintf("api/penaDisk: %v | %v", resp.StatusCode, string(body))) }