2023-04-03 18:27:15 +00:00
|
|
|
|
package penadisk
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"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")
|
2023-04-07 16:39:12 +00:00
|
|
|
|
V1_DISK_API = URL + "api/v1/"
|
2023-04-03 18:27:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-07 16:39:12 +00:00
|
|
|
|
req, err := http.NewRequest("GET", V1_DISK_API+"resources?"+data.Encode(), nil)
|
2023-04-03 18:27:15 +00:00
|
|
|
|
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)
|
2023-04-10 14:51:14 +00:00
|
|
|
|
|
2023-04-03 18:27:15 +00:00
|
|
|
|
|
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
|
path += "/"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := bw.WriteField("path", path); err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if overwrite {
|
|
|
|
|
if err := bw.WriteField("overwrite", "true"); err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fw, err := bw.CreateFormFile("file", filename)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, err = io.Copy(fw, file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 14:51:14 +00:00
|
|
|
|
bw.Close()
|
2023-04-03 18:27:15 +00:00
|
|
|
|
req, err := http.NewRequest("POST", V1_DISK_API+"resources/upload", buf)
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
req.Header.Set("Content-Type", bw.FormDataContentType())
|
|
|
|
|
|
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
2023-04-11 20:00:59 +00:00
|
|
|
|
|
2023-04-03 18:27:15 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = checkError(resp); err != nil {
|
|
|
|
|
return "", "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fullPath = path + filename
|
|
|
|
|
|
|
|
|
|
exportUrl, err = c.GetPublicDownloadURL(fullPath)
|
|
|
|
|
|
|
|
|
|
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)))
|
|
|
|
|
}
|