mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 14:57:16 +08:00
354 lines
8.2 KiB
Go
354 lines
8.2 KiB
Go
//go:build !linux
|
||
|
||
// 这个文件只是为了在 Windows 下能编译通过,实际上并没有任何卵用
|
||
|
||
package service
|
||
|
||
import (
|
||
"fmt"
|
||
"net/http"
|
||
stdos "os"
|
||
"path/filepath"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/go-rat/chix"
|
||
|
||
"github.com/TheTNB/panel/internal/http/request"
|
||
"github.com/TheTNB/panel/pkg/io"
|
||
"github.com/TheTNB/panel/pkg/shell"
|
||
"github.com/TheTNB/panel/pkg/str"
|
||
)
|
||
|
||
type FileService struct {
|
||
}
|
||
|
||
func NewFileService() *FileService {
|
||
return &FileService{}
|
||
}
|
||
|
||
func (s *FileService) Create(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileCreate](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if !req.Dir {
|
||
if _, err = shell.Execf("touch %s", req.Path); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
} else {
|
||
if err = io.Mkdir(req.Path, 0755); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
}
|
||
|
||
s.setPermission(req.Path, 0755, "www", "www")
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Content(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePath](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
fileInfo, err := io.FileInfo(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
if fileInfo.IsDir() {
|
||
Error(w, http.StatusInternalServerError, "目标路径不是文件")
|
||
return
|
||
}
|
||
if fileInfo.Size() > 10*1024*1024 {
|
||
Error(w, http.StatusInternalServerError, "文件大小超过 10 M,不支持在线编辑")
|
||
return
|
||
}
|
||
|
||
content, err := io.Read(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, content)
|
||
}
|
||
|
||
func (s *FileService) Save(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileSave](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
fileInfo, err := io.FileInfo(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.Write(req.Path, req.Content, fileInfo.Mode()); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
s.setPermission(req.Path, 0755, "www", "www")
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Delete(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePath](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.Remove(req.Path); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Upload(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileUpload](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.Write(req.Path, string(req.File), 0755); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
s.setPermission(req.Path, 0755, "www", "www")
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Move(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileMove](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if io.Exists(req.Target) && !req.Force {
|
||
Error(w, http.StatusForbidden, "目标路径"+req.Target+"已存在")
|
||
}
|
||
|
||
if err = io.Mv(req.Source, req.Target); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Copy(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileCopy](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if io.Exists(req.Target) && !req.Force {
|
||
Error(w, http.StatusForbidden, "目标路径"+req.Target+"已存在")
|
||
}
|
||
|
||
if err = io.Cp(req.Source, req.Target); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Download(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePath](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
info, err := io.FileInfo(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
if info.IsDir() {
|
||
Error(w, http.StatusInternalServerError, "不能下载目录")
|
||
return
|
||
}
|
||
|
||
render := chix.NewRender(w, r)
|
||
defer render.Release()
|
||
render.Download(req.Path, info.Name())
|
||
}
|
||
|
||
func (s *FileService) RemoteDownload(w http.ResponseWriter, r *http.Request) {
|
||
}
|
||
|
||
func (s *FileService) Info(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePath](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
info, err := io.FileInfo(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, chix.M{
|
||
"name": info.Name(),
|
||
"size": str.FormatBytes(float64(info.Size())),
|
||
"mode_str": info.Mode().String(),
|
||
"mode": fmt.Sprintf("%04o", info.Mode().Perm()),
|
||
"dir": info.IsDir(),
|
||
"modify": info.ModTime().Format(time.DateTime),
|
||
})
|
||
}
|
||
|
||
func (s *FileService) Permission(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePermission](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
// 解析成8进制
|
||
mode, err := strconv.ParseUint(req.Mode, 8, 64)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.Chmod(req.Path, stdos.FileMode(mode)); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
if err = io.Chown(req.Path, req.Owner, req.Group); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Compress(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileCompress](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.Compress(req.Paths, req.File, io.Zip); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
s.setPermission(req.File, 0755, "www", "www")
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) UnCompress(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileUnCompress](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
if err = io.UnCompress(req.File, req.Path, io.Zip); err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
s.setPermission(req.Path, 0755, "www", "www")
|
||
Success(w, nil)
|
||
}
|
||
|
||
func (s *FileService) Search(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FileSearch](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
paths := make(map[string]stdos.FileInfo)
|
||
err = filepath.Walk(req.Path, func(path string, info stdos.FileInfo, err error) error {
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if strings.Contains(info.Name(), req.KeyWord) {
|
||
paths[path] = info
|
||
}
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
Success(w, paths)
|
||
}
|
||
|
||
func (s *FileService) List(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.FilePath](r)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
fileInfoList, err := io.ReadDir(req.Path)
|
||
if err != nil {
|
||
Error(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
var paths []any
|
||
for _, fileInfo := range fileInfoList {
|
||
info, _ := fileInfo.Info()
|
||
|
||
paths = append(paths, map[string]any{
|
||
"name": info.Name(),
|
||
"full": filepath.Join(req.Path, info.Name()),
|
||
"size": str.FormatBytes(float64(info.Size())),
|
||
"mode_str": info.Mode().String(),
|
||
"mode": fmt.Sprintf("%04o", info.Mode().Perm()),
|
||
"owner": "",
|
||
"group": "",
|
||
"uid": 0,
|
||
"gid": 0,
|
||
"hidden": io.IsHidden(info.Name()),
|
||
"symlink": io.IsSymlink(info.Mode()),
|
||
"link": io.GetSymlink(filepath.Join(req.Path, info.Name())),
|
||
"dir": info.IsDir(),
|
||
"modify": info.ModTime().Format(time.DateTime),
|
||
})
|
||
}
|
||
|
||
paged, total := Paginate(r, paths)
|
||
|
||
Success(w, chix.M{
|
||
"total": total,
|
||
"items": paged,
|
||
})
|
||
}
|
||
|
||
// setPermission
|
||
func (s *FileService) setPermission(path string, mode stdos.FileMode, owner, group string) {
|
||
_ = io.Chmod(path, mode)
|
||
_ = io.Chown(path, owner, group)
|
||
}
|