refactor(vfs): 重构VFS模块,拆分数据访问逻辑与路径解析逻辑

将原先的 `vfs.go` 文件中的功能进行拆分,创建了独立的 DAO 层文件 `vfs_dao.go`
和路径处理文件 `vfs_path.go`,以提升代码结构清晰度和可维护性。

- 将数据库操作相关方法迁移至 `VfsDAO` 结构体中
- 新增 `vfs_dao.go` 文件用于管理底层数据访问对象
- 新增 `vfs_path.go` 文件专门处理路径解析逻辑
- 移除了原 `vfs.go` 中的数据库初始化、用户及节点操作等冗余代码
This commit is contained in:
zzy
2025-09-29 00:42:45 +08:00
parent 429a863b76
commit 35e79e54f1
13 changed files with 1106 additions and 1005 deletions

View File

@ -0,0 +1,396 @@
package vfs_service
import (
"fmt"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
)
type VfsCoreService struct {
vfs *models.VfsDAO
}
type VfsCallback func(this any, node *models.VfsNode, input []byte) ([]byte, error)
func NewVfsCoreService(vfs *models.VfsDAO) *VfsCoreService {
return &VfsCoreService{vfs: vfs}
}
type CreateVFSNodeResult struct {
Node *models.VfsNode
Content []byte // 回调处理后的结果
}
func (s *VfsCoreService) CreateVFSNode(path string, content []byte, callback VfsCallback, thisArg any) (*CreateVFSNodeResult, *VFSError) {
// 解析路径组件
parentPath, nodeName, nodeType, err := models.ParsePathComponents(path)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeInvalidPath,
Error: err,
}
}
parentNode, err := s.vfs.GetNodeByPath(parentPath)
if err != nil {
return nil, &VFSError{
Type: ErrorTypePathNotFound,
Error: err,
}
}
node := models.VfsNode{
Name: nodeName,
ParentID: parentNode.ID,
Type: nodeType,
}
if err := s.vfs.CreateNode(node); err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeCreationFailed,
Error: err,
}
}
// 获取创建后的完整节点信息
createdNode, err := s.vfs.GetNodeByParentIDAndName(parentNode.ID, nodeName)
if err != nil {
// 回滚
s.vfs.DeleteNode(node.ID)
return nil, &VFSError{
Type: ErrorTypeNodeCreationFailed,
Error: err,
}
}
// 执行回调处理
var resultContent []byte
if callback != nil && createdNode.Type == models.VfsNodeTypeService {
ret, err := callback(thisArg, createdNode, content)
if err != nil {
// 回滚操作
s.vfs.DeleteNode(createdNode.ID)
return nil, &VFSError{
Type: ErrorTypeServiceProxyFailed,
Error: err,
}
}
resultContent = ret
}
return &CreateVFSNodeResult{
Node: createdNode,
Content: resultContent,
}, nil
}
func (s *VfsCoreService) DeleteVFSNodeRecursively(path string, callback VfsCallback, thisArg any) (*models.VfsNode, *VFSError) {
// 获取节点
node, err := s.vfs.GetNodeByPath(path)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeNotFound,
Error: err,
}
}
// 递归删除节点
if err := s.deleteNodeRecursively(node, callback, thisArg); err != nil {
return nil, err
}
return node, nil
}
// deleteNodeRecursively 递归删除节点及其所有子节点
func (s *VfsCoreService) deleteNodeRecursively(node *models.VfsNode, callback VfsCallback, thisArg any) *VFSError {
// 如果是目录,先递归删除所有子节点
if node.Type == models.VfsNodeTypeDirectory {
// 获取所有子节点
children, err := s.vfs.GetChildren(node.ID)
if err != nil {
return &VFSError{
Type: ErrorTypeInternal,
Error: fmt.Errorf("failed to get directory children: %v", err),
}
}
// 递归删除每个子节点
for _, childEntry := range children {
// 根据子条目获取完整节点信息
childNode, err := s.vfs.GetNodeByParentIDAndName(node.ID, childEntry.Name)
if err != nil {
return &VFSError{
Type: ErrorTypeNodeNotFound,
Error: fmt.Errorf("failed to get child node %s: %v", childEntry.Name, err),
}
}
// 递归删除子节点
if err := s.deleteNodeRecursively(childNode, callback, thisArg); err != nil {
return err
}
}
} else if node.Type == models.VfsNodeTypeService {
// 对于服务节点,执行回调
if callback != nil {
_, err := callback(thisArg, node, nil)
if err != nil {
return &VFSError{
Type: ErrorTypeServiceProxyFailed,
Error: fmt.Errorf("failed to execute callback for service %s: %v", node.Name, err),
}
}
}
}
// 删除当前节点
if err := s.vfs.DeleteNode(node.ID); err != nil {
return &VFSError{
Type: ErrorTypeNodeDeletionFailed,
Error: fmt.Errorf("failed to delete node %s: %v", node.Name, err),
}
}
return nil
}
func (s *VfsCoreService) DeleteVFSNode(path string, callback VfsCallback, thisArg any) (*models.VfsNode, *VFSError) {
// 获取节点
node, err := s.vfs.GetNodeByPath(path)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeNotFound,
Error: err,
}
}
// 根据节点类型进行不同处理
switch node.Type {
case models.VfsNodeTypeService:
if callback != nil {
_, err := callback(thisArg, node, nil)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeServiceProxyFailed,
Error: err,
}
}
}
case models.VfsNodeTypeDirectory:
// 检查目录是否为空
children, err := s.vfs.GetChildren(node.ID)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeInternal,
Error: fmt.Errorf("failed to get directory children: %v", err),
}
}
if len(children) != 0 {
return nil, &VFSError{
Type: ErrorTypeConflict,
Error: fmt.Errorf("directory is not empty"),
}
}
default:
return nil, &VFSError{
Type: ErrorTypeInvalidArgument,
Error: fmt.Errorf("node type not supported for deletion"),
}
}
// 执行实际的删除操作
if err := s.vfs.DeleteNode(node.ID); err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeDeletionFailed,
Error: fmt.Errorf("failed to delete node: %v", err),
}
}
// 成功删除返回204状态
return node, nil
}
// GetVFSNodeResult 获取节点的返回结果
type GetVFSNodeResult struct {
Node *models.VfsNode
Entries []models.VfsDirEntry
Content []byte
}
// GetVFSNode 获取VFS节点
func (s *VfsCoreService) GetVFSNode(path string, callback VfsCallback, thisArg any) (*GetVFSNodeResult, *VFSError) {
// 获取节点
node, err := s.vfs.GetNodeByPath(path)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeNotFound,
Error: err,
}
}
// 根据节点类型进行不同处理
switch node.Type {
case models.VfsNodeTypeDirectory:
// 处理目录类型
entries, err := s.vfs.GetChildren(node.ID)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeInternal,
Error: err,
}
}
return &GetVFSNodeResult{
Node: node,
Entries: entries,
}, nil
case models.VfsNodeTypeService:
// 处理服务类型
var resultContent []byte
if callback != nil {
ret, err := callback(thisArg, node, nil)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeServiceProxyFailed,
Error: err,
}
}
resultContent = ret
}
return &GetVFSNodeResult{
Node: node,
Content: resultContent,
}, nil
default:
return &GetVFSNodeResult{
Node: node,
}, nil
}
}
// UpdateOperation 更新操作类型
type UpdateOperation int
const (
UpdateOperationRename UpdateOperation = iota
UpdateOperationChange
UpdateOperationMove
UpdateOperationCopy
)
// UpdateVFSNode 更新VFS节点
func (s *VfsCoreService) UpdateVFSNode(path string, operation UpdateOperation, data []byte, callback VfsCallback, thisArg any) (*models.VfsNode, *VFSError) {
// 获取节点
node, err := s.vfs.GetNodeByPath(path)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeNotFound,
Error: err,
}
}
// 根据操作类型进行不同处理
switch operation {
case UpdateOperationRename:
// TODO:
// if err := s.vfs.CheckNameValid(string(data)); err != nil {
// return nil, &VFSError{
// Type: ErrorTypeBadRequest,
// Error: err,
// }
// }
// FIXME: 检查新名称是否合法
// 对于服务类型节点,可能需要保留特定后缀
// 更新节点名称
node.Name = string(data)
if err := s.vfs.UpdateNode(node); err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeUpdateFailed,
Error: fmt.Errorf("failed to rename node: %v", err),
}
}
case UpdateOperationChange:
// Change操作仅适用于文件和服务类型节点
if node.Type != models.VfsNodeTypeFile && node.Type != models.VfsNodeTypeService {
return nil, &VFSError{
Type: ErrorTypeBadRequest,
Error: fmt.Errorf("change operation is only supported for file and service nodes"),
}
}
if callback != nil && node.Type == models.VfsNodeTypeService {
_, err := callback(thisArg, node, data)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeServiceProxyFailed,
Error: fmt.Errorf("failed to proxy change to service: %v", err),
}
}
}
case UpdateOperationMove:
// FIXME: 需要添加权限控制
if len(data) == 0 {
return nil, &VFSError{
Type: ErrorTypeBadRequest,
Error: fmt.Errorf("target path cannot be empty"),
}
}
// 移动节点到新路径
parentPath, nodeName, nodeType, err := models.ParsePathComponents(string(data))
if err != nil {
return nil, &VFSError{
Type: ErrorTypeInvalidPath,
Error: err,
}
}
if nodeType != node.Type {
return nil, &VFSError{
Type: ErrorTypeInvalidArgument,
Error: fmt.Errorf("invalid path type"),
}
}
parentNode, err := s.vfs.GetNodeByPath(parentPath)
if err != nil {
return nil, &VFSError{
Type: ErrorTypePathNotFound,
Error: err,
}
}
sameNode, err := s.vfs.GetNodeByParentIDAndName(parentNode.ID, nodeName)
if sameNode != nil || err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeMoveFailed,
Error: err,
}
}
node.ParentID = parentNode.ID
if err := s.vfs.UpdateNode(node); err != nil {
return nil, &VFSError{
Type: ErrorTypeNodeMoveFailed,
Error: fmt.Errorf("failed to move node: %v", err),
}
}
default:
return nil, &VFSError{
Type: ErrorTypeBadRequest,
Error: fmt.Errorf("unsupported operation type"),
}
}
// 返回更新后的节点信息
return node, nil
}

View File

@ -0,0 +1,50 @@
package vfs_service
type VFSErrorType int
const (
ErrorTypeNoError = iota
// 通用错误类型
ErrorTypeNotFound
ErrorTypeAlreadyExists
ErrorTypeForbidden
ErrorTypeInternal
ErrorTypeBadRequest
ErrorTypeUnauthorized
ErrorTypeConflict
ErrorTypeNotImplemented
ErrorTypeInvalidArgument
// 用户相关错误
ErrorTypeUserNotFound
ErrorTypeUserAlreadyExists
ErrorTypeUserCreationFailed
ErrorTypeUserDeletionFailed
// 节点相关错误
ErrorTypeNodeNotFound
ErrorTypeNodeAlreadyExists
ErrorTypeNodeCreationFailed
ErrorTypeNodeDeletionFailed
ErrorTypeNodeUpdateFailed
ErrorTypeNodeMoveFailed
ErrorTypeNodeAccessDenied
// 权限相关错误
ErrorTypePermissionDenied
ErrorTypeInvalidToken
// 服务代理相关错误
ErrorTypeServiceProxyNotFound
ErrorTypeServiceProxyFailed
// 路径相关错误
ErrorTypeInvalidPath
ErrorTypePathNotFound
)
type VFSError struct {
Type VFSErrorType
Error error
}

View File

@ -0,0 +1,119 @@
package vfs_service
import (
"fmt"
"net/http"
"strings"
"sync"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
)
// ServiceProxy 服务代理接口
type ServiceProxy interface {
// Get 从后端服务获取数据
Get(servicePath string, node *models.VfsNode) ([]byte, error)
// Create 在后端服务创建资源
Create(servicePath string, node *models.VfsNode, data []byte) ([]byte, error) // 返回创建的资源ID
// Update 更新后端服务资源
Update(servicePath string, node *models.VfsNode, data []byte) error
// Delete 删除后端服务资源
Delete(servicePath string, node *models.VfsNode) error
// GetName 获取代理名称
GetName() string
}
// ProxyEntry 代理表条目
type ProxyEntry struct {
Name string
MatchExt string
Proxy ServiceProxy // 对应的代理实现
}
type ProxyService struct {
Proxies []*ProxyEntry
proxyMutex sync.RWMutex
}
func NewProxyService() *ProxyService {
return &ProxyService{
Proxies: make([]*ProxyEntry, 0),
proxyMutex: sync.RWMutex{},
}
}
// FindProxyByServiceName 根据服务节点名称查找对应的代理
func (s *ProxyService) findProxyByServiceName(serviceName string) ServiceProxy {
s.proxyMutex.RLock()
defer s.proxyMutex.RUnlock()
if serviceName == "" {
return nil
}
// 根据服务名称匹配前缀
for _, entry := range s.Proxies {
if entry.MatchExt == serviceName {
return entry.Proxy
}
}
return nil
}
func (s *ProxyService) RegisterProxy(entry *ProxyEntry) {
s.proxyMutex.Lock()
defer s.proxyMutex.Unlock()
s.Proxies = append(s.Proxies, entry)
}
func (s *ProxyService) StrictProxy2Service(method string, data []byte, node *models.VfsNode) ([]byte, error) {
if node.Type != models.VfsNodeTypeService {
return nil, fmt.Errorf("node is not a service")
}
exts := strings.Split(node.Name, ".")
var serviceName = exts[1]
// log.Println("Proxy2Service: ", serviceName)
// 查找对应的代理
proxy := s.findProxyByServiceName(serviceName)
if proxy == nil {
return nil, fmt.Errorf("service proxy not found for: %s", serviceName)
}
// 根据HTTP方法调用相应的代理方法
switch method {
case http.MethodGet:
result, err := proxy.Get(serviceName, node)
if err != nil {
return nil, fmt.Errorf("failed to get service data: %v", err)
}
return result, nil
case http.MethodPost:
// 读取请求体数据
result, err := proxy.Create(serviceName, node, data)
if err != nil {
return nil, fmt.Errorf("failed to create service resource: %v", err)
}
return result, nil
case http.MethodPut, http.MethodPatch:
// 读取请求体数据
err := proxy.Update(serviceName, node, data)
if err != nil {
return nil, fmt.Errorf("failed to update service resource: %v", err)
}
return nil, nil
case http.MethodDelete:
err := proxy.Delete(serviceName, node)
if err != nil {
return nil, fmt.Errorf("failed to delete service resource: %v", err)
}
return nil, nil
default:
return nil, fmt.Errorf("method not allowed")
}
}

View File

@ -0,0 +1,82 @@
package vfs_service
import (
"crypto/rand"
"fmt"
"log"
"time"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
"github.com/casbin/casbin/v2"
)
type UserService struct {
// vfs *models.VfsService
vfs *models.VfsDAO
enforcer *casbin.Enforcer
// errorHandler *ErrorHandler
}
func NewUserService(vfs *models.VfsDAO, enforcer *casbin.Enforcer) *UserService {
return &UserService{
vfs: vfs,
enforcer: enforcer,
}
}
func generateToken() string {
bytes := make([]byte, 16)
if _, err := rand.Read(bytes); err != nil {
// fallback to time-based token
return fmt.Sprintf("%x", time.Now().UnixNano())
}
return fmt.Sprintf("%x", bytes)
}
func (s *UserService) CreateUser(username string) (*string, *VFSError) {
token := generateToken()
// 创建用户
err := s.vfs.CreateUser(username, token)
if err != nil {
return nil, &VFSError{
Type: ErrorTypeUserCreationFailed,
Error: err,
}
}
// 为新用户添加角色
_, err = s.enforcer.AddRoleForUser(username, "user")
if err != nil {
log.Printf("Failed to add role for user %s: %v", username, err)
}
// 保存策略
s.enforcer.SavePolicy()
// 返回带有token的响应
return &token, nil
}
func (s *UserService) DeleteUser(username string) *VFSError {
// 删除用户
err := s.vfs.DeleteUser(username)
if err != nil {
return &VFSError{
Type: ErrorTypeUserDeletionFailed,
Error: err,
}
}
// 从权限系统中移除用户
// 移除用户的所有角色
_, err = s.enforcer.DeleteRolesForUser(username)
if err != nil {
log.Printf("Failed to delete roles for user %s: %v", username, err)
}
// 保存策略
s.enforcer.SavePolicy()
// 成功删除返回204状态
return nil
}

View File

@ -0,0 +1,183 @@
// internal/handlers/vfs_driver/vfs_bookmark.go
package vfsdriver
import (
"context"
"encoding/json"
"fmt"
"net/http"
api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/bookmarks_client"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
vfs_service "git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/services"
)
type VfsBookMarkService struct {
client *api.ClientWithResponses
token string
}
func NewVfsBookMarkService(serverURL string) (*vfs_service.ProxyEntry, error) {
client, err := api.NewClientWithResponses(serverURL)
if err != nil {
return nil, err
}
ret := vfs_service.ProxyEntry{
Name: "bookmark",
MatchExt: "bk",
Proxy: &VfsBookMarkService{
client: client,
token: "random_token",
},
}
return &ret, nil
}
// Create implements ServiceProxy.
func (v *VfsBookMarkService) Create(servicePath string, node *models.VfsNode, data []byte) ([]byte, error) {
ctx := context.Background()
// 解析传入的数据为 BookmarkRequest
var req api.BookmarkRequest
if err := json.Unmarshal(data, &req); err != nil {
return nil, err
}
// 调用 bookmark 服务创建书签
resp, err := v.client.CreateBookmarkWithResponse(ctx, int64(node.ID), req, func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-BookMark-Token", v.token)
return nil
})
if err != nil {
return nil, err
}
// 处理响应
if resp.JSON201 != nil {
data, err := json.Marshal(resp.JSON201)
if err != nil {
return nil, fmt.Errorf("marshal response error: %w", err)
}
return data, nil
}
// 处理错误情况
if resp.JSON400 != nil {
return nil, fmt.Errorf("bad request: %s", resp.JSON400.Message)
}
if resp.JSON500 != nil {
return nil, fmt.Errorf("server error: %s", resp.JSON500.Message)
}
return nil, fmt.Errorf("unknown error: %s %s", resp.HTTPResponse.Status, resp.Body)
}
// Delete implements ServiceProxy.
func (v *VfsBookMarkService) Delete(servicePath string, node *models.VfsNode) error {
ctx := context.Background()
// 调用 bookmark 服务删除书签
resp, err := v.client.DeleteBookmarkWithResponse(ctx, int64(node.ID), func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-BookMark-Token", v.token)
return nil
})
if err != nil {
return err
}
// 处理响应
if resp.StatusCode() == 204 {
return nil
}
// 处理错误情况
if resp.JSON404 != nil {
return fmt.Errorf("not found: %s", resp.JSON404.Message)
}
if resp.JSON500 != nil {
return fmt.Errorf("server error: %s", resp.JSON500.Message)
}
return fmt.Errorf("unknown error")
}
// Get implements ServiceProxy.
func (v *VfsBookMarkService) Get(servicePath string, node *models.VfsNode) ([]byte, error) {
ctx := context.Background()
// 调用 bookmark 服务获取书签
resp, err := v.client.GetBookmarkWithResponse(ctx, int64(node.ID), func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-BookMark-Token", v.token)
return nil
})
if err != nil {
return nil, err
}
// 处理响应
if resp.JSON200 != nil {
data, err := json.Marshal(resp.JSON200)
if err != nil {
return nil, fmt.Errorf("marshal response error: %w", err)
}
return data, nil
}
// 处理错误情况
if resp.JSON404 != nil {
return nil, fmt.Errorf("not found: %s", resp.JSON404.Message)
}
return nil, fmt.Errorf("unknown error")
}
// Update implements ServiceProxy.
func (v *VfsBookMarkService) Update(servicePath string, node *models.VfsNode, data []byte) error {
ctx := context.Background()
// 解析传入的数据为 BookmarkRequest
var req api.BookmarkRequest
if err := json.Unmarshal(data, &req); err != nil {
return err
}
// 调用 bookmark 服务更新书签
resp, err := v.client.UpdateBookmarkWithResponse(ctx, int64(node.ID), req, func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-BookMark-Token", v.token)
return nil
})
if err != nil {
return err
}
// 处理响应
if resp.JSON200 != nil {
return nil
}
// 处理错误情况
if resp.JSON400 != nil {
return fmt.Errorf("bad request: %s", resp.JSON400.Message)
}
if resp.JSON404 != nil {
return fmt.Errorf("not found: %s", resp.JSON404.Message)
}
if resp.JSON500 != nil {
return fmt.Errorf("server error: %s", resp.JSON500.Message)
}
return fmt.Errorf("unknown error")
}
// GetName implements ServiceProxy.
func (v *VfsBookMarkService) GetName() string {
return "bookmark"
}
var _ vfs_service.ServiceProxy = (*VfsBookMarkService)(nil)