-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b136b91
commit 7d5ce8b
Showing
14 changed files
with
536 additions
and
121 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package alist | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"io" | ||
"net/http" | ||
"strings" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
type Resposne[T any] struct { | ||
Code int `json:"code"` | ||
Message string `json:"message"` | ||
Data T `json:"data"` | ||
} | ||
|
||
type Config struct { | ||
Username string | ||
Password string | ||
URL string | ||
} | ||
|
||
func New(cfg *Config) *Client { | ||
cfg.URL = strings.Trim(cfg.URL, "/") | ||
return &Client{ | ||
cfg: cfg, | ||
http: http.DefaultClient, | ||
} | ||
} | ||
|
||
type Client struct { | ||
cfg *Config | ||
http *http.Client | ||
token string | ||
} | ||
|
||
func (c *Client) Login() (string, error) { | ||
p := map[string]string{ | ||
"username": c.cfg.Username, | ||
"password": c.cfg.Password, | ||
} | ||
data, _ := json.Marshal(p) | ||
resp, err := c.http.Post(c.cfg.URL+loginUrl, "application/json", bytes.NewBuffer(data)) | ||
if err != nil { | ||
return "", errors.Wrap(err, "login") | ||
} | ||
defer resp.Body.Close() | ||
d1, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return "", errors.Wrap(err, "read body") | ||
} | ||
var rp Resposne[map[string]string] | ||
|
||
err = json.Unmarshal(d1, &rp) | ||
if err != nil { | ||
return "", errors.Wrap(err, "json") | ||
} | ||
if rp.Code != 200 { | ||
return "", errors.Errorf("alist error: code %d, %s", rp.Code, rp.Message) | ||
} | ||
c.token = rp.Data["token"] | ||
return c.token, nil | ||
} | ||
|
||
type LsInfo struct { | ||
Content []struct { | ||
Name string `json:"name"` | ||
Size int `json:"size"` | ||
IsDir bool `json:"is_dir"` | ||
Modified time.Time `json:"modified"` | ||
Created time.Time `json:"created"` | ||
Sign string `json:"sign"` | ||
Thumb string `json:"thumb"` | ||
Type int `json:"type"` | ||
Hashinfo string `json:"hashinfo"` | ||
HashInfo any `json:"hash_info"` | ||
} `json:"content"` | ||
Total int `json:"total"` | ||
Readme string `json:"readme"` | ||
Header string `json:"header"` | ||
Write bool `json:"write"` | ||
Provider string `json:"provider"` | ||
} | ||
|
||
func (c *Client) Ls(dir string) (*LsInfo, error) { | ||
in := map[string]string{ | ||
"path": dir, | ||
} | ||
|
||
resp, err := c.post(c.cfg.URL+lsUrl, in) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "http") | ||
} | ||
|
||
var out Resposne[LsInfo] | ||
err = json.Unmarshal(resp, &out) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if out.Code != 200 { | ||
return nil, errors.Errorf("alist error: code %d, %s", out.Code, out.Message) | ||
} | ||
return &out.Data, nil | ||
} | ||
|
||
func (c *Client) Mkdir(dir string) error { | ||
in := map[string]string{ | ||
"path": dir, | ||
} | ||
resp, err := c.post(c.cfg.URL+mkdirUrl, in) | ||
if err != nil { | ||
return errors.Wrap(err, "http") | ||
} | ||
var out Resposne[any] | ||
err = json.Unmarshal(resp, &out) | ||
if err != nil { | ||
return err | ||
} | ||
if out.Code != 200 { | ||
return errors.Errorf("alist error: code %d, %s", out.Code, out.Message) | ||
} | ||
return nil | ||
} | ||
|
||
func (c *Client) post(url string, body interface{}) ([]byte, error) { | ||
data, err := json.Marshal(body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "new request") | ||
} | ||
|
||
req.Header.Add("Authorization", c.token) | ||
req.Header.Set("Content-Type", "application/json") | ||
|
||
resp, err := c.http.Do(req) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "http") | ||
} | ||
defer resp.Body.Close() | ||
d1, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "read body") | ||
} | ||
return d1, nil | ||
} | ||
|
||
type UploadStreamResponse struct { | ||
Task struct { | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
State int `json:"state"` | ||
Status string `json:"status"` | ||
Progress int `json:"progress"` | ||
Error string `json:"error"` | ||
} `json:"task"` | ||
} | ||
|
||
func (c *Client) UploadStream(reader io.Reader, toDir string) (*UploadStreamResponse, error) { | ||
req, err := http.NewRequest(http.MethodPost, c.cfg.URL+streamUploadUrl, reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req.Header.Add("Authorization", "{{alist_token}}") | ||
req.Header.Add("File-Path", toDir) | ||
req.Header.Add("As-Task", "true") | ||
req.Header.Add("Content-Length", "") | ||
req.Header.Add("Content-Type", "application/octet-stream") | ||
res, err := c.http.Do(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer res.Body.Close() | ||
d1, err := io.ReadAll(res.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var out Resposne[UploadStreamResponse] | ||
err = json.Unmarshal(d1, &out) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if out.Code != 200 { | ||
return nil, errors.Errorf("alist error: code %d, %s", out.Code, out.Message) | ||
} | ||
|
||
return &out.Data, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package alist | ||
|
||
import ( | ||
"polaris/log" | ||
"testing" | ||
) | ||
|
||
func TestLogin(t *testing.T) { | ||
c := New(&Config{ | ||
URL: "http://10.0.0.8:5244/", | ||
Username: "", | ||
Password: "", | ||
}) | ||
cre, err := c.Login() | ||
if err != nil { | ||
log.Errorf("login fail: %v", err) | ||
t.Fail() | ||
} else { | ||
log.Errorf("login success: %s", cre) | ||
} | ||
info, err := c.Ls("/aliyun") | ||
if err != nil { | ||
log.Errorf("ls fail: %v", err) | ||
t.Fail() | ||
} else { | ||
log.Infof("ls results: %+v", info) | ||
} | ||
err = c.Mkdir("/aliyun/test1") | ||
log.Errorf("mkdir: %v", err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package alist | ||
|
||
const ( | ||
loginUrl = "/api/auth/login" | ||
lsUrl = "/api/fs/list" | ||
mkdirUrl = "/api/fs/mkdir" | ||
streamUploadUrl = "/api/fs/put" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package storage | ||
|
||
import ( | ||
"io" | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"polaris/pkg/alist" | ||
|
||
"github.com/gabriel-vasile/mimetype" | ||
) | ||
|
||
func NewAlist(cfg *alist.Config, dir string) (*Alist, error) { | ||
cl := alist.New(cfg) | ||
_, err := cl.Login() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Alist{baseDir: dir, cfg: cfg, client: cl}, nil | ||
} | ||
|
||
type Alist struct { | ||
baseDir string | ||
cfg *alist.Config | ||
client *alist.Client | ||
progresser func() float64 | ||
} | ||
|
||
func (a *Alist) Move(src, dest string) error { | ||
if err := a.Copy(src, dest); err != nil { | ||
return err | ||
} | ||
return os.RemoveAll(src) | ||
} | ||
|
||
func (a *Alist) Copy(src, dest string) error { | ||
b, err := NewBase(src) | ||
if err != nil { | ||
return err | ||
} | ||
a.progresser = b.Progress | ||
|
||
uploadFunc := func(destPath string, destInfo fs.FileInfo, srcReader io.Reader, mimeType *mimetype.MIME) error { | ||
_, err := a.client.UploadStream(srcReader, destPath) | ||
return err | ||
} | ||
mkdirFunc := func(dir string) error { | ||
return a.client.Mkdir(dir) | ||
} | ||
|
||
baseDest := filepath.Join(a.baseDir, dest) | ||
return b.Upload(baseDest, false, false, false, uploadFunc, mkdirFunc) | ||
} | ||
|
||
func (a *Alist) ReadDir(dir string) ([]fs.FileInfo, error) { | ||
return nil, nil | ||
} | ||
|
||
func (a *Alist) ReadFile(s string) ([]byte, error) { | ||
return nil, nil | ||
} | ||
|
||
func (a *Alist) WriteFile(s string, bytes []byte) error { | ||
return nil | ||
} | ||
|
||
func (a *Alist) UploadProgress() float64 { | ||
if a.progresser == nil { | ||
return 0 | ||
} | ||
return a.progresser() | ||
} |
Oops, something went wrong.