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:
@ -2,21 +2,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type Vfs struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
type VfsNodeType int
|
||||
|
||||
const (
|
||||
@ -39,556 +29,3 @@ type VfsUser struct {
|
||||
Name string
|
||||
Token string
|
||||
}
|
||||
|
||||
type VfsDirEntry struct {
|
||||
ID uint64
|
||||
Name string
|
||||
Type VfsNodeType
|
||||
}
|
||||
|
||||
// NewVfs 创建新的 VFS 实例
|
||||
func NewVfs(dbPath string) (*Vfs, error) {
|
||||
db, err := sql.Open("sqlite3", dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS vfs_nodes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
parent_id INTEGER,
|
||||
type INTEGER NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(parent_id, name)
|
||||
)`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS vfs_users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = createInitialDirectories(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Vfs{DB: db}, nil
|
||||
}
|
||||
|
||||
// 创建初始目录结构
|
||||
func createInitialDirectories(db *sql.DB) error {
|
||||
var err error
|
||||
// 创建 /home 目录
|
||||
_, err = db.Exec(`
|
||||
INSERT OR IGNORE INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES ('home', 0, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
VfsNodeTypeDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建 /public 目录
|
||||
_, err = db.Exec(`
|
||||
INSERT OR IGNORE INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES ('public', 0, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
VfsNodeTypeDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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 (v *Vfs) CreateUser(username string) (string, error) {
|
||||
// 生成随机token
|
||||
token := generateToken()
|
||||
|
||||
// 检查用户是否已存在
|
||||
_, err := v.GetUserByName(username)
|
||||
if err == nil {
|
||||
return "", errors.New("user already exists")
|
||||
}
|
||||
|
||||
// 插入用户(不使用事务)
|
||||
_, err = v.DB.Exec("INSERT INTO vfs_users (name, token) VALUES (?, ?)", username, token)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 使用 defer 确保出错时能清理已创建的用户
|
||||
defer func() {
|
||||
if err != nil {
|
||||
v.DB.Exec("DELETE FROM vfs_users WHERE name = ? AND token = ?", username, token)
|
||||
}
|
||||
}()
|
||||
|
||||
// 确保 /home 目录存在
|
||||
homeDir, getHomeErr := v.GetNodeByPath("/home/")
|
||||
if getHomeErr != nil {
|
||||
// 如果 /home 不存在,创建它
|
||||
homeDir = &VfsNode{
|
||||
Name: "home",
|
||||
ParentID: 0,
|
||||
Type: VfsNodeTypeDirectory,
|
||||
}
|
||||
if createHomeErr := v.CreateVFSNode(*homeDir); createHomeErr != nil {
|
||||
err = createHomeErr
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// 创建用户目录 /home/username
|
||||
userDir := VfsNode{
|
||||
Name: username,
|
||||
ParentID: homeDir.ID,
|
||||
Type: VfsNodeTypeDirectory,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if createDirErr := v.CreateVFSNode(userDir); createDirErr != nil {
|
||||
err = createDirErr
|
||||
return "", err
|
||||
}
|
||||
|
||||
if userDir, getUserErr := v.GetNodeByParentIDAndName(homeDir.ID, username); getUserErr != nil {
|
||||
panic(getUserErr)
|
||||
} else {
|
||||
dotDir := VfsNode{
|
||||
Name: ".Recycle_Bin",
|
||||
ParentID: userDir.ID,
|
||||
Type: VfsNodeTypeDirectory,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if createDirErr := v.CreateVFSNode(dotDir); createDirErr != nil {
|
||||
err = createDirErr
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (v *Vfs) DeleteUser(username string) error {
|
||||
// TODO: 递归删除用户相关文件
|
||||
// 这里暂时只删除用户记录
|
||||
_, err := v.DB.Exec("DELETE FROM vfs_users WHERE name = ?", username)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *Vfs) GetUserByToken(token string) (*VfsUser, error) {
|
||||
user := &VfsUser{}
|
||||
err := v.DB.QueryRow("SELECT name, token FROM vfs_users WHERE token = ?", token).
|
||||
Scan(&user.Name, &user.Token)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (v *Vfs) GetUserByName(username string) (*VfsUser, error) {
|
||||
user := &VfsUser{}
|
||||
err := v.DB.QueryRow("SELECT name, token FROM vfs_users WHERE name = ?", username).
|
||||
Scan(&user.Name, &user.Token)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetChildrenID 获取目录下所有子项的 ID
|
||||
func (v *Vfs) GetChildren(parentID uint64) ([]VfsDirEntry, error) {
|
||||
rows, err := v.DB.Query("SELECT id, name, type FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var dirEntrys []VfsDirEntry
|
||||
for rows.Next() {
|
||||
var entry VfsDirEntry
|
||||
if err := rows.Scan(&entry.ID, &entry.Name, &entry.Type); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dirEntrys = append(dirEntrys, entry)
|
||||
}
|
||||
|
||||
return dirEntrys, nil
|
||||
}
|
||||
|
||||
func (v *Vfs) GetChildrenID(parentID uint64, recursive bool) (ids []uint64, services []uint64, err error) {
|
||||
if recursive {
|
||||
// 递归获取所有子项ID
|
||||
err := v.getChildrenIDRecursive(parentID, &ids, &services)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
// 只获取直接子项ID
|
||||
rows, err := v.DB.Query("SELECT id FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id uint64
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
|
||||
return ids, services, nil
|
||||
}
|
||||
|
||||
// DeleteNodeRecursively 递归删除节点及其所有子项
|
||||
func (v *Vfs) DeleteNodeRecursively(nodeID uint64) ([]uint64, error) {
|
||||
// 获取所有需要删除的ID(包括自己和所有子项)
|
||||
idsToDelete := []uint64{nodeID}
|
||||
|
||||
// 获取所有子项ID
|
||||
childIDs, sericeIDs, err := v.GetChildrenID(nodeID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idsToDelete = append(idsToDelete, childIDs...)
|
||||
|
||||
// 构建删除语句
|
||||
if len(idsToDelete) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 创建占位符
|
||||
placeholders := make([]string, len(idsToDelete))
|
||||
args := make([]any, len(idsToDelete))
|
||||
for i, id := range idsToDelete {
|
||||
placeholders[i] = "?"
|
||||
args[i] = id
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("DELETE FROM vfs_nodes WHERE id IN (%s)", strings.Join(placeholders, ","))
|
||||
|
||||
_, err = v.DB.Exec(query, args...)
|
||||
return sericeIDs, err
|
||||
}
|
||||
|
||||
// getChildrenIDRecursive 递归获取所有子项ID的辅助函数
|
||||
func (v *Vfs) getChildrenIDRecursive(parentID uint64, ids *[]uint64, services *[]uint64) error {
|
||||
// 获取当前层级的子项
|
||||
rows, err := v.DB.Query("SELECT id, type FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id uint64
|
||||
var nodeType VfsNodeType
|
||||
if err := rows.Scan(&id, &nodeType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 将当前节点ID添加到列表中
|
||||
*ids = append(*ids, id)
|
||||
|
||||
// 如果是目录,递归获取其子项
|
||||
switch nodeType {
|
||||
case VfsNodeTypeDirectory:
|
||||
err := v.getChildrenIDRecursive(id, ids, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case VfsNodeTypeService:
|
||||
*services = append(*services, id)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetParentID 根据父路径查找父节点 ID
|
||||
// parentPath 应该是 ParsePathComponents 的第一个返回值
|
||||
func (v *Vfs) GetParentID(parentPath string) (uint64, error) {
|
||||
// 根目录特殊处理
|
||||
if parentPath == "/" || parentPath == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 递归查找父路径ID
|
||||
// 先解析父路径的父路径和节点名
|
||||
grandParentPath, parentName, _, err := ParsePathComponents(parentPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 递归获取祖父节点ID
|
||||
grandParentID, err := v.GetParentID(grandParentPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 在祖父节点下查找父节点
|
||||
var parentID uint64
|
||||
err = v.DB.QueryRow("SELECT id FROM vfs_nodes WHERE parent_id = ? AND name = ?",
|
||||
grandParentID, parentName).Scan(&parentID)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return 0, errors.New("parent path not found")
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return parentID, nil
|
||||
}
|
||||
|
||||
// GetNodeByPath 根据完整路径查找节点
|
||||
func (v *Vfs) GetNodeByPath(fullPath string) (*VfsNode, error) {
|
||||
// 根目录特殊处理
|
||||
if path.Clean(fullPath) == "/" {
|
||||
return &VfsNode{
|
||||
ID: 0,
|
||||
Name: "/",
|
||||
ParentID: 0,
|
||||
Type: VfsNodeTypeDirectory,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 使用 ParsePathComponents 解析路径
|
||||
parentPath, nodeName, nodeType, err := ParsePathComponents(fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取父节点ID
|
||||
parentID, err := v.GetParentID(parentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 根据 parentID, nodeName, nodeType 查找或创建节点
|
||||
node, err := v.GetNodeByParentIDAndName(parentID, nodeName)
|
||||
if err != nil {
|
||||
// 如果节点不存在,可以选择创建它或者返回错误
|
||||
// 这里根据你的需求决定是返回错误还是创建节点
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node.Type != nodeType {
|
||||
return nil, errors.New("node type mismatch")
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// GetNodeByParentIDAndName 根据父ID和名称查找节点
|
||||
func (v *Vfs) GetNodeByParentIDAndName(parentID uint64, name string) (*VfsNode, error) {
|
||||
node := &VfsNode{}
|
||||
err := v.DB.QueryRow(`
|
||||
SELECT id, name, parent_id, type, created_at, updated_at
|
||||
FROM vfs_nodes
|
||||
WHERE parent_id = ? AND name = ?`, parentID, name).Scan(
|
||||
&node.ID, &node.Name, &node.ParentID, &node.Type, &node.CreatedAt, &node.UpdatedAt)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("node not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// CreateNodeByComponents 根据路径组件创建节点
|
||||
func (v *Vfs) CreateNodeByComponents(parentPath, nodeName string, nodeType VfsNodeType) (*VfsNode, error) {
|
||||
// 获取父节点ID
|
||||
parentID, err := v.GetParentID(parentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建新节点
|
||||
node := &VfsNode{
|
||||
Name: nodeName,
|
||||
ParentID: parentID,
|
||||
Type: nodeType,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
// 保存到数据库
|
||||
result, err := v.DB.Exec(`
|
||||
INSERT INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
node.Name, node.ParentID, node.Type, node.CreatedAt, node.UpdatedAt)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取插入的ID
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node.ID = uint64(id)
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func ParsePathComponents(pathStr string) (parentPath, nodeName string, nodeType VfsNodeType, err error) {
|
||||
// FIXME: 路径判断以及update的类型判断
|
||||
abspath := path.Clean(pathStr)
|
||||
if !path.IsAbs(abspath) {
|
||||
return "", "", 0, errors.New("path must be absolute")
|
||||
}
|
||||
|
||||
// 特殊处理根路径
|
||||
if abspath == "/" {
|
||||
return "", "", VfsNodeTypeDirectory, nil
|
||||
}
|
||||
|
||||
// 判断是文件还是目录
|
||||
nodeType = VfsNodeTypeFile
|
||||
// 如果原始路径以 / 结尾,则为目录
|
||||
if len(pathStr) > 1 && pathStr[len(pathStr)-1] == '/' {
|
||||
nodeType = VfsNodeTypeDirectory
|
||||
}
|
||||
if nodeType == VfsNodeTypeFile && path.Ext(pathStr) == ".api" {
|
||||
nodeType = VfsNodeTypeService
|
||||
}
|
||||
|
||||
// 分割路径
|
||||
parentPath, nodeName = path.Split(abspath)
|
||||
|
||||
// 清理父路径
|
||||
if parentPath != "/" && parentPath != "" {
|
||||
parentPath = path.Clean(parentPath)
|
||||
}
|
||||
|
||||
// 处理特殊情况
|
||||
if parentPath == "." {
|
||||
parentPath = "/"
|
||||
}
|
||||
|
||||
return parentPath, nodeName, nodeType, nil
|
||||
}
|
||||
|
||||
// MoveToPath 将节点移动到指定路径
|
||||
func (v *Vfs) MoveToPath(node *VfsNode, destPath string) error {
|
||||
// FIXME: 路径和权限的检查
|
||||
// 1. 解析目标路径
|
||||
parentPath, nodeName, _, err := ParsePathComponents(destPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid destination path: %w", err)
|
||||
}
|
||||
|
||||
// 2. 查找目标父节点
|
||||
parentID, err := v.GetParentID(parentPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find parent directory '%s': %w", parentPath, err)
|
||||
}
|
||||
|
||||
// 3. 检查目标位置是否已存在同名节点
|
||||
_, err = v.GetNodeByParentIDAndName(parentID, nodeName)
|
||||
if err == nil {
|
||||
return fmt.Errorf("destination path '%s' already exists", destPath)
|
||||
}
|
||||
if err.Error() != "node not found" {
|
||||
return fmt.Errorf("error checking destination path: %w", err)
|
||||
}
|
||||
|
||||
// 4. 更新节点的父节点ID和名称
|
||||
node.ParentID = parentID
|
||||
node.Name = nodeName
|
||||
node.UpdatedAt = time.Now()
|
||||
|
||||
// 5. 更新数据库中的节点信息
|
||||
_, err = v.DB.Exec(`
|
||||
UPDATE vfs_nodes
|
||||
SET name = ?, parent_id = ?, updated_at = ?
|
||||
WHERE id = ?`,
|
||||
node.Name, node.ParentID, node.UpdatedAt, node.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update node: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Vfs) CheckNameValid(name string) error {
|
||||
if name == "" || strings.Contains(name, "/") {
|
||||
return fmt.Errorf("invalid node name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Vfs) CreateVFSNode(p VfsNode) error {
|
||||
_, err := v.DB.Exec(`
|
||||
INSERT INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
p.Name, p.ParentID, p.Type, time.Now(), time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *Vfs) DeleteVFSNode(p *VfsNode) error {
|
||||
_, err := v.DB.Exec("DELETE FROM vfs_nodes WHERE id = ?", p.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *Vfs) GetVFSNode(ID uint64) *VfsNode {
|
||||
node := &VfsNode{}
|
||||
err := v.DB.QueryRow(`
|
||||
SELECT id, name, parent_id, type, created_at, updated_at
|
||||
FROM vfs_nodes
|
||||
WHERE id = ?`, ID).Scan(
|
||||
&node.ID, &node.Name, &node.ParentID, &node.Type, &node.CreatedAt, &node.UpdatedAt)
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func (v *Vfs) UpdateVFSNode(p *VfsNode) error {
|
||||
_, err := v.DB.Exec(`
|
||||
UPDATE vfs_nodes
|
||||
SET name = ?, parent_id = ?, type = ?, updated_at = ?
|
||||
WHERE id = ?`,
|
||||
p.Name, p.ParentID, p.Type, time.Now(), p.ID)
|
||||
return err
|
||||
}
|
||||
|
336
internal/vfs/models/vfs_dao.go
Normal file
336
internal/vfs/models/vfs_dao.go
Normal file
@ -0,0 +1,336 @@
|
||||
// models/vfs_dao.go - 数据访问对象
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// VfsDAO 处理底层数据库操作
|
||||
type VfsDAO struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
type VfsDirEntry struct {
|
||||
ID uint64
|
||||
Name string
|
||||
Type VfsNodeType
|
||||
}
|
||||
|
||||
func NewVfsDAO(dbPath string) (*VfsDAO, error) {
|
||||
db, err := sql.Open("sqlite3", dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS vfs_nodes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
parent_id INTEGER,
|
||||
type INTEGER NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(parent_id, name)
|
||||
)`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS vfs_users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vfsdao := VfsDAO{DB: db}
|
||||
err = vfsdao.createInitialDirectories()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &vfsdao, nil
|
||||
}
|
||||
|
||||
// 创建初始目录结构
|
||||
func (dao *VfsDAO) createInitialDirectories() error {
|
||||
var err error
|
||||
// 创建 /home 目录
|
||||
_, err = dao.DB.Exec(`
|
||||
INSERT OR IGNORE INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES ('home', 0, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
VfsNodeTypeDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建 /public 目录
|
||||
_, err = dao.DB.Exec(`
|
||||
INSERT OR IGNORE INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES ('public', 0, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
VfsNodeTypeDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Node 相关操作
|
||||
func (dao *VfsDAO) CreateNode(node VfsNode) error {
|
||||
_, err := dao.DB.Exec(`
|
||||
INSERT INTO vfs_nodes (name, parent_id, type, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
node.Name, node.ParentID, node.Type, time.Now(), time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) UpdateNode(node *VfsNode) error {
|
||||
_, err := dao.DB.Exec(`
|
||||
UPDATE vfs_nodes
|
||||
SET name = ?, parent_id = ?, type = ?, updated_at = ?
|
||||
WHERE id = ?`,
|
||||
node.Name, node.ParentID, node.Type, time.Now(), node.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) DeleteNode(id uint64) error {
|
||||
_, err := dao.DB.Exec("DELETE FROM vfs_nodes WHERE id = ?", id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) GetNodeByID(id uint64) (*VfsNode, error) {
|
||||
node := &VfsNode{}
|
||||
err := dao.DB.QueryRow(`
|
||||
SELECT id, name, parent_id, type, created_at, updated_at
|
||||
FROM vfs_nodes
|
||||
WHERE id = ?`, id).Scan(
|
||||
&node.ID, &node.Name, &node.ParentID, &node.Type, &node.CreatedAt, &node.UpdatedAt)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("node not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) GetNodeByParentIDAndName(parentID uint64, name string) (*VfsNode, error) {
|
||||
node := &VfsNode{}
|
||||
err := dao.DB.QueryRow(`
|
||||
SELECT id, name, parent_id, type, created_at, updated_at
|
||||
FROM vfs_nodes
|
||||
WHERE parent_id = ? AND name = ?`, parentID, name).Scan(
|
||||
&node.ID, &node.Name, &node.ParentID, &node.Type, &node.CreatedAt, &node.UpdatedAt)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// GetParentID 根据父路径查找父节点 ID
|
||||
// parentPath 应该是 ParsePathComponents 的第一个返回值
|
||||
func (dao *VfsDAO) GetNodeByPath(parentPath string) (*VfsNode, error) {
|
||||
// log.Printf("GetNodeByPath: %s", parentPath)
|
||||
// 根目录特殊处理
|
||||
if parentPath == "/" || parentPath == "" {
|
||||
return &VfsNode{
|
||||
ID: 0,
|
||||
Name: "Root",
|
||||
ParentID: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 递归查找父路径ID
|
||||
// 先解析父路径的父路径和节点名
|
||||
grandParentPath, parentName, _, err := ParsePathComponents(parentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 递归获取祖父节点ID
|
||||
grandParentNode, err := dao.GetNodeByPath(grandParentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 在祖父节点下查找父节点
|
||||
var parentID uint64
|
||||
err = dao.DB.QueryRow("SELECT id FROM vfs_nodes WHERE parent_id = ? AND name = ?",
|
||||
grandParentNode.ID, parentName).Scan(&parentID)
|
||||
// log.Printf("parentID: %+v, %+v, %+v", grandParentNode, parentName, parentID)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("parent path not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dao.GetNodeByID(parentID)
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) GetChildren(parentID uint64) ([]VfsDirEntry, error) {
|
||||
rows, err := dao.DB.Query("SELECT id, name, type FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var dirEntries []VfsDirEntry
|
||||
for rows.Next() {
|
||||
var entry VfsDirEntry
|
||||
if err := rows.Scan(&entry.ID, &entry.Name, &entry.Type); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dirEntries = append(dirEntries, entry)
|
||||
}
|
||||
|
||||
return dirEntries, nil
|
||||
}
|
||||
|
||||
// 递归获取所有子项ID的辅助函数
|
||||
func (dao *VfsDAO) getChildrenIDRecursive(parentID uint64, ids *[]uint64, services *[]uint64) error {
|
||||
// 获取当前层级的子项
|
||||
rows, err := dao.DB.Query("SELECT id, type FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id uint64
|
||||
var nodeType VfsNodeType
|
||||
if err := rows.Scan(&id, &nodeType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 将当前节点ID添加到列表中
|
||||
*ids = append(*ids, id)
|
||||
|
||||
// 如果是目录,递归获取其子项
|
||||
switch nodeType {
|
||||
case VfsNodeTypeDirectory:
|
||||
err := dao.getChildrenIDRecursive(id, ids, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case VfsNodeTypeService:
|
||||
*services = append(*services, id)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetChildrenID 获取目录下所有子项的 ID
|
||||
func (dao *VfsDAO) GetChildrenID(parentID uint64, recursive bool) (ids []uint64, services []uint64, err error) {
|
||||
if recursive {
|
||||
// 递归获取所有子项ID
|
||||
err := dao.getChildrenIDRecursive(parentID, &ids, &services)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
// 只获取直接子项ID
|
||||
rows, err := dao.DB.Query("SELECT id FROM vfs_nodes WHERE parent_id = ?", parentID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id uint64
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
|
||||
return ids, services, nil
|
||||
}
|
||||
|
||||
// DeleteNodeRecursively 递归删除节点及其所有子项
|
||||
func (dao *VfsDAO) DeleteNodeRecursively(nodeID uint64) ([]uint64, error) {
|
||||
// 获取所有需要删除的ID(包括自己和所有子项)
|
||||
idsToDelete := []uint64{nodeID}
|
||||
|
||||
// 获取所有子项ID
|
||||
childIDs, serviceIDs, err := dao.GetChildrenID(nodeID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idsToDelete = append(idsToDelete, childIDs...)
|
||||
|
||||
// 构建删除语句
|
||||
if len(idsToDelete) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 创建占位符
|
||||
placeholders := make([]string, len(idsToDelete))
|
||||
args := make([]any, len(idsToDelete))
|
||||
for i, id := range idsToDelete {
|
||||
placeholders[i] = "?"
|
||||
args[i] = id
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("DELETE FROM vfs_nodes WHERE id IN (%s)", strings.Join(placeholders, ","))
|
||||
|
||||
_, err = dao.DB.Exec(query, args...)
|
||||
return serviceIDs, err
|
||||
}
|
||||
|
||||
// User 相关操作
|
||||
func (dao *VfsDAO) GetUserByToken(token string) (*VfsUser, error) {
|
||||
user := &VfsUser{}
|
||||
err := dao.DB.QueryRow("SELECT name, token FROM vfs_users WHERE token = ?", token).
|
||||
Scan(&user.Name, &user.Token)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) GetUserByName(username string) (*VfsUser, error) {
|
||||
user := &VfsUser{}
|
||||
err := dao.DB.QueryRow("SELECT name, token FROM vfs_users WHERE name = ?", username).
|
||||
Scan(&user.Name, &user.Token)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) CreateUser(username, token string) error {
|
||||
_, err := dao.DB.Exec("INSERT INTO vfs_users (name, token) VALUES (?, ?)", username, token)
|
||||
return err
|
||||
}
|
||||
|
||||
func (dao *VfsDAO) DeleteUser(username string) error {
|
||||
_, err := dao.DB.Exec("DELETE FROM vfs_users WHERE name = ?", username)
|
||||
return err
|
||||
}
|
44
internal/vfs/models/vfs_path.go
Normal file
44
internal/vfs/models/vfs_path.go
Normal file
@ -0,0 +1,44 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path"
|
||||
)
|
||||
|
||||
func ParsePathComponents(pathStr string) (parentPath, nodeName string, nodeType VfsNodeType, err error) {
|
||||
// FIXME: 路径判断以及update的类型判断
|
||||
abspath := path.Clean(pathStr)
|
||||
if !path.IsAbs(abspath) {
|
||||
return "", "", 0, errors.New("path must be absolute")
|
||||
}
|
||||
|
||||
// 特殊处理根路径
|
||||
if abspath == "/" {
|
||||
return "", "", VfsNodeTypeDirectory, nil
|
||||
}
|
||||
|
||||
// 判断是文件还是目录
|
||||
nodeType = VfsNodeTypeFile
|
||||
// 如果原始路径以 / 结尾,则为目录
|
||||
if len(pathStr) > 1 && pathStr[len(pathStr)-1] == '/' {
|
||||
nodeType = VfsNodeTypeDirectory
|
||||
}
|
||||
if nodeType == VfsNodeTypeFile && path.Ext(pathStr) == ".api" {
|
||||
nodeType = VfsNodeTypeService
|
||||
}
|
||||
|
||||
// 分割路径
|
||||
parentPath, nodeName = path.Split(abspath)
|
||||
|
||||
// 清理父路径
|
||||
if parentPath != "/" && parentPath != "" {
|
||||
parentPath = path.Clean(parentPath)
|
||||
}
|
||||
|
||||
// 处理特殊情况
|
||||
if parentPath == "." {
|
||||
parentPath = "/"
|
||||
}
|
||||
|
||||
return parentPath, nodeName, nodeType, nil
|
||||
}
|
396
internal/vfs/services/vfs_core.go
Normal file
396
internal/vfs/services/vfs_core.go
Normal 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
|
||||
}
|
50
internal/vfs/services/vfs_error.go
Normal file
50
internal/vfs/services/vfs_error.go
Normal 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
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
package vfs
|
||||
package vfs_service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
|
||||
)
|
||||
@ -33,17 +34,29 @@ type ProxyEntry struct {
|
||||
Proxy ServiceProxy // 对应的代理实现
|
||||
}
|
||||
|
||||
type ProxyService struct {
|
||||
Proxies []*ProxyEntry
|
||||
proxyMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func NewProxyService() *ProxyService {
|
||||
return &ProxyService{
|
||||
Proxies: make([]*ProxyEntry, 0),
|
||||
proxyMutex: sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
// FindProxyByServiceName 根据服务节点名称查找对应的代理
|
||||
func (v *VfsImpl) FindProxyByServiceName(serviceName string) ServiceProxy {
|
||||
v.proxyMutex.RLock()
|
||||
defer v.proxyMutex.RUnlock()
|
||||
func (s *ProxyService) findProxyByServiceName(serviceName string) ServiceProxy {
|
||||
s.proxyMutex.RLock()
|
||||
defer s.proxyMutex.RUnlock()
|
||||
|
||||
if serviceName == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据服务名称匹配前缀
|
||||
for _, entry := range v.proxyTable {
|
||||
for _, entry := range s.Proxies {
|
||||
if entry.MatchExt == serviceName {
|
||||
return entry.Proxy
|
||||
}
|
||||
@ -52,19 +65,22 @@ func (v *VfsImpl) FindProxyByServiceName(serviceName string) ServiceProxy {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VfsImpl) RegisterProxy(entry *ProxyEntry) {
|
||||
v.proxyMutex.Lock()
|
||||
defer v.proxyMutex.Unlock()
|
||||
func (s *ProxyService) RegisterProxy(entry *ProxyEntry) {
|
||||
s.proxyMutex.Lock()
|
||||
defer s.proxyMutex.Unlock()
|
||||
|
||||
v.proxyTable = append(v.proxyTable, entry)
|
||||
s.Proxies = append(s.Proxies, entry)
|
||||
}
|
||||
|
||||
func (v *VfsImpl) StrictProxy2Service(method string, data []byte, node *models.VfsNode) ([]byte, error) {
|
||||
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 := v.FindProxyByServiceName(serviceName)
|
||||
proxy := s.findProxyByServiceName(serviceName)
|
||||
if proxy == nil {
|
||||
return nil, fmt.Errorf("service proxy not found for: %s", serviceName)
|
||||
}
|
82
internal/vfs/services/vfs_user.go
Normal file
82
internal/vfs/services/vfs_user.go
Normal 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
|
||||
}
|
@ -9,8 +9,8 @@ import (
|
||||
"net/http"
|
||||
|
||||
api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/bookmarks_client"
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs"
|
||||
"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 {
|
||||
@ -18,13 +18,13 @@ type VfsBookMarkService struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func NewVfsBookMarkService(serverURL string) (*vfs.ProxyEntry, error) {
|
||||
func NewVfsBookMarkService(serverURL string) (*vfs_service.ProxyEntry, error) {
|
||||
client, err := api.NewClientWithResponses(serverURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := vfs.ProxyEntry{
|
||||
ret := vfs_service.ProxyEntry{
|
||||
Name: "bookmark",
|
||||
MatchExt: "bk",
|
||||
Proxy: &VfsBookMarkService{
|
||||
@ -180,4 +180,4 @@ func (v *VfsBookMarkService) GetName() string {
|
||||
return "bookmark"
|
||||
}
|
||||
|
||||
var _ vfs.ServiceProxy = (*VfsBookMarkService)(nil)
|
||||
var _ vfs_service.ServiceProxy = (*VfsBookMarkService)(nil)
|
@ -4,27 +4,28 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
|
||||
vfs_service "git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/services"
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
fileadapter "github.com/casbin/casbin/v2/persist/file-adapter"
|
||||
)
|
||||
|
||||
type VfsImpl struct {
|
||||
vfs *models.Vfs
|
||||
enfocer *casbin.Enforcer
|
||||
config VFSConfig
|
||||
proxyTable []*ProxyEntry // 动态代理表
|
||||
proxyMutex sync.RWMutex // 保护代理表的读写锁
|
||||
Core *vfs_service.VfsCoreService
|
||||
Proxy *vfs_service.ProxyService
|
||||
User *vfs_service.UserService
|
||||
DAO *models.VfsDAO
|
||||
Enfocer *casbin.Enforcer
|
||||
Config VFSConfig
|
||||
}
|
||||
|
||||
// 在NewVfsHandler中注册中间件
|
||||
func NewVfsHandler(config *Config) (*VfsImpl, error) {
|
||||
var err error
|
||||
|
||||
vfs, err := models.NewVfs(config.VFS.DbPath)
|
||||
dao, err := models.NewVfsDAO(config.VFS.DbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -67,11 +68,12 @@ func NewVfsHandler(config *Config) (*VfsImpl, error) {
|
||||
log.Printf("Register Token: %s", config.VFS.RegisterToken)
|
||||
|
||||
impl := &VfsImpl{
|
||||
vfs: vfs,
|
||||
enfocer: e,
|
||||
config: config.VFS,
|
||||
proxyTable: make([]*ProxyEntry, 0),
|
||||
proxyMutex: sync.RWMutex{},
|
||||
Core: vfs_service.NewVfsCoreService(dao),
|
||||
Proxy: vfs_service.NewProxyService(),
|
||||
User: vfs_service.NewUserService(dao, e),
|
||||
DAO: dao,
|
||||
Enfocer: e,
|
||||
Config: config.VFS,
|
||||
}
|
||||
|
||||
// 注册中间件
|
||||
|
@ -30,7 +30,7 @@ func (v *VfsImpl) PermissionMiddleware(handler api.StrictHandlerFunc, operation
|
||||
token := ctx.GetHeader("X-VFS-Token")
|
||||
|
||||
// Admin token 拥有所有权限
|
||||
if token == v.config.AdminToken && len(token) != 0 {
|
||||
if token == v.Config.AdminToken && len(token) != 0 {
|
||||
return handler(ctx, request)
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ func (v *VfsImpl) PermissionMiddleware(handler api.StrictHandlerFunc, operation
|
||||
switch operation {
|
||||
case "CreateUser":
|
||||
// 只有admin或register token可以创建用户
|
||||
if token != v.config.RegisterToken {
|
||||
if token != v.Config.RegisterToken {
|
||||
return api.CreateUser403JSONResponse{
|
||||
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeForbidden,
|
||||
@ -57,8 +57,8 @@ func (v *VfsImpl) PermissionMiddleware(handler api.StrictHandlerFunc, operation
|
||||
}
|
||||
|
||||
// 验证token对应的用户是否存在
|
||||
user, err := v.vfs.GetUserByToken(token)
|
||||
if err != nil || (user.Name != username && token != v.config.AdminToken) {
|
||||
user, err := v.DAO.GetUserByToken(token)
|
||||
if err != nil || (user.Name != username && token != v.Config.AdminToken) {
|
||||
return api.DeleteUser403JSONResponse{
|
||||
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeForbidden,
|
||||
@ -155,12 +155,12 @@ func (v *VfsImpl) PermissionMiddleware(handler api.StrictHandlerFunc, operation
|
||||
// FIXME: using casbin to check it
|
||||
func (v *VfsImpl) CheckPermission(token, path, method string) (bool, error) {
|
||||
// Admin token 拥有所有权限
|
||||
if token == v.config.AdminToken && len(token) != 0 {
|
||||
if token == v.Config.AdminToken && len(token) != 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 根据 token 获取用户信息
|
||||
user, err := v.vfs.GetUserByToken(token)
|
||||
user, err := v.DAO.GetUserByToken(token)
|
||||
if err != nil {
|
||||
// 匿名用户
|
||||
user = &models.VfsUser{Name: "", Token: ""}
|
||||
@ -180,7 +180,7 @@ func (v *VfsImpl) CheckPermission(token, path, method string) (bool, error) {
|
||||
// sub: 用户名 (匿名用户为空字符串)
|
||||
// obj: 路径
|
||||
// act: HTTP方法
|
||||
allowed, err := v.enfocer.Enforce(user.Name, path, method)
|
||||
allowed, err := v.Enfocer.Enforce(user.Name, path, method)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -8,61 +8,40 @@ import (
|
||||
|
||||
api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/vfs_server"
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
|
||||
vfs_service "git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/services"
|
||||
)
|
||||
|
||||
// TODO 重命名名称冲突,以及合法名称检测,以及JSONBody and TextBody的检测
|
||||
// TODO: 特殊字符过滤
|
||||
|
||||
// CreateVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) CreateVFSNode(ctx context.Context, request api.CreateVFSNodeRequestObject) (api.CreateVFSNodeResponseObject, error) {
|
||||
// 解析路径组件
|
||||
parentPath, nodeName, nodeType, err := models.ParsePathComponents(request.Params.Path)
|
||||
if err != nil {
|
||||
return api.CreateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
var content []byte
|
||||
if request.Body != nil {
|
||||
content = []byte(*request.Body)
|
||||
}
|
||||
res, err := v.Core.CreateVFSNode(request.Params.Path, content, func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodPost, input, node)
|
||||
return result, err
|
||||
} else {
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
// 读取请求体数据
|
||||
// FIXME: 使用stream可能更好
|
||||
var content []byte = []byte(*request.Body)
|
||||
|
||||
// 创建节点 (可能需要传递content数据到vfs层)
|
||||
node, err := v.vfs.CreateNodeByComponents(parentPath, nodeName, nodeType)
|
||||
if err != nil {
|
||||
log.Printf("Error creating VFS node: %+v", err)
|
||||
return api.CreateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: err.Error(),
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 处理服务类型节点
|
||||
if nodeType == models.VfsNodeTypeService {
|
||||
// 这里可能需要将content传递给服务处理
|
||||
if result, err := v.StrictProxy2Service(http.MethodPost, content, node); err != nil {
|
||||
// 回滚操作
|
||||
delete_err := v.vfs.DeleteVFSNode(node)
|
||||
log.Printf("service node: %s, err %s", node.Name, err.Error())
|
||||
if delete_err != nil {
|
||||
// FIXME: 需要解决这种原子性
|
||||
return nil, fmt.Errorf("consistency error: %w", err)
|
||||
}
|
||||
return api.CreateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
// 返回二进制数据响应
|
||||
return api.CreateVFSNode201TextResponse(result), nil
|
||||
}
|
||||
}
|
||||
|
||||
node := res.Node
|
||||
// 返回JSON响应
|
||||
return api.CreateVFSNode201JSONResponse{
|
||||
Name: node.Name,
|
||||
@ -72,172 +51,97 @@ func (v *VfsImpl) CreateVFSNode(ctx context.Context, request api.CreateVFSNodeRe
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) DeleteVFSNode(ctx context.Context, request api.DeleteVFSNodeRequestObject) (api.DeleteVFSNodeResponseObject, error) {
|
||||
// 获取节点
|
||||
node, err := v.vfs.GetNodeByPath(request.Params.Path)
|
||||
// GetVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) GetVFSNode(ctx context.Context, request api.GetVFSNodeRequestObject) (api.GetVFSNodeResponseObject, error) {
|
||||
res, err := v.Core.GetVFSNode(request.Params.Path, func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodGet, nil, node)
|
||||
return result, err
|
||||
} else {
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
if err != nil {
|
||||
return api.DeleteVFSNode404JSONResponse{
|
||||
PathNotFoundErrorJSONResponse: api.PathNotFoundErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypePathNotFound,
|
||||
Message: err.Error(),
|
||||
return api.GetVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 根据节点类型进行不同处理
|
||||
switch node.Type {
|
||||
case models.VfsNodeTypeService:
|
||||
// 对于服务类型节点,通过代理删除
|
||||
_, err := v.StrictProxy2Service(http.MethodDelete, nil, node)
|
||||
if res.Node.Type == models.VfsNodeTypeDirectory {
|
||||
// 手动构造响应对象
|
||||
entries := make([]api.VFSDirectoryEntry, len(res.Entries))
|
||||
for i, entry := range res.Entries {
|
||||
entries[i] = api.VFSDirectoryEntry{
|
||||
Name: entry.Name,
|
||||
Type: ModelType2ResponseType(entry.Type),
|
||||
}
|
||||
}
|
||||
return api.GetVFSNode200JSONResponse(entries), nil
|
||||
} else {
|
||||
return api.GetVFSNode200TextResponse(res.Content), nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) DeleteVFSNode(ctx context.Context, request api.DeleteVFSNodeRequestObject) (api.DeleteVFSNodeResponseObject, error) {
|
||||
op := request.Params.Op
|
||||
if op == nil {
|
||||
_, err := v.Core.DeleteVFSNode(request.Params.Path, func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodDelete, nil, node)
|
||||
return result, err
|
||||
} else {
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
if err != nil {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: err.Error(),
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
case models.VfsNodeTypeDirectory:
|
||||
|
||||
if request.Params.Op != nil && *request.Params.Op == api.Recursive {
|
||||
if sericeIDs, err := v.vfs.DeleteNodeRecursively(node.ID); err != nil {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to delete node: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
// 成功删除返回204状态
|
||||
return api.DeleteVFSNode204Response{}, nil
|
||||
} else if *op == api.Recursive {
|
||||
_, err := v.Core.DeleteVFSNodeRecursively(request.Params.Path, func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodDelete, nil, node)
|
||||
return result, err
|
||||
} else {
|
||||
for _, serviceID := range sericeIDs {
|
||||
// 对于服务类型节点,通过代理删除
|
||||
_, err := v.StrictProxy2Service(http.MethodDelete, nil, v.vfs.GetVFSNode(serviceID))
|
||||
if err != nil {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return api.DeleteVFSNode204Response{}, nil
|
||||
}
|
||||
} else {
|
||||
// 检查目录是否为空
|
||||
children, err := v.vfs.GetChildren(node.ID)
|
||||
if err != nil {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to get directory children: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
if len(children) != 0 {
|
||||
return api.DeleteVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeConflictError,
|
||||
Message: "Directory is not empty",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
default:
|
||||
return api.DeleteVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Node type not supported for deletion",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 执行实际的删除操作
|
||||
if err := v.vfs.DeleteVFSNode(node); err != nil {
|
||||
// 成功删除返回204状态
|
||||
return api.DeleteVFSNode204Response{}, nil
|
||||
} else {
|
||||
return api.DeleteVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to delete node: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 成功删除返回204状态
|
||||
return api.DeleteVFSNode204Response{}, nil
|
||||
}
|
||||
|
||||
// GetVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) GetVFSNode(ctx context.Context, request api.GetVFSNodeRequestObject) (api.GetVFSNodeResponseObject, error) {
|
||||
// 获取节点
|
||||
node, err := v.vfs.GetNodeByPath(request.Params.Path)
|
||||
if err != nil {
|
||||
return api.GetVFSNode404JSONResponse{
|
||||
PathNotFoundErrorJSONResponse: api.PathNotFoundErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypePathNotFound,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
switch node.Type {
|
||||
case models.VfsNodeTypeDirectory:
|
||||
// 处理目录类型
|
||||
entries, err := v.vfs.GetChildren(node.ID)
|
||||
if err != nil {
|
||||
return api.GetVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var responseEntries []api.VFSDirectoryEntry
|
||||
for _, entry := range entries {
|
||||
responseEntries = append(responseEntries, api.VFSDirectoryEntry{
|
||||
Name: entry.Name,
|
||||
Type: ModelType2ResponseType(entry.Type),
|
||||
})
|
||||
}
|
||||
return api.GetVFSNode200JSONResponse(responseEntries), nil
|
||||
|
||||
// case models.VfsNodeTypeFile:
|
||||
// // 处理文件类型,返回二进制数据
|
||||
// // 这里需要从vfs中获取文件内容
|
||||
// fileContent, err := v.vfs.GetFileContent(node.ID) // 假设有此方法
|
||||
// if err != nil {
|
||||
// return api.GetVFSNode500JSONResponse{
|
||||
// ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
// Errtype: api.ErrorErrtypeInternalServerError,
|
||||
// Message: err.Error(),
|
||||
// },
|
||||
// }, nil
|
||||
// }
|
||||
// return api.GetVFSNode200ApplicationoctetStreamResponse{
|
||||
// Body: bytes.NewReader(fileContent),
|
||||
// ContentLength: int64(len(fileContent)),
|
||||
// }, nil
|
||||
|
||||
case models.VfsNodeTypeService:
|
||||
// 处理服务类型
|
||||
result, err := v.StrictProxy2Service(http.MethodGet, nil, node)
|
||||
if err != nil {
|
||||
return api.GetVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return api.GetVFSNode200TextResponse(result), nil
|
||||
|
||||
default:
|
||||
return api.GetVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Not a valid node type",
|
||||
Message: fmt.Errorf("not suported op").Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -245,172 +149,48 @@ func (v *VfsImpl) GetVFSNode(ctx context.Context, request api.GetVFSNodeRequestO
|
||||
|
||||
// UpdateVFSNode implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) UpdateVFSNode(ctx context.Context, request api.UpdateVFSNodeRequestObject) (api.UpdateVFSNodeResponseObject, error) {
|
||||
// 获取节点
|
||||
node, err := v.vfs.GetNodeByPath(request.Params.Path)
|
||||
if err != nil {
|
||||
return api.UpdateVFSNode404JSONResponse{
|
||||
PathNotFoundErrorJSONResponse: api.PathNotFoundErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypePathNotFound,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
var content []byte
|
||||
if request.JSONBody != nil {
|
||||
content = []byte(*request.JSONBody)
|
||||
} else if request.TextBody != nil {
|
||||
content = []byte(*request.TextBody)
|
||||
}
|
||||
|
||||
// 根据操作类型进行不同处理
|
||||
var op vfs_service.UpdateOperation
|
||||
switch request.Params.Op {
|
||||
case api.Rename:
|
||||
// 检查请求体
|
||||
if request.JSONBody == nil {
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Request body is required for rename operation",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
newName := string(*request.JSONBody)
|
||||
if err := v.vfs.CheckNameValid(newName); err != nil {
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FIXME: 检查新名称是否合法
|
||||
// 对于服务类型节点,可能需要保留特定后缀
|
||||
if node.Type == models.VfsNodeTypeService {
|
||||
// 可以添加对服务节点重命名的特殊处理
|
||||
// 例如确保保留.service后缀
|
||||
}
|
||||
|
||||
// 更新节点名称
|
||||
node.Name = newName
|
||||
if err := v.vfs.UpdateVFSNode(node); err != nil {
|
||||
return api.UpdateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to rename node: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
case api.Change:
|
||||
// Change操作仅适用于文件和服务类型节点
|
||||
if node.Type != models.VfsNodeTypeFile && node.Type != models.VfsNodeTypeService {
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Change operation is only supported for file and service nodes",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 读取请求体数据
|
||||
// FIXME: 使用stream可能更好
|
||||
var content []byte = []byte(*request.TextBody)
|
||||
|
||||
// 对于服务节点,通过代理发送变更
|
||||
if node.Type == models.VfsNodeTypeService {
|
||||
_, err := v.StrictProxy2Service(http.MethodPatch, content, node)
|
||||
if err != nil {
|
||||
return api.UpdateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: "Failed to proxy change to service: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
} else {
|
||||
// 对于文件节点,可能需要更新文件内容
|
||||
// 这里可以根据需要实现文件内容更新逻辑
|
||||
return api.UpdateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "File Opreation Not Supported",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
case api.Move:
|
||||
// FIXME: 需要添加权限控制
|
||||
if request.JSONBody == nil {
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Request body is required for move operation",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
targetPath := string(*request.JSONBody)
|
||||
if targetPath == "" {
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Target path cannot be empty",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 移动节点到新路径
|
||||
if err := v.vfs.MoveToPath(node, targetPath); err != nil {
|
||||
return api.UpdateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to move node: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
op = vfs_service.UpdateOperationChange
|
||||
case api.Copy:
|
||||
fallthrough
|
||||
// if request.Body == nil {
|
||||
// return api.UpdateVFSNode400JSONResponse{
|
||||
// ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
// Errtype: api.ErrorErrtypeParameterError,
|
||||
// Message: "Request body is required for copy operation",
|
||||
// },
|
||||
// }, nil
|
||||
// }
|
||||
op = vfs_service.UpdateOperationCopy
|
||||
case api.Move:
|
||||
op = vfs_service.UpdateOperationMove
|
||||
case api.Rename:
|
||||
op = vfs_service.UpdateOperationRename
|
||||
}
|
||||
res, err := v.Core.UpdateVFSNode(request.Params.Path, op, content, func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodPut, input, node)
|
||||
return result, err
|
||||
} else {
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
// targetPath := string(*request.Body)
|
||||
// if targetPath == "" {
|
||||
// return api.UpdateVFSNode400JSONResponse{
|
||||
// ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
// Errtype: api.ErrorErrtypeParameterError,
|
||||
// Message: "Target path cannot be empty",
|
||||
// },
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
// // 复制节点到新路径
|
||||
// if err := v.vfs.CopyToPath(node, targetPath); err != nil {
|
||||
// return api.UpdateVFSNode500JSONResponse{
|
||||
// ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
// Errtype: api.ErrorErrtypeInternalServerError,
|
||||
// Message: "Failed to copy node: " + err.Error(),
|
||||
// },
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
default:
|
||||
return api.UpdateVFSNode400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeParameterError,
|
||||
Message: "Unsupported operation type",
|
||||
if err != nil {
|
||||
return api.UpdateVFSNode500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 返回更新后的节点信息
|
||||
return api.UpdateVFSNode200JSONResponse{
|
||||
Name: node.Name,
|
||||
Type: ModelType2ResponseType(node.Type),
|
||||
CreatedAt: node.CreatedAt,
|
||||
UpdatedAt: node.UpdatedAt,
|
||||
Name: res.Name,
|
||||
Type: ModelType2ResponseType(res.Type),
|
||||
CreatedAt: res.CreatedAt,
|
||||
UpdatedAt: res.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -430,42 +210,23 @@ func ModelType2ResponseType(nodeType models.VfsNodeType) api.VFSNodeType {
|
||||
// CreateUser implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) CreateUser(ctx context.Context, request api.CreateUserRequestObject) (api.CreateUserResponseObject, error) {
|
||||
// 创建用户
|
||||
token, err := v.vfs.CreateUser(request.Username)
|
||||
if err != nil {
|
||||
// 检查是否是用户已存在的错误
|
||||
if err.Error() == "user already exists" {
|
||||
return api.CreateUser400JSONResponse{
|
||||
ParameterErrorJSONResponse: api.ParameterErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeConflictError,
|
||||
Message: "User already exists",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
token, err := v.User.CreateUser(request.Username)
|
||||
if err != nil || token == nil {
|
||||
return api.CreateUser500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to create user: " + err.Error(),
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 为新用户添加角色
|
||||
_, err = v.enfocer.AddRoleForUser(request.Username, "user")
|
||||
if err != nil {
|
||||
log.Printf("Failed to add role for user %s: %v", request.Username, err)
|
||||
// 注意:这里即使添加角色失败,我们也不会回滚用户创建
|
||||
// 因为用户创建已经成功,且这是两个独立的系统
|
||||
// FIXME: unknown
|
||||
}
|
||||
|
||||
// 保存策略
|
||||
v.enfocer.SavePolicy()
|
||||
v.Core.CreateVFSNode("/home/"+request.Username+"/", nil, nil, nil)
|
||||
v.Core.CreateVFSNode("/home/"+request.Username+"/.Recycle_Bin/", nil, nil, nil)
|
||||
|
||||
// 返回带有token的响应
|
||||
return api.CreateUser201Response{
|
||||
Headers: api.CreateUser201ResponseHeaders{
|
||||
XVFSToken: token,
|
||||
XVFSToken: *token,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -473,58 +234,36 @@ func (v *VfsImpl) CreateUser(ctx context.Context, request api.CreateUserRequestO
|
||||
// DeleteUser implements server.StrictServerInterface.
|
||||
func (v *VfsImpl) DeleteUser(ctx context.Context, request api.DeleteUserRequestObject) (api.DeleteUserResponseObject, error) {
|
||||
// 删除用户
|
||||
err := v.vfs.DeleteUser(request.Username)
|
||||
if err != nil {
|
||||
// 检查是否是用户未找到的错误
|
||||
if err.Error() == "user not found" {
|
||||
return api.DeleteUser404JSONResponse{
|
||||
Errtype: api.ErrorErrtypeNotFoundError,
|
||||
Message: "User not found",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if err := v.User.DeleteUser(request.Username); err != nil {
|
||||
return api.DeleteUser500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: "Failed to delete user: " + err.Error(),
|
||||
Message: err.Error.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if userDir, err := v.vfs.GetNodeByPath("/home/" + request.Username + "/"); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
if serviceIDs, err := v.vfs.DeleteNodeRecursively(userDir.ID); err != nil {
|
||||
panic(err)
|
||||
// TODO: Remove User DIR
|
||||
_, err := v.Core.DeleteVFSNodeRecursively("/home/"+request.Username+"/", func(this any, node *models.VfsNode, input []byte) ([]byte, error) {
|
||||
if svc, ok := this.(*vfs_service.ProxyService); ok {
|
||||
result, err := svc.StrictProxy2Service(http.MethodDelete, nil, node)
|
||||
return result, err
|
||||
} else {
|
||||
for _, serviceID := range serviceIDs {
|
||||
// 对于服务类型节点,通过代理删除
|
||||
_, err := v.StrictProxy2Service(http.MethodDelete, nil, v.vfs.GetVFSNode(serviceID))
|
||||
if err != nil {
|
||||
return api.DeleteUser500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeServiceProxyError,
|
||||
Message: err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
// 可选日志记录或错误处理
|
||||
log.Println("this is not of type ProxyService")
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
}, v.Proxy)
|
||||
|
||||
// 从权限系统中移除用户
|
||||
// 移除用户的所有角色
|
||||
_, err = v.enfocer.DeleteRolesForUser(request.Username)
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete roles for user %s: %v", request.Username, err)
|
||||
// 注意:这里即使删除角色失败,我们也不会回滚用户删除
|
||||
// 因为数据库中的用户已经删除,且这是两个独立的系统
|
||||
// FIXME: unknown
|
||||
return api.DeleteUser500JSONResponse{
|
||||
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
|
||||
Errtype: api.ErrorErrtypeInternalServerError,
|
||||
Message: fmt.Errorf("failed to delete node: %+v", err).Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 保存策略
|
||||
v.enfocer.SavePolicy()
|
||||
|
||||
// 成功删除返回204状态
|
||||
return api.DeleteUser204Response{}, nil
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
package vfs
|
4
main.go
4
main.go
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/handlers"
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs"
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/vfsdriver"
|
||||
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/services/vfsdriver"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/viper"
|
||||
@ -49,7 +49,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create bookmark service client:", err)
|
||||
}
|
||||
server.RegisterProxy(bookmarkService)
|
||||
server.Proxy.RegisterProxy(bookmarkService)
|
||||
}
|
||||
handlers.TodoHandler(api_router)
|
||||
}
|
||||
|
Reference in New Issue
Block a user