github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/filesystem/filesystem.go (about) 1 package filesystem 2 3 import ( 4 "errors" 5 "fmt" 6 model "github.com/cloudreve/Cloudreve/v3/models" 7 "github.com/cloudreve/Cloudreve/v3/pkg/cluster" 8 "github.com/cloudreve/Cloudreve/v3/pkg/conf" 9 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver" 10 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/cos" 11 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/googledrive" 12 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/local" 13 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/onedrive" 14 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/oss" 15 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/qiniu" 16 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/remote" 17 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/s3" 18 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/shadow/masterinslave" 19 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/shadow/slaveinmaster" 20 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/upyun" 21 "github.com/cloudreve/Cloudreve/v3/pkg/request" 22 "github.com/cloudreve/Cloudreve/v3/pkg/serializer" 23 "github.com/gin-gonic/gin" 24 cossdk "github.com/tencentyun/cos-go-sdk-v5" 25 "net/http" 26 "net/url" 27 "sync" 28 ) 29 30 // FSPool 文件系统资源池 31 var FSPool = sync.Pool{ 32 New: func() interface{} { 33 return &FileSystem{} 34 }, 35 } 36 37 // FileSystem 管理文件的文件系统 38 type FileSystem struct { 39 // 文件系统所有者 40 User *model.User 41 // 操作文件使用的存储策略 42 Policy *model.Policy 43 // 当前正在处理的文件对象 44 FileTarget []model.File 45 // 当前正在处理的目录对象 46 DirTarget []model.Folder 47 // 相对根目录 48 Root *model.Folder 49 // 互斥锁 50 Lock sync.Mutex 51 52 /* 53 钩子函数 54 */ 55 Hooks map[string][]Hook 56 57 /* 58 文件系统处理适配器 59 */ 60 Handler driver.Handler 61 62 // 回收锁 63 recycleLock sync.Mutex 64 } 65 66 // getEmptyFS 从pool中获取新的FileSystem 67 func getEmptyFS() *FileSystem { 68 fs := FSPool.Get().(*FileSystem) 69 return fs 70 } 71 72 // Recycle 回收FileSystem资源 73 func (fs *FileSystem) Recycle() { 74 fs.recycleLock.Lock() 75 fs.reset() 76 FSPool.Put(fs) 77 } 78 79 // reset 重设文件系统,以便回收使用 80 func (fs *FileSystem) reset() { 81 fs.User = nil 82 fs.CleanTargets() 83 fs.Policy = nil 84 fs.Hooks = nil 85 fs.Handler = nil 86 fs.Root = nil 87 fs.Lock = sync.Mutex{} 88 fs.recycleLock = sync.Mutex{} 89 } 90 91 // NewFileSystem 初始化一个文件系统 92 func NewFileSystem(user *model.User) (*FileSystem, error) { 93 fs := getEmptyFS() 94 fs.User = user 95 fs.Policy = &fs.User.Policy 96 97 // 分配存储策略适配器 98 err := fs.DispatchHandler() 99 100 return fs, err 101 } 102 103 // NewAnonymousFileSystem 初始化匿名文件系统 104 func NewAnonymousFileSystem() (*FileSystem, error) { 105 fs := getEmptyFS() 106 fs.User = &model.User{} 107 108 // 如果是主机模式下,则为匿名文件系统分配游客用户组 109 if conf.SystemConfig.Mode == "master" { 110 anonymousGroup, err := model.GetGroupByID(3) 111 if err != nil { 112 return nil, err 113 } 114 fs.User.Group = anonymousGroup 115 } else { 116 // 从机模式下,分配本地策略处理器 117 fs.Handler = local.Driver{} 118 } 119 120 return fs, nil 121 } 122 123 // DispatchHandler 根据存储策略分配文件适配器 124 func (fs *FileSystem) DispatchHandler() error { 125 if fs.Policy == nil { 126 return errors.New("未设置存储策略") 127 } 128 policyType := fs.Policy.Type 129 currentPolicy := fs.Policy 130 131 switch policyType { 132 case "mock", "anonymous": 133 return nil 134 case "local": 135 fs.Handler = local.Driver{ 136 Policy: currentPolicy, 137 } 138 return nil 139 case "remote": 140 handler, err := remote.NewDriver(currentPolicy) 141 if err != nil { 142 return err 143 } 144 145 fs.Handler = handler 146 case "qiniu": 147 fs.Handler = qiniu.NewDriver(currentPolicy) 148 return nil 149 case "oss": 150 handler, err := oss.NewDriver(currentPolicy) 151 fs.Handler = handler 152 return err 153 case "upyun": 154 fs.Handler = upyun.Driver{ 155 Policy: currentPolicy, 156 } 157 return nil 158 case "onedrive": 159 var odErr error 160 fs.Handler, odErr = onedrive.NewDriver(currentPolicy) 161 return odErr 162 case "cos": 163 u, _ := url.Parse(currentPolicy.Server) 164 b := &cossdk.BaseURL{BucketURL: u} 165 fs.Handler = cos.Driver{ 166 Policy: currentPolicy, 167 Client: cossdk.NewClient(b, &http.Client{ 168 Transport: &cossdk.AuthorizationTransport{ 169 SecretID: currentPolicy.AccessKey, 170 SecretKey: currentPolicy.SecretKey, 171 }, 172 }), 173 HTTPClient: request.NewClient(), 174 } 175 return nil 176 case "s3": 177 handler, err := s3.NewDriver(currentPolicy) 178 fs.Handler = handler 179 return err 180 case "googledrive": 181 handler, err := googledrive.NewDriver(currentPolicy) 182 fs.Handler = handler 183 return err 184 default: 185 return ErrUnknownPolicyType 186 } 187 188 return nil 189 } 190 191 // NewFileSystemFromContext 从gin.Context创建文件系统 192 func NewFileSystemFromContext(c *gin.Context) (*FileSystem, error) { 193 user, exist := c.Get("user") 194 if !exist { 195 return NewAnonymousFileSystem() 196 } 197 fs, err := NewFileSystem(user.(*model.User)) 198 return fs, err 199 } 200 201 // NewFileSystemFromCallback 从gin.Context创建回调用文件系统 202 func NewFileSystemFromCallback(c *gin.Context) (*FileSystem, error) { 203 fs, err := NewFileSystemFromContext(c) 204 if err != nil { 205 return nil, err 206 } 207 208 // 获取回调会话 209 callbackSessionRaw, ok := c.Get(UploadSessionCtx) 210 if !ok { 211 return nil, errors.New("upload session not exist") 212 } 213 callbackSession := callbackSessionRaw.(*serializer.UploadSession) 214 215 // 重新指向上传策略 216 fs.Policy = &callbackSession.Policy 217 err = fs.DispatchHandler() 218 219 return fs, err 220 } 221 222 // SwitchToSlaveHandler 将负责上传的 Handler 切换为从机节点 223 func (fs *FileSystem) SwitchToSlaveHandler(node cluster.Node) { 224 fs.Handler = slaveinmaster.NewDriver(node, fs.Handler, fs.Policy) 225 } 226 227 // SwitchToShadowHandler 将负责上传的 Handler 切换为从机节点转存使用的影子处理器 228 func (fs *FileSystem) SwitchToShadowHandler(master cluster.Node, masterURL, masterID string) { 229 switch fs.Policy.Type { 230 case "local": 231 fs.Policy.Type = "remote" 232 fs.Policy.Server = masterURL 233 fs.Policy.AccessKey = fmt.Sprintf("%d", master.ID()) 234 fs.Policy.SecretKey = master.DBModel().MasterKey 235 fs.DispatchHandler() 236 case "onedrive": 237 fs.Policy.MasterID = masterID 238 } 239 240 fs.Handler = masterinslave.NewDriver(master, fs.Handler, fs.Policy) 241 } 242 243 // SetTargetFile 设置当前处理的目标文件 244 func (fs *FileSystem) SetTargetFile(files *[]model.File) { 245 if len(fs.FileTarget) == 0 { 246 fs.FileTarget = *files 247 } else { 248 fs.FileTarget = append(fs.FileTarget, *files...) 249 } 250 251 } 252 253 // SetTargetDir 设置当前处理的目标目录 254 func (fs *FileSystem) SetTargetDir(dirs *[]model.Folder) { 255 if len(fs.DirTarget) == 0 { 256 fs.DirTarget = *dirs 257 } else { 258 fs.DirTarget = append(fs.DirTarget, *dirs...) 259 } 260 261 } 262 263 // SetTargetFileByIDs 根据文件ID设置目标文件,忽略用户ID 264 func (fs *FileSystem) SetTargetFileByIDs(ids []uint) error { 265 files, err := model.GetFilesByIDs(ids, 0) 266 if err != nil || len(files) == 0 { 267 return ErrFileExisted.WithError(err) 268 } 269 fs.SetTargetFile(&files) 270 return nil 271 } 272 273 // SetTargetByInterface 根据 model.File 或者 model.Folder 设置目标对象 274 // TODO 测试 275 func (fs *FileSystem) SetTargetByInterface(target interface{}) error { 276 if file, ok := target.(*model.File); ok { 277 fs.SetTargetFile(&[]model.File{*file}) 278 return nil 279 } 280 if folder, ok := target.(*model.Folder); ok { 281 fs.SetTargetDir(&[]model.Folder{*folder}) 282 return nil 283 } 284 285 return ErrObjectNotExist 286 } 287 288 // CleanTargets 清空目标 289 func (fs *FileSystem) CleanTargets() { 290 fs.FileTarget = fs.FileTarget[:0] 291 fs.DirTarget = fs.DirTarget[:0] 292 }