package vfs import ( "log" "net/http" "os" "path/filepath" "sync" api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/vfs" "git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" fileadapter "github.com/casbin/casbin/v2/persist/file-adapter" "github.com/gin-gonic/gin" ) type VfsImpl struct { vfs *models.Vfs enfocer *casbin.Enforcer config VFSConfig proxyTable []*ProxyEntry // 动态代理表 proxyMutex sync.RWMutex // 保护代理表的读写锁 } func NewVfsHandler(config *Config) (*VfsImpl, error) { var err error vfs, err := models.NewVfs(config.VFS.DbPath) if err != nil { return nil, err } var policyPath = config.VFS.PolicyPath // 检查策略文件是否存在,如果不存在则创建 if _, err := os.Stat(policyPath); os.IsNotExist(err) { // 确保目录存在 dir := filepath.Dir(policyPath) if err := os.MkdirAll(dir, 0755); err != nil { log.Fatalf("error: failed to create policy directory: %s", err) } // 创建空的策略文件 file, err := os.Create(policyPath) if err != nil { log.Fatalf("error: failed to create policy file: %s", err) } file.Close() log.Printf("Created policy file: %s", policyPath) } a := fileadapter.NewAdapter(policyPath) if a == nil { log.Fatalf("error: adapter: %s", err) } m, err := model.NewModelFromString(CasbinModel) if err != nil { log.Fatalf("error: model: %s", err) } e, err := casbin.NewEnforcer(m, a) if err != nil { return nil, err } log.Printf("Admin Token: %s", config.VFS.AdminToken) log.Printf("Register Token: %s", config.VFS.RegisterToken) return &VfsImpl{ vfs: vfs, enfocer: e, config: config.VFS, proxyTable: make([]*ProxyEntry, 0), proxyMutex: sync.RWMutex{}, }, nil } func ModelType2ResponseType(nodeType models.VfsNodeType) api.VFSNodeType { var reponseType api.VFSNodeType switch nodeType { case models.VfsNodeTypeFile: reponseType = api.File case models.VfsNodeTypeDirectory: reponseType = api.Directory case models.VfsNodeTypeService: reponseType = api.Service } return reponseType } // CreateVFSNode implements api.ServerInterface. func (v *VfsImpl) CreateVFSNode(c *gin.Context, params api.CreateVFSNodeParams) { if !v.CheckPermissionMiddleware(c, params.Path) { return } // 解析路径组件 parentPath, nodeName, nodeType, err := models.ParsePathComponents(params.Path) if err != nil { c.JSON(http.StatusBadRequest, api.Error{ Errtype: "error", Message: err.Error(), }) return } // 创建节点 node, err := v.vfs.CreateNodeByComponents(parentPath, nodeName, nodeType) if err != nil { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "CreateNodeByComponents", Message: err.Error(), }) return } if nodeType == models.VfsNodeTypeService { if !v.Proxy2Service(c, node) { // Rollback err := v.vfs.DeleteVFSNode(node) if err != nil { // FIXME: 需要解决这种原子性 panic("Maybe Consistency Error") } return } } // 返回创建成功的节点 c.JSON(http.StatusCreated, api.VFSNodeResponse{ Name: node.Name, Type: ModelType2ResponseType(node.Type), CreatedAt: node.CreatedAt, UpdatedAt: node.UpdatedAt, }) } // GetVFSNode implements api.ServerInterface. func (v *VfsImpl) GetVFSNode(c *gin.Context, params api.GetVFSNodeParams) { if !v.CheckPermissionMiddleware(c, params.Path) { return } node, err := v.vfs.GetNodeByPath(params.Path) if err != nil { c.JSON(http.StatusNotFound, api.Error{ Errtype: "error", Message: err.Error(), }) return } switch node.Type { case models.VfsNodeTypeDirectory: if entries, err := v.vfs.GetChildren(node.ID); err != nil { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: err.Error(), }) return } else { var responseEntries []api.VFSDirectoryEntry for _, entry := range entries { responseEntries = append(responseEntries, api.VFSDirectoryEntry{ Name: entry.Name, Type: ModelType2ResponseType(entry.Type), }) } c.JSON(http.StatusOK, responseEntries) return } case models.VfsNodeTypeService: v.Proxy2Service(c, node) default: c.JSON(http.StatusBadRequest, api.Error{ Errtype: "error", Message: "Not a valid node type", }) } } // DeleteVFSNode implements api.ServerInterface. func (v *VfsImpl) DeleteVFSNode(c *gin.Context, params api.DeleteVFSNodeParams) { if !v.CheckPermissionMiddleware(c, params.Path) { return } node, err := v.vfs.GetNodeByPath(params.Path) if err != nil { c.JSON(http.StatusNotFound, api.Error{ Errtype: "error", Message: err.Error(), }) return } switch node.Type { case models.VfsNodeTypeService: if !v.Proxy2Service(c, node) { return } case models.VfsNodeTypeDirectory: if children, err := v.vfs.GetChildren(node.ID); err != nil || len(children) != 0 { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: "the folder is not empty", }) return } default: c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: "node type not supported", }) return } if err := v.vfs.DeleteVFSNode(node); err != nil { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: err.Error(), }) return } c.JSON(http.StatusNoContent, nil) } // UpdateVFSNode implements api.ServerInterface. func (v *VfsImpl) UpdateVFSNode(c *gin.Context, params api.UpdateVFSNodeParams) { if !v.CheckPermissionMiddleware(c, params.Path) { return } var req api.UpdateVFSNodeJSONRequestBody if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, api.Error{ Errtype: "ParameterError", Message: "Invalid request parameters", }) return } node, err := v.vfs.GetNodeByPath(params.Path) if err != nil { c.JSON(http.StatusNotFound, api.Error{ Errtype: "error", Message: err.Error(), }) return } switch params.Op { case api.Rename: if req == "" { c.JSON(http.StatusBadRequest, api.Error{ Errtype: "ParameterError", Message: "Invalid request parameters", }) return } // FIXME: 对于service,后缀属性需要强制保留 if err := v.vfs.UpdateVFSNode(node); err != nil { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: err.Error(), }) return } case api.Change: if node.Type != models.VfsNodeTypeFile { c.JSON(http.StatusBadRequest, api.Error{ Errtype: "ParameterError", Message: "Invalid request parameters, node type must be a service", }) return } if !v.Proxy2Service(c, node) { return } case api.Move: // FIXME: 需要添加权限控制 v.vfs.MoveToPath(node, req) case api.Copy: fallthrough default: c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "error", Message: "op type not supported", }) return } } // CreateUser implements api.ServerInterface. func (v *VfsImpl) CreateUser(c *gin.Context, username string) { token := c.GetHeader("X-VFS-Token") if token != v.config.RegisterToken || token != v.config.AdminToken { c.JSON(http.StatusForbidden, api.Error{ Errtype: "AccessDenied", Message: "Access denied", }) return } token, err := v.vfs.CreateUser(username) if err != nil { c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "CreateUserError", Message: err.Error(), }) return } _, err = v.enfocer.AddRoleForUser(username, "user") if err != nil { log.Printf("Failed to add role for user %s: %v", username, err) } v.enfocer.SavePolicy() // 根据API文档,token应该通过响应头返回 c.Header("X-VFS-Token", token) c.Status(http.StatusCreated) } // DeleteUser implements api.ServerInterface. func (v *VfsImpl) DeleteUser(c *gin.Context, username string) { token := c.GetHeader("X-VFS-Token") user, err := v.vfs.GetUserByToken(token) if err != nil || user.Name != username { c.JSON(http.StatusForbidden, api.Error{ Errtype: "AccessDenied", Message: "Access denied", }) return } err = v.vfs.DeleteUser(username) if err != nil { if err.Error() == "user not found" { c.JSON(http.StatusNotFound, api.Error{ Errtype: "UserNotFoundError", Message: "User not found", }) return } c.JSON(http.StatusInternalServerError, api.Error{ Errtype: "DeleteUserError", Message: err.Error(), }) return } // 根据API文档,删除成功返回204状态码 c.Status(http.StatusNoContent) } // Make sure we conform to ServerInterface var _ api.ServerInterface = (*VfsImpl)(nil)