- 工具栏:面包屑与右侧组件像素级等高(:deep 34px)、合并重复search handler、统一分隔符样式、删除死代码 - 面板对齐:三面板header统一padding/font-size、文件列表分页固定底部(自定义紧凑)、表头默认隐藏、滚动条统一样式 - 预览区:始终显示空白预览面板、重启自动恢复上次打开文件 - 收藏夹:简化计数显示(共N项) - 远程连接:ConnectionIndicator自适应UI(无远程显示mini云图标)、ConnectionDialog支持编辑配置、transport抽象层(本地Wails/远程HTTP双模式)、agent后端模块
106 lines
2.8 KiB
Go
106 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"u-desk/internal/agent/config"
|
|
agentmw "u-desk/internal/agent/middleware"
|
|
"u-desk/internal/agent/handler"
|
|
"u-desk/internal/filesystem"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/labstack/echo/v4/middleware"
|
|
)
|
|
|
|
func main() {
|
|
cfg, err := config.Load("configs/agent.yaml")
|
|
if err != nil {
|
|
log.Fatalf("[FATAL] 加载配置失败: %v", err)
|
|
}
|
|
|
|
fsConfig := filesystem.DefaultConfig()
|
|
fsSvc, err := filesystem.NewFileSystemService(fsConfig)
|
|
if err != nil {
|
|
log.Fatalf("[FATAL] 初始化文件服务失败: %v", err)
|
|
}
|
|
|
|
e := echo.New()
|
|
e.HideBanner = true
|
|
e.HidePort = true
|
|
|
|
e.Use(middleware.Recover())
|
|
e.Use(middleware.Logger())
|
|
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
|
AllowOrigins: cfg.CORS.AllowedOrigins,
|
|
AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE, echo.PATCH, echo.OPTIONS},
|
|
AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAuthorization, echo.HeaderAccept},
|
|
}))
|
|
if cfg.Auth.Token != "" {
|
|
e.Use(agentmw.Auth(cfg.Auth.Token))
|
|
}
|
|
|
|
h := handler.New(fsSvc, cfg)
|
|
|
|
api := e.Group("/api/v1")
|
|
{
|
|
api.GET("/ping", h.Ping)
|
|
api.GET("/info", h.Info)
|
|
|
|
// 文件操作 — 所有通过 ?path= 参数传递路径
|
|
api.GET("/fs", h.ListOrStat) // ?path=xxx [&action=stat]
|
|
api.GET("/fs/read", h.ReadFile) // ?path=xxx
|
|
api.PUT("/fs/write", h.WriteFile) // ?path=xxx & body={content}
|
|
api.POST("/fs/create", h.Create) // ?path=xxx & body={type,name}
|
|
api.DELETE("/fs/delete", h.Delete) // ?path=xxx
|
|
api.PATCH("/fs/rename", h.Rename) // ?path=xxx & body={new_path}
|
|
api.POST("/fs/upload", h.Upload) // ?path=xxx & body={content}
|
|
api.GET("/fs/detect", h.DetectType) // ?path=xxx
|
|
|
|
sys := api.Group("/system")
|
|
{
|
|
sys.GET("/common-paths", h.CommonPaths)
|
|
sys.GET("/drives", h.Drives)
|
|
}
|
|
|
|
proxy := api.Group("/proxy")
|
|
{
|
|
proxy.GET("/localfs/*", h.FileServerProxy)
|
|
proxy.GET("/html-preview", h.HTMLPreviewProxy)
|
|
}
|
|
}
|
|
|
|
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
|
go func() {
|
|
log.Printf("[INFO] u-fs-agent 启动于 %s", addr)
|
|
if err := e.Start(addr); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("[FATAL] HTTP 服务器错误: %v", err)
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
if _, err := filesystem.StartLocalFileServer(); err != nil {
|
|
log.Printf("[WARN] 文件服务器启动失败(媒体预览不可用): %v", err)
|
|
}
|
|
}()
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
log.Println("[INFO] 正在关闭...")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
filesystem.ShutdownLocalFileServer()
|
|
e.Shutdown(ctx)
|
|
fsSvc.Close(ctx)
|
|
log.Println("[INFO] 已关闭")
|
|
}
|