mirror of
https://github.com/AlistGo/alist.git
synced 2025-12-19 02:50:06 +08:00
Add support for Gofile.io cloud storage service with full CRUD operations. Features: - File and folder listing - Upload and download functionality - Create, move, rename, copy, and delete operations - Direct link generation for file access - API token authentication The driver implements all required driver interfaces and follows the existing driver patterns in the codebase.
261 lines
5.9 KiB
Go
261 lines
5.9 KiB
Go
package gofile
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/alist-org/alist/v3/internal/driver"
|
|
"github.com/alist-org/alist/v3/internal/errs"
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
"github.com/alist-org/alist/v3/internal/op"
|
|
)
|
|
|
|
type Gofile struct {
|
|
model.Storage
|
|
Addition
|
|
|
|
accountId string
|
|
}
|
|
|
|
func (d *Gofile) Config() driver.Config {
|
|
return config
|
|
}
|
|
|
|
func (d *Gofile) GetAddition() driver.Additional {
|
|
return &d.Addition
|
|
}
|
|
|
|
func (d *Gofile) Init(ctx context.Context) error {
|
|
if d.APIToken == "" {
|
|
return fmt.Errorf("API token is required")
|
|
}
|
|
|
|
// Get account ID
|
|
accountId, err := d.getAccountId(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get account ID: %w", err)
|
|
}
|
|
d.accountId = accountId
|
|
|
|
// Get account info to set root folder if not specified
|
|
if d.RootFolderID == "" {
|
|
accountInfo, err := d.getAccountInfo(ctx, accountId)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get account info: %w", err)
|
|
}
|
|
d.RootFolderID = accountInfo.Data.RootFolder
|
|
}
|
|
|
|
// Save driver storage
|
|
op.MustSaveDriverStorage(d)
|
|
return nil
|
|
}
|
|
|
|
func (d *Gofile) Drop(ctx context.Context) error {
|
|
return nil
|
|
}
|
|
|
|
func (d *Gofile) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
|
var folderId string
|
|
if dir.GetID() == "" {
|
|
folderId = d.GetRootId()
|
|
} else {
|
|
folderId = dir.GetID()
|
|
}
|
|
|
|
endpoint := fmt.Sprintf("/contents/%s", folderId)
|
|
|
|
var response ContentsResponse
|
|
err := d.getJSON(ctx, endpoint, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var objects []model.Obj
|
|
|
|
// Process children or contents
|
|
contents := response.Data.Children
|
|
if contents == nil {
|
|
contents = response.Data.Contents
|
|
}
|
|
|
|
for _, content := range contents {
|
|
objects = append(objects, d.convertContentToObj(content))
|
|
}
|
|
|
|
return objects, nil
|
|
}
|
|
|
|
func (d *Gofile) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
|
if file.IsDir() {
|
|
return nil, errs.NotFile
|
|
}
|
|
|
|
// Create a direct link for the file
|
|
directLink, err := d.createDirectLink(ctx, file.GetID())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create direct link: %w", err)
|
|
}
|
|
|
|
return &model.Link{
|
|
URL: directLink,
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
|
|
var parentId string
|
|
if parentDir.GetID() == "" {
|
|
parentId = d.GetRootId()
|
|
} else {
|
|
parentId = parentDir.GetID()
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"parentFolderId": parentId,
|
|
"folderName": dirName,
|
|
}
|
|
|
|
var response CreateFolderResponse
|
|
err := d.postJSON(ctx, "/contents/createFolder", data, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &model.Object{
|
|
ID: response.Data.ID,
|
|
Name: response.Data.Name,
|
|
IsFolder: true,
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
|
var dstId string
|
|
if dstDir.GetID() == "" {
|
|
dstId = d.GetRootId()
|
|
} else {
|
|
dstId = dstDir.GetID()
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"contentsId": srcObj.GetID(),
|
|
"folderId": dstId,
|
|
}
|
|
|
|
err := d.putJSON(ctx, "/contents/move", data, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Return updated object
|
|
return &model.Object{
|
|
ID: srcObj.GetID(),
|
|
Name: srcObj.GetName(),
|
|
Size: srcObj.GetSize(),
|
|
Modified: srcObj.ModTime(),
|
|
IsFolder: srcObj.IsDir(),
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
|
|
data := map[string]interface{}{
|
|
"attribute": "name",
|
|
"attributeValue": newName,
|
|
}
|
|
|
|
var response UpdateResponse
|
|
err := d.putJSON(ctx, fmt.Sprintf("/contents/%s/update", srcObj.GetID()), data, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &model.Object{
|
|
ID: srcObj.GetID(),
|
|
Name: newName,
|
|
Size: srcObj.GetSize(),
|
|
Modified: srcObj.ModTime(),
|
|
IsFolder: srcObj.IsDir(),
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
|
var dstId string
|
|
if dstDir.GetID() == "" {
|
|
dstId = d.GetRootId()
|
|
} else {
|
|
dstId = dstDir.GetID()
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"contentsId": srcObj.GetID(),
|
|
"folderId": dstId,
|
|
}
|
|
|
|
var response CopyResponse
|
|
err := d.postJSON(ctx, "/contents/copy", data, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get the new ID from the response
|
|
newId := srcObj.GetID()
|
|
if response.Data.CopiedContents != nil {
|
|
if id, ok := response.Data.CopiedContents[srcObj.GetID()]; ok {
|
|
newId = id
|
|
}
|
|
}
|
|
|
|
return &model.Object{
|
|
ID: newId,
|
|
Name: srcObj.GetName(),
|
|
Size: srcObj.GetSize(),
|
|
Modified: srcObj.ModTime(),
|
|
IsFolder: srcObj.IsDir(),
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) Remove(ctx context.Context, obj model.Obj) error {
|
|
data := map[string]interface{}{
|
|
"contentsId": obj.GetID(),
|
|
}
|
|
|
|
return d.deleteJSON(ctx, "/contents", data)
|
|
}
|
|
|
|
func (d *Gofile) Put(ctx context.Context, dstDir model.Obj, fileStreamer model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
|
var folderId string
|
|
if dstDir.GetID() == "" {
|
|
folderId = d.GetRootId()
|
|
} else {
|
|
folderId = dstDir.GetID()
|
|
}
|
|
|
|
response, err := d.uploadFile(ctx, folderId, fileStreamer, up)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &model.Object{
|
|
ID: response.Data.FileId,
|
|
Name: response.Data.FileName,
|
|
Size: fileStreamer.GetSize(),
|
|
IsFolder: false,
|
|
}, nil
|
|
}
|
|
|
|
func (d *Gofile) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
func (d *Gofile) ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error) {
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
func (d *Gofile) Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error) {
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
func (d *Gofile) ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error) {
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
var _ driver.Driver = (*Gofile)(nil) |