Compare commits
5
Commits
8f8d098faa
...
011a3356b7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
011a3356b7 | ||
|
|
4aba71d451 | ||
|
|
6d550505a0 | ||
|
|
d6816925ed | ||
|
|
47590ec0db |
No files matched your search
+2
-1
@@ -23,9 +23,10 @@ dist-ssr
|
||||
*.sln
|
||||
*.sw?
|
||||
.vscode
|
||||
serve
|
||||
miao-directory.exe
|
||||
miao-directory-amd64-linux
|
||||
miao-directory-amd64-win.exe
|
||||
test
|
||||
stats.html
|
||||
|
||||
src-server/web/*
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
"dev": "vite",
|
||||
"dev:host": "vite --host 0.0.0.0",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"build:auto": "pnpm run build && go env -w GOOS=windows GOARCH=amd64 && rm -rf ./serve/web/* && cp -r ./dist/* ./serve/web/ && cd ./serve && go env -w GOOS=windows && go build -o ../miao-directory.exe",
|
||||
"build:auto:release": "pnpm run build && rm -rf ./serve/web/* && cp -r ./dist/* ./serve/web/ && cd ./serve && go env -w GOOS=windows GOARCH=amd64 && go build -o ../miao-directory-amd64-win.exe && go env -w GOOS=linux GOARCH=amd64 && go build -o ../miao-directory-amd64-linux",
|
||||
"build:auto": "pnpm run build && go env -w GOOS=windows GOARCH=amd64 && rm -rf ./src-server/web/* && cp -r ./dist/* ./src-server/web/ && cd ./src-server && go env -w GOOS=windows && go build -o ../miao-directory.exe",
|
||||
"build:auto:release": "pnpm run build && rm -rf ./src-server/web/* && cp -r ./dist/* ./src-server/web/ && cd ./src-server && go env -w GOOS=windows GOARCH=amd64 && go build -o ../miao-directory-amd64-win.exe && go env -w GOOS=linux GOARCH=amd64 && go build -o ../miao-directory-amd64-linux",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package api
|
||||
|
||||
var staticPath = "./"
|
||||
@@ -0,0 +1,57 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
)
|
||||
|
||||
func CopyHandler(fsOperateEventCenter *fsOperateEventCenter.FsOperateEventCenter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req struct {
|
||||
NewPath string `json:"newPath"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
newPath := filepath.Join(staticPath, req.NewPath, filepath.Base(decodedPath))
|
||||
eventId := fsOperateEventCenter.Push(func() error {
|
||||
return copyFile(decodedPath, newPath)
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{"eventId": eventId})
|
||||
}
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
sourceFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
destFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, sourceFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return destFile.Sync()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
)
|
||||
|
||||
func CutHandler(fsOperateEventCenter *fsOperateEventCenter.FsOperateEventCenter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req struct {
|
||||
NewPath string `json:"newPath"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
newPath := filepath.Join(staticPath, req.NewPath, filepath.Base(decodedPath))
|
||||
eventId := fsOperateEventCenter.Push(func() error {
|
||||
return os.Rename(decodedPath, newPath)
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{"eventId": eventId})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func DeleteHandler(fsOperateEventCenter *fsOperateEventCenter.FsOperateEventCenter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
eventId := fsOperateEventCenter.Push(func() error {
|
||||
return os.RemoveAll(decodedPath)
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{"eventId": eventId})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetHandler(c *gin.Context) {
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(decodedPath)
|
||||
if os.IsNotExist(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Path not found"})
|
||||
return
|
||||
}
|
||||
|
||||
if fileInfo.IsDir() {
|
||||
files, err := ioutil.ReadDir(decodedPath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to scan directory"})
|
||||
return
|
||||
}
|
||||
|
||||
var fileDetails []gin.H
|
||||
for _, file := range files {
|
||||
fileDetails = append(fileDetails, gin.H{
|
||||
"name": file.Name(),
|
||||
"size": file.Size(),
|
||||
"type": func() string {
|
||||
if file.IsDir() {
|
||||
return "directory"
|
||||
}
|
||||
return "file"
|
||||
}(),
|
||||
"stats": gin.H{
|
||||
"atimeMs": file.ModTime().UnixNano() / 1e6,
|
||||
"birthtimeMs": file.ModTime().UnixNano() / 1e6,
|
||||
"ctimeMs": file.ModTime().UnixNano() / 1e6,
|
||||
"mtimeMs": file.ModTime().UnixNano() / 1e6,
|
||||
},
|
||||
})
|
||||
}
|
||||
if len(fileDetails) == 0 {
|
||||
c.JSON(http.StatusOK, []gin.H{})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, fileDetails)
|
||||
}
|
||||
} else {
|
||||
if strings.HasSuffix(decodedPath, "index.html") {
|
||||
f, err := os.Open(decodedPath)
|
||||
if err != nil {
|
||||
c.Writer.WriteHeader(http.StatusInternalServerError)
|
||||
c.Writer.Write([]byte("Internal Server Error"))
|
||||
return
|
||||
}
|
||||
http.ServeContent(c.Writer, c.Request, "index.html", time.Now(), f)
|
||||
} else {
|
||||
// if c.Query("import") != "" {
|
||||
// c.Writer.Header().Set("Content-Type", "application/javascript")
|
||||
// }
|
||||
ext := filepath.Ext(decodedPath)
|
||||
switch ext {
|
||||
case ".js":
|
||||
case ".cjs":
|
||||
c.Writer.Header().Set("Content-Type", "application/javascript")
|
||||
case ".css":
|
||||
c.Writer.Header().Set("Content-Type", "text/css")
|
||||
case ".html":
|
||||
c.Writer.Header().Set("Content-Type", "text/html")
|
||||
case ".json":
|
||||
c.Writer.Header().Set("Content-Type", "application/json")
|
||||
default:
|
||||
c.Writer.Header().Set("Content-Type", "application/octet-stream")
|
||||
}
|
||||
c.File(decodedPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func MkdirHandler(c *gin.Context) {
|
||||
var request struct {
|
||||
FolderName string `json:"folderName"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
mkdirPath := filepath.Join(decodedPath, request.FolderName)
|
||||
|
||||
if err := os.MkdirAll(mkdirPath, os.ModePerm); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
)
|
||||
|
||||
func QueryHandler(fsOperateEventCenter *fsOperateEventCenter.FsOperateEventCenter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
idStr := c.Query("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id"})
|
||||
return
|
||||
}
|
||||
|
||||
event := fsOperateEventCenter.Query(int32(id))
|
||||
c.JSON(http.StatusOK, event)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
)
|
||||
|
||||
func RenameHandler(fsOperateEventCenter *fsOperateEventCenter.FsOperateEventCenter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req struct {
|
||||
NewName string `json:"newName"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
newTargetPath := filepath.Join(filepath.Dir(decodedPath), req.NewName)
|
||||
eventId := fsOperateEventCenter.Push(func() error {
|
||||
return os.Rename(decodedPath, newTargetPath)
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{"eventId": eventId})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func UploadHandler(c *gin.Context) {
|
||||
fileName := c.PostForm("fileName")
|
||||
operateType := c.PostForm("operateType")
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
decodedPath, err := filepath.Abs(filepath.Join(staticPath, c.Param("path")))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": "Unable to access path"})
|
||||
return
|
||||
}
|
||||
|
||||
savePath := filepath.Join(decodedPath, fileName)
|
||||
fileData, err := file.Open()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer fileData.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(fileData)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if operateType == "write" {
|
||||
err = ioutil.WriteFile(savePath, data, 0644)
|
||||
} else {
|
||||
f, err := os.OpenFile(savePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write(data)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "failed", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package fsOperateEventCenter
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FsOperateEventStatus string
|
||||
|
||||
const (
|
||||
FsOperateEventStatusProgress FsOperateEventStatus = "progress"
|
||||
FsOperateEventStatusSuccess FsOperateEventStatus = "success"
|
||||
FsOperateEventStatusFailed FsOperateEventStatus = "failed"
|
||||
FsOperateEventStatusUnknown FsOperateEventStatus = "unknown"
|
||||
)
|
||||
|
||||
type FsOperateEvent struct {
|
||||
Status FsOperateEventStatus `json:"status"`
|
||||
FailedEvent error `json:"failedEvent"`
|
||||
UID int32 `json:"uid"`
|
||||
}
|
||||
|
||||
type FsOperateEventCenter struct {
|
||||
eventMap sync.Map
|
||||
}
|
||||
|
||||
func NewFsOperateEventCenter() *FsOperateEventCenter {
|
||||
return &FsOperateEventCenter{}
|
||||
}
|
||||
|
||||
func (c *FsOperateEventCenter) Push(event func() error) int32 {
|
||||
ev := &FsOperateEvent{
|
||||
Status: FsOperateEventStatusProgress,
|
||||
UID: generateId(),
|
||||
}
|
||||
|
||||
wrapper := &eventWrapper{
|
||||
event: ev,
|
||||
timer: time.AfterFunc(time.Hour, func() {
|
||||
c.Query(ev.UID)
|
||||
}),
|
||||
}
|
||||
|
||||
c.eventMap.Store(ev.UID, wrapper)
|
||||
|
||||
go func() {
|
||||
if err := event(); err != nil {
|
||||
wrapper.event.Status = FsOperateEventStatusFailed
|
||||
wrapper.event.FailedEvent = err
|
||||
} else {
|
||||
wrapper.event.Status = FsOperateEventStatusSuccess
|
||||
}
|
||||
}()
|
||||
|
||||
return ev.UID
|
||||
}
|
||||
|
||||
type eventWrapper struct {
|
||||
event *FsOperateEvent
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
func (c *FsOperateEventCenter) Query(id int32) *FsOperateEvent {
|
||||
val, ok := c.eventMap.Load(id)
|
||||
// fmt.Printf("Query ID: %d; ok: %t; val: %v\n", id, ok, val)
|
||||
|
||||
// c.eventMap.Range(func(key, value interface{}) bool {
|
||||
// fmt.Printf("key: %d (type: %T), id: %d (type: %T), bool: %t\n", key, key, id, id, id == key)
|
||||
// event := value.(*eventWrapper).event
|
||||
// fmt.Printf("Event UID: %d, Status: %s\n", event.UID, event.Status)
|
||||
// return true
|
||||
// })
|
||||
|
||||
if !ok {
|
||||
return &FsOperateEvent{
|
||||
Status: FsOperateEventStatusUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
wrapper := val.(*eventWrapper)
|
||||
if wrapper.event.Status == FsOperateEventStatusSuccess || wrapper.event.Status == FsOperateEventStatusFailed {
|
||||
wrapper.timer.Stop()
|
||||
c.eventMap.Delete(id)
|
||||
}
|
||||
|
||||
return wrapper.event
|
||||
}
|
||||
|
||||
func generateId() int32 {
|
||||
return rand.Int31()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
module miao-directory
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/akavel/rsrc v0.10.2 // indirect
|
||||
github.com/bytedance/sonic v1.12.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||
github.com/gin-contrib/gzip v1.0.1 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.10.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/josephspurrier/goversioninfo v1.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.9.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,86 @@
|
||||
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
|
||||
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24=
|
||||
github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
|
||||
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
||||
github.com/gin-contrib/gzip v1.0.1/go.mod h1:njt428fdUNRvjuJf16tZMYZ2Yl+WQB53X5wmhDwXvC4=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/josephspurrier/goversioninfo v1.4.0 h1:Puhl12NSHUSALHSuzYwPYQkqa2E1+7SrtAPJorKK0C8=
|
||||
github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k=
|
||||
golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,84 @@
|
||||
//go:generate goversioninfo -icon=./icon.ico
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"miao-directory/api"
|
||||
"miao-directory/fsOperateEventCenter"
|
||||
)
|
||||
|
||||
//go:embed all:web/*
|
||||
var webFS embed.FS
|
||||
|
||||
var port = ":17705"
|
||||
|
||||
func main() {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
fsOperateEventCenter := fsOperateEventCenter.NewFsOperateEventCenter()
|
||||
|
||||
router := gin.Default()
|
||||
router.Use(corsMiddleware())
|
||||
|
||||
router.GET("/query", api.QueryHandler(fsOperateEventCenter))
|
||||
router.GET("/get/*path", api.GetHandler)
|
||||
router.POST("/mkdir/*path", api.MkdirHandler)
|
||||
router.POST("/upload/*path", api.UploadHandler)
|
||||
router.POST("/cut/*path", api.CutHandler(fsOperateEventCenter))
|
||||
router.POST("/copy/*path", api.CopyHandler(fsOperateEventCenter))
|
||||
router.POST("/rename/*path", api.RenameHandler(fsOperateEventCenter))
|
||||
router.POST("/delete/*path", api.DeleteHandler(fsOperateEventCenter))
|
||||
|
||||
// Redirect from '/' to '/web/'
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
c.Redirect(http.StatusMovedPermanently, "/web/")
|
||||
})
|
||||
|
||||
// Serve static files from the embedded filesystem with gzip compression
|
||||
staticFS := http.FS(webFS)
|
||||
staticGroup := router.Group("/web")
|
||||
staticGroup.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
staticGroup.GET("/*filepath", func(c *gin.Context) {
|
||||
http.FileServer(staticFS).ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
address := "[::]" + port
|
||||
printListeningAddresses(port)
|
||||
router.Run(address)
|
||||
}
|
||||
|
||||
func corsMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func printListeningAddresses(port string) {
|
||||
host, _ := os.Hostname()
|
||||
addrs, _ := net.LookupHost(host)
|
||||
|
||||
fmt.Printf("Listening on:\n")
|
||||
fmt.Printf(" ➜ Local: http://localhost%s\n", port)
|
||||
for _, addr := range addrs {
|
||||
if strings.Contains(addr, "%") {
|
||||
addr = strings.Split(addr, "%")[0]
|
||||
}
|
||||
if strings.Contains(addr, ":") {
|
||||
// IPv6 address
|
||||
fmt.Printf(" ➜ Network: http://[%s]%s\n", addr, port)
|
||||
} else {
|
||||
// IPv4 address
|
||||
fmt.Printf(" ➜ Network: http://%s%s\n", addr, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# miao-directory的后端部分
|
||||
* 原有的node后端不再维护。
|
||||
* ./web文件夹中的内容自己到main分支去打包一个出来
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"IconPath": "icon.ico"
|
||||
}
|
||||
+7
-18
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, provide, reactive, ref, shallowRef, useTemplateRef } from 'vue'
|
||||
import { computed, onMounted, provide, ref, shallowRef, useTemplateRef } from 'vue'
|
||||
import { NIcon, NScrollbar, NDropdown } from 'naive-ui'
|
||||
import {
|
||||
EyeOffOutline,
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
QrCodeOutline,
|
||||
ExtensionPuzzleOutline
|
||||
} from '@vicons/ionicons5'
|
||||
import VirtualDirectory, { VirtualFile } from './class/VirtualDirectory'
|
||||
import type VirtualDirectory from './class/VirtualDirectory'
|
||||
import type { VirtualFile } from './class/VirtualDirectory'
|
||||
import MiaoMask from './components/miaoMask.vue'
|
||||
import MiaoMessageProvider from './components/miaoAlertTipProvider.vue'
|
||||
import config from './config'
|
||||
@@ -20,6 +21,7 @@ import usePluginCenter from './hooks/usePluginCenter'
|
||||
import PluginCenter, { PluginGroup } from './class/PluginCenter'
|
||||
import { renderIcon } from './hooks/miaoTools'
|
||||
import { DropdownMixedOption } from 'naive-ui/es/dropdown/src/interface'
|
||||
import useRootVDirectory from './hooks/useRootVDirectory'
|
||||
|
||||
const { baseUrl } = config
|
||||
|
||||
@@ -37,17 +39,7 @@ const messageProviderRef = useTemplateRef('messageProviderRef')
|
||||
const views = useVirtualPages()
|
||||
let pluginCenter = ref<PluginCenter>()
|
||||
|
||||
const rootDirectory = reactive(
|
||||
new VirtualDirectory({
|
||||
name: '根目录',
|
||||
stats: {
|
||||
atimeMs: 0,
|
||||
birthtimeMs: 0,
|
||||
ctimeMs: 0,
|
||||
mtimeMs: 0
|
||||
}
|
||||
})
|
||||
)
|
||||
const rootDirectory = useRootVDirectory()
|
||||
|
||||
// component就是一个vue组件,类似于miaoDirectory
|
||||
const createView = (
|
||||
@@ -62,9 +54,6 @@ const createView = (
|
||||
|
||||
const deleteView = (index: number) => {
|
||||
views.deleteView(index)
|
||||
if (views.length === 0) {
|
||||
pluginCenter.value && pluginCenter.value.usePlugin('miaoDirectory', [rootDirectory], [])
|
||||
}
|
||||
}
|
||||
|
||||
// 点击标题是隐藏其他标签或显示其他标签,还挺好用的
|
||||
@@ -127,8 +116,6 @@ onMounted(async () => {
|
||||
// @ts-ignore
|
||||
await init(messageProviderRef.value?.alertTip)
|
||||
pluginCenter.value = usePluginCenter()
|
||||
// console.log({ pluginCenter })
|
||||
pluginCenter.value.usePlugin('miaoDirectory', [rootDirectory], [])
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
@@ -210,6 +197,8 @@ $controller-height: 25px;
|
||||
$tag-width: 170px;
|
||||
|
||||
.view {
|
||||
|
||||
background-color: #ffffff;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
@@ -3,10 +3,13 @@ import VirtualDirectory, { VirtualFile } from "./VirtualDirectory";
|
||||
import { ShallowRef, shallowRef } from "vue";
|
||||
import { alertTipType, usePluginHooksType } from "@/types/type";
|
||||
import VirtualPage, { VirtualPages } from "./VirtualPage";
|
||||
import useRootVDirectory from "@/hooks/useRootVDirectory";
|
||||
|
||||
export enum PluginGroup {
|
||||
default = "default",
|
||||
mainMenu = "mainMenu"
|
||||
mainMenu = "mainMenu",
|
||||
// 导入的时候会立即执行函数一次
|
||||
immediately = "immediately"
|
||||
}
|
||||
|
||||
export interface registerComponentOption {
|
||||
@@ -53,6 +56,13 @@ export default class PluginCenter {
|
||||
|
||||
register(key: string, plugin: Plugin) {
|
||||
this.pluginsMap[key] = plugin;
|
||||
if (plugin.group.includes(PluginGroup.immediately)) {
|
||||
this.usePlugin(key, [], [], this.usePluginHook)
|
||||
}
|
||||
}
|
||||
|
||||
deregister(key: string) {
|
||||
delete this.pluginsMap[key]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,18 +134,21 @@ export default class PluginCenter {
|
||||
return res;
|
||||
}
|
||||
|
||||
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]): void;
|
||||
// usePlugin(key: string, VPages: VirtualPages, ...args: any[]) : void
|
||||
get usePluginHook(): usePluginHooksType {
|
||||
return {
|
||||
globalAlertTip: this.globalAlertTip,
|
||||
getViews: useVirtualPages,
|
||||
getPluginCenter: () => this,
|
||||
getRootVDirectory: () => useRootVDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]): void;
|
||||
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]) {
|
||||
this.pluginsMap[key].func(
|
||||
VDirectories ?? [],
|
||||
VFiles ?? [],
|
||||
{
|
||||
globalAlertTip: this.globalAlertTip,
|
||||
getViews: useVirtualPages,
|
||||
getPluginCenter: () => this
|
||||
},
|
||||
this.usePluginHook,
|
||||
...args
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ import { alertTipType, PluginExportType } from "@/types/type";
|
||||
|
||||
const initPlugin = async (globalAlertTip: alertTipType) => {
|
||||
initPluginCenter(globalAlertTip);
|
||||
const modulesFiles = import.meta.glob("@/plugins/**/export.ts", { eager: true });
|
||||
const modulesFiles = import.meta.glob("@/plugins/**/export*.ts", { eager: true });
|
||||
const pluginCenter = usePluginCenter();
|
||||
const promiseArray = [];
|
||||
for (let pluginConfig of Object.values(modulesFiles)) {
|
||||
promiseArray.push(
|
||||
new Promise(async resolve => {
|
||||
const _config = pluginConfig as {
|
||||
default: registerComponentOption | Plugin;
|
||||
type: PluginExportType;
|
||||
@@ -17,14 +14,11 @@ const initPlugin = async (globalAlertTip: alertTipType) => {
|
||||
};
|
||||
const { type, key } = _config;
|
||||
if (type === PluginExportType.component) {
|
||||
resolve(pluginCenter.registerComponent(_config.default as registerComponentOption));
|
||||
pluginCenter.registerComponent(_config.default as registerComponentOption);
|
||||
} else if (type === PluginExportType.default) {
|
||||
resolve(pluginCenter.register(key as string, _config.default as Plugin));
|
||||
pluginCenter.register(key as string, _config.default as Plugin);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
await Promise.all(promiseArray);
|
||||
};
|
||||
|
||||
export default initPlugin;
|
||||
@@ -0,0 +1,17 @@
|
||||
import VirtualDirectory from "@/class/VirtualDirectory";
|
||||
import { reactive } from "vue";
|
||||
|
||||
const root = reactive(
|
||||
new VirtualDirectory({
|
||||
name: '根目录',
|
||||
stats: {
|
||||
atimeMs: 0,
|
||||
birthtimeMs: 0,
|
||||
ctimeMs: 0,
|
||||
mtimeMs: 0
|
||||
}
|
||||
})
|
||||
)
|
||||
export default function useRootVDirectory() {
|
||||
return root;
|
||||
}
|
||||
@@ -30,7 +30,11 @@ const pluginConfig: registerComponentOption = {
|
||||
'yaml',
|
||||
'txt',
|
||||
'xml',
|
||||
'vue'
|
||||
'vue',
|
||||
'srt',
|
||||
'vtt',
|
||||
'ass',
|
||||
'ssa'
|
||||
]) {
|
||||
if (vFiles[0].name.endsWith(end)) {
|
||||
return true
|
||||
|
||||
@@ -73,6 +73,7 @@ const mainRef = ref<HTMLDivElement>()
|
||||
const draggable = ref(true)
|
||||
|
||||
// 使用ResizeObserver实现
|
||||
// 什么?性能问题?这玩意性能问题多着呢,轮不到它。
|
||||
const clientWidth = ref<number>(666)
|
||||
|
||||
const name = props.name ?? props.item.name
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Plugin, PluginGroup } from "@/class/PluginCenter";
|
||||
import { PluginExportType } from "@/types/type";
|
||||
import { watch } from "vue";
|
||||
|
||||
const pluginConfig: Plugin = {
|
||||
name: "初始化完成之后打开miaoDirectory",
|
||||
filter: () => {
|
||||
return false;
|
||||
},
|
||||
disable: false,
|
||||
group: [PluginGroup.immediately],
|
||||
func: (_, __, hooks) => {
|
||||
const { getPluginCenter, getRootVDirectory, getViews } = hooks
|
||||
const views = getViews();
|
||||
const pc = getPluginCenter();
|
||||
const root = getRootVDirectory();
|
||||
setTimeout(() => {
|
||||
if (views.length === 0) {
|
||||
pc.usePlugin('miaoDirectory', [root])
|
||||
}
|
||||
watch(() => views.length, () => {
|
||||
if(views.length === 0) {
|
||||
pc.usePlugin('miaoDirectory', [root])
|
||||
}
|
||||
})
|
||||
|
||||
pc.deregister('miaoDirectory_onInit')
|
||||
})
|
||||
},
|
||||
priority: -1
|
||||
};
|
||||
|
||||
export default pluginConfig;
|
||||
|
||||
export const type = PluginExportType.default;
|
||||
|
||||
export const key = "miaoDirectory_onInit";
|
||||
File renamed without changes.
@@ -298,7 +298,7 @@ function ssaToVtt(ssaContent: string): string {
|
||||
|
||||
const findVideo = (vFiles: VirtualFile[]) =>
|
||||
uniq(vFiles.filter((v) => {
|
||||
for (let s of ['mp4', 'mp3']) {
|
||||
for (let s of ['mp4', 'mp3', 'mkv']) {
|
||||
if (v.name.endsWith(s)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Plugin, registerComponentOption } from "@/class/PluginCenter";
|
||||
|
||||
export function checkNormalPlugin(obj: any): obj is Plugin {
|
||||
return (
|
||||
typeof obj === "object" &&
|
||||
obj!== null &&
|
||||
typeof obj.name === "string" &&
|
||||
(obj.icon === undefined || typeof obj.icon === "object") &&
|
||||
typeof obj.disable === "boolean" &&
|
||||
Array.isArray(obj.group) &&
|
||||
obj.group.every((group: any) => typeof group === "string") &&
|
||||
typeof obj.priority === "number" &&
|
||||
typeof obj.filter === "function" &&
|
||||
typeof obj.func === "function"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function checkComponentPlugin(
|
||||
obj: any
|
||||
): obj is registerComponentOption {
|
||||
return (
|
||||
typeof obj === "object" &&
|
||||
obj!== null &&
|
||||
typeof obj.key === "string" &&
|
||||
typeof obj.name === "string" &&
|
||||
(obj.icon === undefined || typeof obj.icon === "object") &&
|
||||
typeof obj.getComponent === "function" &&
|
||||
((obj.group === undefined) || (Array.isArray(obj.group) && obj.group.every((item: any) => typeof item === "string"))) &&
|
||||
typeof obj.filter === "function" &&
|
||||
(obj.disable === undefined || typeof obj.disable === "boolean") &&
|
||||
(obj.exitConfirm === undefined || typeof obj.exitConfirm === "boolean") &&
|
||||
(obj.single === undefined || typeof obj.single === "boolean") &&
|
||||
(obj.priority === undefined || typeof obj.priority === "number")
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Plugin, PluginGroup } from "@/class/PluginCenter";
|
||||
import { LogoGithub } from "@vicons/ionicons5";
|
||||
import { PluginExportType } from "@/types/type";
|
||||
import { shallowRef } from "vue";
|
||||
import registerExternalPlugin from "./registerExternalPlugin";
|
||||
|
||||
const pluginConfig: Plugin = {
|
||||
name: "导入插件",
|
||||
icon: shallowRef(LogoGithub),
|
||||
filter: (vDirs, vFiles) => {
|
||||
if (vDirs.length !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (vFiles.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
return vFiles[0].name.endsWith('js')
|
||||
},
|
||||
disable: false,
|
||||
group: [PluginGroup.default],
|
||||
func: registerExternalPlugin,
|
||||
priority: -1
|
||||
};
|
||||
|
||||
export default pluginConfig;
|
||||
|
||||
export const type = PluginExportType.default;
|
||||
|
||||
export const key = 'registerExternalPlugin';
|
||||
@@ -0,0 +1,36 @@
|
||||
import VirtualDirectory, { VirtualFile } from "@/class/VirtualDirectory";
|
||||
// import useMiaoFetchApi from "@/hooks/useMiaoFetchApi";
|
||||
import { PluginExportType, usePluginHooksType } from "@/types/type";
|
||||
import type { Plugin, registerComponentOption } from "@/class/PluginCenter";
|
||||
import { checkComponentPlugin, checkNormalPlugin } from "./checkPluginAvailable";
|
||||
|
||||
// const miaoFetchApi = useMiaoFetchApi()
|
||||
|
||||
export default async function registerExternalPlugin(_VDirectories: VirtualDirectory[], VFiles: VirtualFile[], hooks: usePluginHooksType) {
|
||||
try {
|
||||
const targetPluginVFile = VFiles[0] as VirtualFile
|
||||
const plugin = await import(/* @vite-ignore */ targetPluginVFile.url) as {
|
||||
default: registerComponentOption | Plugin;
|
||||
type: PluginExportType;
|
||||
key?: string;
|
||||
}
|
||||
const pc = hooks.getPluginCenter()
|
||||
if (plugin.type === PluginExportType.default) {
|
||||
if (checkNormalPlugin(plugin.default) === false) {
|
||||
throw('插件不合法')
|
||||
}
|
||||
pc.register(plugin.key ?? `${Math.random()}`, plugin.default as Plugin)
|
||||
} else {
|
||||
if (checkComponentPlugin(plugin.default) === false) {
|
||||
throw('插件不合法')
|
||||
}
|
||||
pc.registerComponent(plugin.default as registerComponentOption)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
hooks.globalAlertTip('导入外部插件失败', {
|
||||
type: 'error',
|
||||
timeout: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
:root
|
||||
body {
|
||||
background-color: aliceblue;
|
||||
}
|
||||
+3
-1
@@ -1,5 +1,6 @@
|
||||
import PluginCenter from "@/class/PluginCenter";
|
||||
import { VirtualPages } from "@/class/VirtualPage";
|
||||
import VirtualDirectory from "@/class/VirtualDirectory";
|
||||
import type { VirtualPages } from "@/class/VirtualPage";
|
||||
|
||||
export type stats = {
|
||||
atimeMs: number; // 上次访问时间(毫秒)
|
||||
@@ -41,6 +42,7 @@ export interface usePluginHooksType {
|
||||
globalAlertTip: alertTipType;
|
||||
getViews: () => VirtualPages;
|
||||
getPluginCenter: () => PluginCenter;
|
||||
getRootVDirectory: () => VirtualDirectory;
|
||||
}
|
||||
|
||||
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
|
||||
+2
-34
@@ -19,42 +19,10 @@ export default defineConfig({
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/get': {
|
||||
'^/(get|upload|delete|query|rename|cut|mkdir)': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/get/, '/get')
|
||||
},
|
||||
|
||||
'/upload': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/upload/, '/upload')
|
||||
},
|
||||
|
||||
'/delete': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/delete/, '/delete')
|
||||
},
|
||||
'/query': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/query/, '/query')
|
||||
},
|
||||
'/rename': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/rename/, '/rename')
|
||||
},
|
||||
'/cut': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/cut/, '/cut')
|
||||
},
|
||||
'/mkdir': {
|
||||
target: 'http://127.0.0.1:17705',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/mkdir/, '/mkdir')
|
||||
rewrite: (path) => path
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user