package webfilesystem import ( "context" "errors" "strings" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" ) type WebFileSystem struct { webfsCollection *mongo.Collection webfsFilesTable *mongo.Collection webfsFilesData *mongo.Collection ctx context.Context } func NewWebFileSystem(mongoClient *mongo.Client, dBName string, fsCollectionName string) *WebFileSystem { return &WebFileSystem{ webfsCollection: mongoClient.Database(dBName).Collection(fsCollectionName), // TODO Check collection is exist webfsFilesTable: mongoClient.Database(dBName).Collection("webfs-table"), // TODO Check collection is exist, //FIXME webfsFilesData: mongoClient.Database(dBName).Collection("webfs-data"), // TODO Check collection is exist, //FIXME ctx: context.Background(), } } type FileHeader struct { MongoId primitive.ObjectID `bson:"_id" json:"-"` Name string `bson:"name" json:"name"` Type string `bson:"type" json:"type"` Icon string `bson:"icon" json:"icon"` Data primitive.ObjectID `bson:"data_id" json:"-"` //TODO rename to DataId } func (fh *FileHeader) GetType() string { //TODO return by extension and etc return fh.Type } type BinaryFileData struct { MongoId primitive.ObjectID `bson:"_id" json:"-"` Bin []byte `bson:"bin" json:"-"` } type PlainTextFileData struct { MongoId primitive.ObjectID `bson:"_id" json:"-"` Data string `bson:"data" json:"data"` } // Deprecated func (fs *WebFileSystem) ReadHeader(fileID primitive.ObjectID) (*FileHeader, error) { file := &FileHeader{} filter := primitive.M{ "_id": fileID, } err := fs.webfsFilesTable.FindOne(fs.ctx, filter).Decode(file) return file, err } //TODO To private, get name from path and set it to file struct, force set newObjectID func (fs *WebFileSystem) Write(filePath string, file *FileHeader, data interface{}) (primitive.ObjectID, primitive.ObjectID, error) { headerId, dataId, err := fs.writeFileToMongo(file, data) if err != nil { return primitive.NilObjectID, primitive.NilObjectID, err } parentPath := fs.GetParentPath(filePath) parentDir, err := fs.FindFile(parentPath) if err != nil { return primitive.NilObjectID, primitive.NilObjectID, err } if parentDir.IsZero() { return primitive.NilObjectID, primitive.NilObjectID, errors.New("parent dir not found") } err = fs.AppendChildToDirectory(headerId, parentDir) if err != nil { return primitive.NilObjectID, primitive.NilObjectID, err } return headerId, dataId, nil } func (fs *WebFileSystem) UpdateFileData(file *FileHeader, data interface{}) error { update := bson.M{"$set": data} // println("updating data file: " + file.MongoId.String()) res, err := fs.webfsFilesData.UpdateByID(fs.ctx, file.Data, update) if err != nil { return err } if res.ModifiedCount < 1 { return errors.New("no data updated") } return err } func (fs *WebFileSystem) InitFS() error { //FIXME Can't set parent_id to itself rootData := DirectoryData{ MongoId: primitive.NewObjectID(), Parent: primitive.NewObjectID(), Children: []primitive.ObjectID{}, } rootHeader := FileHeader{ MongoId: primitive.NewObjectID(), Name: "/", Type: "directory", Icon: "", } _, _, err := fs.writeFileToMongo(&rootHeader, &rootData) if err != nil { return err } return nil } //TODO get on boot and safe to struct func (fs *WebFileSystem) GetRootDir() (*FileHeader, *DirectoryData, error) { filter := primitive.M{ "name": "/", } res := fs.webfsFilesTable.FindOne(fs.ctx, filter) if res == nil { return nil, nil, errors.New("TODO") //TODO } rootDir := FileHeader{} err := res.Decode(&rootDir) if res == nil { return nil, nil, err } filterData := primitive.M{ "_id": rootDir.Data, } resData := fs.webfsFilesData.FindOne(fs.ctx, filterData) if resData.Err() != nil { return nil, nil, err } rootDirData := DirectoryData{} err = resData.Decode(&rootDirData) if err != nil { return nil, nil, err } return &rootDir, &rootDirData, nil } func (fs *WebFileSystem) Remove(filePath string) error { parentPath := fs.GetParentPath(filePath) parentDirId, err := fs.FindFile(parentPath) if err != nil { return err } //TODO: Check, if parent file is dir parentDirData := DirectoryData{} parentDir, err := fs.readFSDocs(parentDirId, &parentDirData) if err != nil { return err } fileId, err := fs.FindFile(filePath) if err != nil { return err } newChildren := []primitive.ObjectID{} for _, childId := range parentDirData.Children { if childId != fileId { newChildren = append(newChildren, childId) } } parentDirData.Children = newChildren err = fs.UpdateFileData(parentDir, parentDirData) if err != nil { return err } return nil } func (fs *WebFileSystem) SplitPath(path string) []string { resPath := []string{} splittedPath := strings.Split(path, "/") splittedPath[0] = "/" for _, split := range splittedPath { if split != "" { resPath = append(resPath, split) } } return resPath } func (fs *WebFileSystem) GetExtension(filename string) string { splittedName := strings.Split(filename, ".") return splittedName[len(splittedName)-1] } func (fs *WebFileSystem) GetParentPath(path string) string { splittedPath := fs.SplitPath(path) if len(splittedPath) > 1 { return "/" + strings.Join(splittedPath[1:len(splittedPath)-1], "/") } return "/" }