自动更新管控端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

251 lines
6.0 KiB

package handler
import (
"encoding/json"
"fmt"
"html/template"
"io"
"mime"
"strings"
"time"
"net/http"
"os"
"path/filepath"
"xtcfs/config"
"xtcfs/util"
"github.com/chyok/st/web"
)
// rpc功能 压缩包的结构体
// 文件路径 文件名
type Args struct {
Zpfile, Fname string
}
// 获取文件大小的接口
type Size interface {
Size() int64
}
// 获取文件信息的接口
type Stat interface {
Stat() (os.FileInfo, error)
}
// 显示状态
func ReceiveStatus(w http.ResponseWriter, r *http.Request) {
switch r.Method {
// 显示当前传送文件的大小
case http.MethodPost:
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if statInterface, ok := file.(Stat); ok {
fileInfo, _ := statInterface.Stat()
fmt.Fprintf(w, "上传文件的大小为: %d", fileInfo.Size())
}
if sizeInterface, ok := file.(Size); ok {
fmt.Fprintf(w, "上传文件的大小为: %d", sizeInterface.Size())
}
return
}
// fmt.Fprintf(w, r.Method)
}
// 接收 上传
func ReceiveHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// serve upload page for receive
// tmpl, err := template.New("index").Parse(web.UploadPage)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// return
// }
// // 获取当前设备名称
// err = tmpl.Execute(w, config.G.DeviceName)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// }
//
fmt.Fprintf(w, "%s:接收文件中...", r.Host)
case http.MethodPost:
// receive file and save
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
_, params, err := mime.ParseMediaType(header.Header.Get("Content-Disposition"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
filename := filepath.FromSlash(params["filename"])
// fpath
bfpath := r.Header.Get("Fpath")
//debug
fmt.Printf("header params:%v\n", r.Header)
fmt.Printf("fpath is:%s,afbs64 is:%s\n", bfpath, util.Base64dec(bfpath))
fmt.Printf("Downloading [%s]...\n", filename)
// 拼装完整路径
nfname := filepath.Join(config.G.FilePath, util.Base64dec(bfpath))
dirPath := filepath.Dir(nfname)
//dirPath := filepath.Dir(filename)
err = os.MkdirAll(dirPath, os.ModePerm)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 检查文件是否存在
if util.IsFileExist(filename) {
// 文件重命名
dstfname := filename + "_backup_" + time.Now().Format("20060102150405")
os.Rename(filename, dstfname)
}
out, err := os.Create(nfname)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 如果单文件,需要先备份
// 如果收到的是zip文件,自动给解压缩
suf := strings.Split(filename, ".")
if suf[1] == "zip" {
go util.DecompressZip(filename)
}
fmt.Printf("[√] Download [%s] Success.\n", filename)
//
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
// 输出接收结果
// fmt.Fprintf(w, "接收成功,并已经完成解压缩")
}
// 文件服务
func FileServerHandler(w http.ResponseWriter, r *http.Request) {
currentPath := config.G.FilePath
fileInfo, err := os.Stat(currentPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
basePath := filepath.Base(currentPath)
if fileInfo.IsDir() {
path := r.URL.Path[len("/download/"+basePath):]
fullPath := filepath.Join(currentPath, path)
http.ServeFile(w, r, fullPath)
} else {
http.ServeFile(w, r, currentPath)
}
}
// 发送拦截
func SendHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// serve download page for send
realFilePath := filepath.Join(config.G.FilePath, r.URL.Path[1:])
downloadPath := filepath.Join(filepath.Base(config.G.FilePath), r.URL.Path[1:])
fileInfo, err := os.Stat(realFilePath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := struct {
DeviceName string
IsDir bool
FileName string
DownloadPath string
UrlPath string
Files []os.DirEntry
}{
DeviceName: config.G.DeviceName,
DownloadPath: downloadPath,
UrlPath: strings.TrimSuffix(r.URL.Path, "/"),
}
if fileInfo.IsDir() {
data.IsDir = true
// 遍历目录
files, err := os.ReadDir(realFilePath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data.Files = files
} else {
data.FileName = filepath.Base(realFilePath)
}
// 文件列表模板
tmpl, err := template.New("download").Parse(web.DownloadPage)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
case http.MethodPost:
// return file or folder information in JSON format for convenient send to the recipient
currentPath := config.G.FilePath
fileInfo, err := os.Stat(currentPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var pathInfo struct {
Type string `json:"type"`
Paths []string `json:"paths"`
}
if fileInfo.IsDir() {
files, err := util.GetDirFilePaths(currentPath, true)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
pathInfo.Paths = files
pathInfo.Type = "dir"
} else {
pathInfo.Paths = []string{filepath.Base(currentPath)}
pathInfo.Type = "file"
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(pathInfo)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}