package localserver import ( "context" "encoding/json" "fmt" "io" "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" "time" "github.com/pion/webrtc/v3" ) const ( CREATE_FOLDER = "create_folder" COPY_FOLDER = "copy_folder" COPY_FILE = "copy_file" CUT_FILE = "cut_file" CUT_FOLDER = "cut_folder" RENAME_FOLDER = "rename_folder" RENAME_FILE = "rename_file" DELETE_FOLDER = "delete_folder" DELETE_FILE = "delete_file" UPDATE_PERMISSIONS = "update_permissions" GET_FS_ENTITIES = "get_fs_entities" ADD_FS_ENTITY_MEMBERS = "add_fs_entity_members" REMOVE_FS_ENTITY_MEMBERS = "remove_fs_entity_members" ZONE_UPLOAD_FILE = "zone_upload_file" ZONE_DOWNLOAD_FILE = "zone_download_file" ) const ( CREATE_FOLDER_DONE = "create_folder_done" CREATE_FILE_DONE = "create_file_done" COPY_FOLDER_DONE = "copy_folder_done" COPY_FILE_DONE = "copy_file_done" CUT_FILE_DONE = "cut_file_done" CUT_FOLDER_DONE = "cut_folder_done" RENAME_FOLDER_DONE = "rename_folder_done" RENAME_FILE_DONE = "rename_file_done" DELETE_FOLDER_DONE = "delete_folder_done" DELETE_FILE_DONE = "delete_file_done" UPDATE_PERMISSIONS_DONE = "update_permissions_done" GET_FS_ENTITIES_DONE = "get_fs_entities_done" ADD_FS_ENTITY_MEMBERS_DONE = "add_fs_entity_members_done" REMOVE_FS_ENTITY_MEMBERS_DONE = "remove_fs_entity_members_done" ZONE_DOWNLOAD_FILE_DONE = "zone_download_file_done" ZONE_UPLOAD_FILE_DONE = "zone_upload_file_done" ) const ( PARENT = "parent" ) // ZoneFileHandler : Handle all interaction of the node zone related to the file system type ZoneFileHandler struct { ZoneId string HostId string ZoneMembersId []string DataChannels map[string]*DataChannel Flag *uint32 FSInstanceFlag *uint32 Publishers []<-chan *ZoneRequest FSInstance *FSInstance reqChans []chan<- *ZoneRequest DB *ZoneFilesDBHandler } // FSEntityAccessRights : representation of the different rights users can have on a ZoneFSEntity type FSEntityAccessRights struct { // Read : this field for folder determine if the member is allowed to see this folder only because he is allowed to read a child folder or because he actually is authorized to read this folder (hard to explain) Read bool `json:"read"` // Write : this field for folder determine if the user can upload file in this folder and for file if the user can edit the file (future feature). Write bool `json:"write"` // Download : this field for folder determine if the user can download a zip of the folder (future feature) and for file if he can download the file. Download bool `json:"download"` // Rename : determine the ability of the user to change the name of the fsEntity Rename bool `json:"rename"` } // ZoneFSEntity : representation of a FSEntity (file or folder) for the zone fs feature type ZoneFSEntity struct { Name string `json:"name"` Owner string `json:"owner"` Type string `json:"type"` Folder bool `json:"folder"` ModTime string `json:"modTime"` CreationTime string `json:"creationTime"` Size uint64 `json:"size"` Members map[string]*FSEntityAccessRights `json:"members"` } // NewZoneFileHandler: factory function to create a zone file handler the name of the parameters are explicit, this is the only way to safely create a ZoneFSEntity func NewZoneFileHandler(_ string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneFileHandler *ZoneFileHandler, err error) { db, err := NewZoneFilesDBHandler(zoneId) if err != nil { return } initFsDirectory := func(u string) (err error) { logger.Printf("creating fs directory for user %s...\n", u) baseConfig := ZoneFSEntity{ Name: u, Owner: u, Type: "private", Folder: true, Members: map[string]*FSEntityAccessRights{ u: { Read: true, Write: true, Download: true, Rename: true, }, }, } err = db.AddNewFSEntity("", &baseConfig) return } if _, dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "fs")); os.IsNotExist(dirErr) { dirErr := os.MkdirAll(filepath.Join("data", "zones", zoneId, "fs"), 0700) if dirErr != nil { return } } for _, user := range authorizedMembers { if _, dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "fs", user)); os.IsNotExist(dirErr) { if e := initFsDirectory(user); e != nil { logger.Println(e) } } } fSInstanceFlag := uint32(0) fsInstance := NewFSInstance(zoneId, owner, authorizedMembers) zoneFileHandler = &ZoneFileHandler{ ZoneId: zoneId, ZoneMembersId: authorizedMembers, DataChannels: dataChannels, FSInstanceFlag: &fSInstanceFlag, FSInstance: fsInstance, DB: db, Flag: flag, } return } // func (zch *ZoneFileHandler) sendZoneRequest(reqType string, from string, payload map[string]interface{}) { // go func() { // for _, rc := range zch.reqChans { // rc <- &ZoneRequest{ // ReqType: reqType, // From: from, // Payload: payload, // } // } // }() // } func (zch *ZoneFileHandler) Init(ctx context.Context, authorizedMembers []string) (err error) { for _, member := range authorizedMembers { if serr := zch.SetPublicRootFolders(member); serr != nil { logger.Println(serr) } } return } func (zch *ZoneFileHandler) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) { done, errCh := make(chan struct{}), make(chan error) go func() { if err := atomicallyExecute(zch.Flag, func() (err error) { if _, ok := zch.DataChannels[to]; ok { bs, jsonErr := json.Marshal(&ZoneResponse{ Type: reqType, From: from, To: to, Payload: payload, }) if jsonErr != nil { return jsonErr } err = zch.DataChannels[to].DataChannel.SendText(string(bs)) } return }); err != nil { errCh <- err return } done <- struct{}{} }() return done, errCh } func (zch *ZoneFileHandler) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) { reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error) zch.reqChans = append(zch.reqChans, reqChan) go func() { for { select { case <-ctx.Done(): done <- struct{}{} return case req := <-publisher: if err := zch.handleZoneRequest(ctx, req); err != nil { errCh <- err } } } }() return } func (zfh *ZoneFileHandler) signalCandidate(from string, to string, candidate *webrtc.ICECandidate) (err error) { d, e := zfh.sendDataChannelMessage(string(ZONE_FS_WEBRTC_CANDIDATE), from, to, map[string]interface{}{ "from": from, "to": to, "candidate": candidate.ToJSON().Candidate, "sdpMid": *candidate.ToJSON().SDPMid, "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)), }) select { case <-d: case err = <-e: } return } // GetFSEntities: Return a list of ZoneFSEntity to the user with the provided userId func (zfh *ZoneFileHandler) GetFSEntities(userId string, section string, basePath string, limit int, lastIndex int, backward bool) (err error) { var fsEntities []*ZoneFSEntity var currentPath string = basePath var listFSEntities func(string, string, int, int, bool) listFSEntities = func(userId, path string, limit, lastIndex int, backward bool) { fsEntities, _, err = zfh.DB.ListZoneFSEntity(path, userId, lastIndex, limit) if err != nil { return } currentPath = path if len(fsEntities) == 1 { if rights, ok := fsEntities[0].Members[userId]; ok { if !rights.Read { if !backward { listFSEntities(userId, filepath.Join(path, fsEntities[0].Name), 100, 0, backward) } else { splittedPath := filepath.SplitList(path) if len(splittedPath) > 1 { listFSEntities(userId, filepath.Dir(path), 100, 0, backward) } else { listFSEntities(userId, "", 100, 0, backward) } } } } } } listFSEntities(userId, basePath, 100, 0, backward) var parent *ZoneFSEntity if len(filepath.SplitList(basePath)) > 0 { parent, err = zfh.DB.GetFSEntity(filepath.Dir(basePath), filepath.Base(basePath)) if err != nil { return } logger.Println("------------------ parent is --------------") logger.Println(parent) } done, errCh := zfh.sendDataChannelMessage(GET_FS_ENTITIES, "node", userId, map[string]interface{}{ "fsEntities": fsEntities, "parent": parent, "currentPath": currentPath, "section": section, }) select { case <-done: case err = <-errCh: } return } // CreateFolder: create a ZoneFSEntity folder mapped to a real folder on the disk func (zfh *ZoneFileHandler) CreateFolder(path string, config *ZoneFSEntity) (err error) { if config.Type == PARENT { parentPath := filepath.Dir(path) parentFolderName := filepath.Base(path) logger.Println(parentPath, "-------", parentFolderName) var folder *ZoneFSEntity if len(parentPath) > 1 { folder, err = zfh.DB.GetFSEntity(parentPath, parentFolderName) } else { folder, err = zfh.DB.GetFSEntity("", parentFolderName) } if err != nil { return } config.Members = make(map[string]*FSEntityAccessRights) for k, v := range folder.Members { config.Members[k] = &FSEntityAccessRights{ Read: v.Read, Write: v.Write, Download: v.Download, Rename: v.Rename, } } } if err = zfh.DB.AddNewFSEntity(path, config); err != nil { return } for member := range config.Members { done, errCh := zfh.sendDataChannelMessage(CREATE_FOLDER_DONE, "node", member, map[string]interface{}{ "path": path, "fsEntity": config, }) select { case <-done: case err = <-errCh: logger.Println(err) } } return } // CreateFile: create a ZoneFSEntity file mapped to a real file on the disk func (zfh *ZoneFileHandler) CreateFile(path, fileName string, config *ZoneFSEntity) (err error) { splittedPath := strings.Split(path, "/") if config.Type == PARENT { logger.Println(strings.Join(splittedPath[:len(splittedPath)-1], "/"), "-------", splittedPath[len(splittedPath)-1]) var folder *ZoneFSEntity if len(splittedPath) > 1 { folder, err = zfh.DB.GetFSEntity(strings.Join(splittedPath[:len(splittedPath)-1], "/"), splittedPath[len(splittedPath)-1]) } else { folder, err = zfh.DB.GetFSEntity("", splittedPath[0]) } if err != nil { return } config.Members = make(map[string]*FSEntityAccessRights) for k, v := range folder.Members { config.Members[k] = &FSEntityAccessRights{ Read: v.Read, Write: v.Write, Download: v.Download, Rename: v.Rename, } } } if err = zfh.DB.AddNewFSEntity(path, config); err != nil { return } for member := range config.Members { done, errCh := zfh.sendDataChannelMessage(CREATE_FILE_DONE, "node", member, map[string]interface{}{ "path": path, "fsEntity": config, }) select { case <-done: case err = <-errCh: logger.Println(err) } } return } // EditFolderType: change the type of the folder and modify rights of the users according to the new ZoneFSEntity type provided func (zfh *ZoneFileHandler) EditFolderType(userId string, path string, folderName string, newFolderType string) (err error) { folder, err := zfh.DB.GetFSEntity(path, folderName) if err != nil { return } folder.Type = newFolderType if err = zfh.DB.SetFSEntity(path, folderName, folder); err != nil { return } done, errCh := zfh.sendDataChannelMessage("", "node", userId, map[string]interface{}{ "newFolder": folder, }) select { case <-done: case err = <-errCh: } return } func (zfh *ZoneFileHandler) EditFileType(path string, fileName string, newFileType string) (err error) { return } // AddFolderMember: add a list of members to the map of users allowed to access the folder with the provided folderName and set the rights func (zfh *ZoneFileHandler) AddFolderMember(userId string, path string, folderName string, members []interface{}, read bool, write bool, download bool, rename bool) (err error) { var addMembersDb func(string, string, bool, bool, bool, bool, bool) (folder *ZoneFSEntity, err error) addMembersDb = func(path string, folderName string, read bool, write bool, download bool, rename bool, init bool) (folder *ZoneFSEntity, err error) { folder, err = zfh.DB.GetFSEntity(path, folderName) if err != nil { return } childrens := make([]*ZoneFSEntity, 0) if init { childrens, _, err = zfh.DB.ListZoneFSEntity(filepath.Join(path, folderName), userId, 0, 100) if err != nil { logger.Println("cannot get siblings folders:", err) return } } for _, newMember := range members { if m, ok := newMember.(string); ok { if _, ok := folder.Members[m]; !ok { folder.Members[m] = &FSEntityAccessRights{ Read: read, Write: write, Download: download, Rename: rename, } } if init { go func() { for _, children := range childrens { logger.Println("------:", filepath.Join(path, folderName), "-", children.Name) if children.Type != "private" { if _, err = addMembersDb(filepath.Join(path, folderName), children.Name, read, write, download, rename, true); err != nil { logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*") logger.Println("error from ttttthheeere:", err) logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*") } } } }() } } } err = zfh.DB.SetFSEntity(path, folderName, folder) return } folder, err := addMembersDb(path, folderName, read, write, download, rename, true) if err != nil { return } splittedPath := strings.Split(path, "/") for i := 1; i <= len(splittedPath); i++ { logger.Println(i) var addErr error if i == len(splittedPath) { _, addErr = addMembersDb("", splittedPath[0], false, false, false, false, false) } else { _, addErr = addMembersDb(strings.Join(splittedPath[:len(splittedPath)-i], "/"), splittedPath[len(splittedPath)-i], false, false, false, false, false) } if addErr != nil { return addErr } } for member := range folder.Members { done, errCh := zfh.sendDataChannelMessage(ADD_FS_ENTITY_MEMBERS_DONE, "node", member, map[string]interface{}{ "path": path, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } func (zfh *ZoneFileHandler) AddFileMember(path string, filename string, members []interface{}, read bool, write bool, download bool, rename bool) (err error) { return } func (zfh *ZoneFileHandler) RemoveFolderMember(userId string, path string, folderName string, members []interface{}) (err error) { membersM := make(map[string]bool) staticMembersM := make(map[string]bool) for _, member := range members { if m, ok := member.(string); ok { membersM[m] = true staticMembersM[m] = true } } var removeChildMemberDb func(string, string) (folder *ZoneFSEntity, err error) removeChildMemberDb = func(path, folderName string) (folder *ZoneFSEntity, err error) { childrens, _, err := zfh.DB.ListZoneFSEntity(filepath.Join(path, folderName), userId, 0, 100) if err != nil { logger.Println("cannot get siblings folders:", err) return } go func() { for _, children := range childrens { for member := range staticMembersM { if _, ok := children.Members[member]; ok && member != children.Owner { delete(children.Members, member) } } logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*") logger.Println(filepath.Join(path, folderName), ":", children.Name) logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*") _, _ = removeChildMemberDb(filepath.Join(path, folderName), children.Name) err = zfh.DB.SetFSEntity(filepath.Join(path, folderName), children.Name, children) } }() return } removeMemberDb := func(path, folderName string, init bool) (folder *ZoneFSEntity, err error) { folder, err = zfh.DB.GetFSEntity(path, folderName) if err != nil { return } siblings, _, err := zfh.DB.ListZoneFSEntity(path, userId, 0, 100) if err != nil { logger.Println("cannot get siblings folders:", err) return } if init { _, _ = removeChildMemberDb(path, folderName) } for member := range membersM { if _, ok := folder.Members[member]; ok && member != folder.Owner { if !folder.Members[member].Read || init { delete(folder.Members, member) } else { delete(membersM, member) } for _, sibling := range siblings { if sibling.Name != folder.Name { if _, ok := sibling.Members[member]; ok { delete(membersM, member) } } } } } err = zfh.DB.SetFSEntity(path, folderName, folder) return } folder, err := removeMemberDb(path, folderName, true) if err != nil { return } splittedPath := strings.Split(path, "/") for i := 1; i <= len(splittedPath) && len(membersM) > 0; i++ { logger.Println(i) var addErr error if i == len(splittedPath) { _, addErr = removeMemberDb("", splittedPath[0], false) } else { _, addErr = removeMemberDb(strings.Join(splittedPath[:len(splittedPath)-i], "/"), splittedPath[len(splittedPath)-i], false) } if addErr != nil { return addErr } } for member := range folder.Members { done, errCh := zfh.sendDataChannelMessage(REMOVE_FS_ENTITY_MEMBERS_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, folderName), }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } for _, member := range members { if _, ok := member.(string); ok { done, errCh := zfh.sendDataChannelMessage(REMOVE_FS_ENTITY_MEMBERS_DONE, "node", member.(string), map[string]interface{}{ "path": filepath.Join(path, folderName), }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } } return } func (zfh *ZoneFileHandler) RemoveFileMember(path, filename, members, read, write, download, rename bool) (err error) { return } func (zfh *ZoneFileHandler) RenameFolder(path, currentName, newName string) (err error) { fsEntity, err := zfh.DB.GetFSEntity(path, currentName) if err != nil { return } fsEntity.Name = newName if err = os.Rename(filepath.Join(filepath.Join("data", "zones", zfh.ZoneId, "fs"), path, currentName), filepath.Join(filepath.Join("data", "zones", zfh.ZoneId, "fs"), path, newName)); err != nil { return } if err = zfh.DB.SetFSEntity(path, currentName, fsEntity); err != nil { return } for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(RENAME_FOLDER_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, newName), "folderId": newName, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } func (zfh *ZoneFileHandler) RenameFile(path, currentName, newName string) (err error) { fsEntity, err := zfh.DB.GetFSEntity(path, currentName) if err != nil { return } fsEntity.Name = newName if err = os.Rename(filepath.Join(filepath.Join("data", "zones", zfh.ZoneId, "fs"), path, "__files__", currentName), filepath.Join(filepath.Join("data", "zones", zfh.ZoneId, "fs"), path, "__files__", newName)); err != nil { return } if err = zfh.DB.SetFSEntity(path, currentName, fsEntity); err != nil { return } for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(RENAME_FILE_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, newName), "folderId": newName, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } func (zfh *ZoneFileHandler) UpdatePermissions(path, name, userId string, newPermission *FSEntityAccessRights) (err error) { var updatePermission func(string, string) error updatePermission = func(path, name string) (err error) { fsEntity, err := zfh.DB.GetFSEntity(path, name) if err != nil { return } if fsEntity.Folder { splittedPath := append(filepath.SplitList(path), name) childrens, _, err := zfh.DB.ListZoneFSEntity(filepath.Join(splittedPath...), userId, 0, 100) if err != nil { return err } go func() { for _, children := range childrens { if children.Type == PARENT { if err = updatePermission(filepath.Join(splittedPath...), children.Name); err != nil { return } } } }() } fsEntity.Members[userId] = newPermission if err = zfh.DB.SetFSEntity(path, name, fsEntity); err != nil { return } for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(UPDATE_PERMISSIONS_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, name), }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } err = updatePermission(path, name) return } func (zfh *ZoneFileHandler) DeleteFolder(path, name string) (err error) { fsEntity, err := zfh.DB.GetFSEntity(path, name) if err != nil { return } if err = zfh.DB.DeleteFolder(path, name); err != nil { return } for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(DELETE_FOLDER_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, name), "folderId": name, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } func (zfh *ZoneFileHandler) DeleteFile(path, name string) (err error) { fsEntity, err := zfh.DB.GetFSEntity(path, name) if err != nil { return } if err = zfh.DB.DeleteFile(path, name); err != nil { return } for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(DELETE_FOLDER_DONE, "node", member, map[string]interface{}{ "path": filepath.Join(path, name), "folderId": name, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } return } func (zfh *ZoneFileHandler) CopyFile(src, dst string, init bool, fsEntity *ZoneFSEntity) (err error) { var srcfd *os.File var dstfd *os.File var srcinfo os.FileInfo var srcPath string var dstPath string if init { srcPath = filepath.Join("data", "zones", zfh.ZoneId, "fs", filepath.Dir(src), "__files__", filepath.Base(src)) dstPath = filepath.Join("data", "zones", zfh.ZoneId, "fs", filepath.Dir(dst), "__files__", filepath.Base(dst)) } else { srcPath = filepath.Join("data", "zones", zfh.ZoneId, "fs", src) dstPath = filepath.Join("data", "zones", zfh.ZoneId, "fs", dst) } if err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil && !os.IsExist(err) { return } if srcfd, err = os.Open(srcPath); err != nil { return } defer srcfd.Close() if dstfd, err = os.Create(dstPath); err != nil { return } defer dstfd.Close() if _, err = io.Copy(dstfd, srcfd); err != nil { return } if srcinfo, err = os.Stat(srcPath); err != nil { return } if err = os.Chmod(dstPath, srcinfo.Mode()); err != nil { return } if init { err = zfh.DB.AddNewFSEntity(filepath.Dir(dst), fsEntity) for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(COPY_FILE_DONE, "node", member, map[string]interface{}{ "path": dst, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } } return } func (zfh *ZoneFileHandler) CopyDir(src, dst string, init bool, fsEntity *ZoneFSEntity) (err error) { var fds []os.FileInfo var srcinfo os.FileInfo srcPath := filepath.Join("data", "zones", zfh.ZoneId, "fs", src) dstPath := filepath.Join("data", "zones", zfh.ZoneId, "fs", dst) if srcinfo, err = os.Stat(srcPath); err != nil { return } if init { logger.Println("---------------------adding new fs entity---------------------") if err = zfh.DB.AddNewFSEntity(filepath.Dir(dst), fsEntity); err != nil { return } } else { if err = os.MkdirAll(dstPath, srcinfo.Mode()); err != nil { return } } if fds, err = ioutil.ReadDir(srcPath); err != nil { return } for _, fd := range fds { srcfp := path.Join(src, fd.Name()) dstfp := path.Join(dst, fd.Name()) if fd.IsDir() { if err = zfh.CopyDir(srcfp, dstfp, false, nil); err != nil { logger.Println(err) } } else { if err = zfh.CopyFile(srcfp, dstfp, false, nil); err != nil { logger.Println(err) } } } if fsEntity != nil { for member := range fsEntity.Members { done, errCh := zfh.sendDataChannelMessage(COPY_FOLDER_DONE, "node", member, map[string]interface{}{ "path": dst, }) select { case <-done: case sendErr := <-errCh: logger.Println(sendErr) } } } return } func (zfh *ZoneFileHandler) CutFolder(id, path, dstPath string, init bool, fsEntity *ZoneFSEntity) (err error) { if err = zfh.CopyDir(path, dstPath, init, fsEntity); err != nil { return } err = zfh.DeleteFolder(filepath.Dir(path), filepath.Base(path)) return } func (zfh *ZoneFileHandler) CutFile(id, path, dstPath string, init bool, fsEntity *ZoneFSEntity) (err error) { if err = zfh.CopyFile(path, dstPath, init, fsEntity); err != nil { return } err = zfh.DeleteFile(filepath.Dir(path), filepath.Base(path)) return } func (zfh *ZoneFileHandler) ConnectToFSInstance(channelId string, userId string, sdp string) (err error) { err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { d, e := zfh.FSInstance.HandleOffer(context.Background(), channelId, userId, sdp, zfh.HostId, zfh.sendDataChannelMessage, zfh.signalCandidate) select { case <-d: case err = <-e: } return }) return } func (zfh *ZoneFileHandler) LeaveFSInstance( userId string) (err error) { err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { zfh.FSInstance.HandleLeavingMember(userId) return }) return } func (zch *ZoneFileHandler) SetPublicRootFolders(user string) (err error) { return } func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneRequest) (err error) { switch req.ReqType { case string(REMOVED_ZONE_AUTHORIZED_MEMBER): if err = verifyFieldsString(req.Payload, "userId"); err != nil { return } var index int for i, m := range zfh.ZoneMembersId { if m == req.Payload["userId"].(string) { index = i break } } zfh.ZoneMembersId = append(zfh.ZoneMembersId[:index], zfh.ZoneMembersId[index+1:]...) err = zfh.DeleteFolder("", req.Payload["userId"].(string)) case string(NEW_AUTHORIZED_ZONE_MEMBER): if err = verifyFieldsString(req.Payload, "userId"); err != nil { return } var contain bool for _, m := range zfh.ZoneMembersId { if m == req.Payload["userId"].(string) { contain = true break } } if !contain { zfh.ZoneMembersId = append(zfh.ZoneMembersId, req.Payload["userId"].(string)) } err = zfh.DB.AddNewFSEntity("", &ZoneFSEntity{ Name: req.Payload["userId"].(string), Owner: req.Payload["userId"].(string), Type: PRIVATE, Folder: true, ModTime: time.Now().Format(time.UnixDate), CreationTime: time.Now().Format(time.UnixDate), Size: 0, Members: map[string]*FSEntityAccessRights{ req.Payload["userId"].(string): { Read: true, Write: true, Download: true, Rename: true, }, }, }) case LEAVE_ZONE: logger.Println("*-----------------handling leaving zone---------------*") if err = verifyFieldsString(req.Payload, "userId"); err != nil { return } err = zfh.LeaveFSInstance(req.Payload["userId"].(string)) case ZONE_UPLOAD_FILE_DONE: if err = verifyFieldsBool(req.Payload, "failed"); err != nil { return } if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil { return } if err = verifyFieldsFloat64(req.Payload, "size"); err != nil { return } if req.Payload["failed"].(bool) { logger.Println(zfh.FSInstance.FileUploadFailed(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))) } else { defer func() { logger.Println(zfh.FSInstance.FileUploadDone(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))) }() err = zfh.CreateFile(req.Payload["path"].(string), req.Payload["fileName"].(string), &ZoneFSEntity{ Name: req.Payload["fileName"].(string), Owner: req.Payload["userId"].(string), Type: req.Payload["type"].(string), Size: uint64(req.Payload["size"].(float64)), ModTime: time.Now().Format(time.UnixDate), CreationTime: time.Now().Format(time.UnixDate), Folder: false, Members: map[string]*FSEntityAccessRights{ req.Payload["userId"].(string): { Read: true, Write: true, Download: true, Rename: true, }, }, }) } case ZONE_UPLOAD_FILE: if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil { return } err = zfh.FSInstance.SetupFileUpload(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)) case ZONE_DOWNLOAD_FILE: if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil { return } err = zfh.FSInstance.SetupFileDownload(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)) case GET_FS_ENTITIES: logger.Println("getting files entities") if err = verifyFieldsString(req.Payload, "path", "userId", "section"); err != nil { return } var backward bool if err = verifyFieldsBool(req.Payload, "backward"); err == nil { backward = req.Payload["backward"].(bool) } if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil { return } err = zfh.GetFSEntities(req.Payload["userId"].(string), req.Payload["section"].(string), req.Payload["path"].(string), 0, 100, backward) case CREATE_FOLDER: logger.Println("creating folder") if err = verifyFieldsString(req.Payload, "path"); err != nil { return } if _, ok := req.Payload["config"]; !ok { err = fmt.Errorf("no field config in request payload") return } bs, jsonErr := json.Marshal(req.Payload["config"]) if jsonErr != nil { return jsonErr } var config ZoneFSEntity if err = json.Unmarshal(bs, &config); err != nil { err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err) return } err = zfh.CreateFolder(req.Payload["path"].(string), &config) case RENAME_FOLDER: if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil { return } err = zfh.RenameFolder(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string)) case RENAME_FILE: if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil { return } err = zfh.RenameFile(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string)) case COPY_FOLDER: if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil { return } if _, ok := req.Payload["config"]; !ok { err = fmt.Errorf("no field config in request payload") return } bs, jsonErr := json.Marshal(req.Payload["config"]) if jsonErr != nil { return jsonErr } var config ZoneFSEntity if err = json.Unmarshal(bs, &config); err != nil { err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err) return } go func() { err = zfh.CopyDir(req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config) logger.Println(err) }() case COPY_FILE: if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil { return } if _, ok := req.Payload["config"]; !ok { err = fmt.Errorf("no field config in request payload") return } bs, jsonErr := json.Marshal(req.Payload["config"]) if jsonErr != nil { return jsonErr } var config ZoneFSEntity if err = json.Unmarshal(bs, &config); err != nil { err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err) return } go func() { err = zfh.CopyFile(req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config) logger.Println(err) }() case CUT_FOLDER: if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil { return } if _, ok := req.Payload["config"]; !ok { err = fmt.Errorf("no field config in request payload") return } bs, jsonErr := json.Marshal(req.Payload["config"]) if jsonErr != nil { return jsonErr } var config ZoneFSEntity if err = json.Unmarshal(bs, &config); err != nil { err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err) return } go func() { err = zfh.CutFolder(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config) logger.Println(err) }() case CUT_FILE: if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil { return } if _, ok := req.Payload["config"]; !ok { err = fmt.Errorf("no field config in request payload") return } bs, jsonErr := json.Marshal(req.Payload["config"]) if jsonErr != nil { return jsonErr } var config ZoneFSEntity if err = json.Unmarshal(bs, &config); err != nil { err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err) return } go func() { err = zfh.CutFile(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config) logger.Println(err) }() case UPDATE_PERMISSIONS: if err = verifyFieldsString(req.Payload, "path", "name", "userId"); err != nil { return } if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil { return } fsAcessRights := &FSEntityAccessRights{ Read: req.Payload["read"].(bool), Write: req.Payload["write"].(bool), Download: req.Payload["download"].(bool), Rename: req.Payload["rename"].(bool), } err = zfh.UpdatePermissions(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["userId"].(string), fsAcessRights) case DELETE_FOLDER: if err = verifyFieldsString(req.Payload, "path", "name"); err != nil { return } err = zfh.DeleteFolder(req.Payload["path"].(string), req.Payload["name"].(string)) case DELETE_FILE: if err = verifyFieldsString(req.Payload, "path", "name"); err != nil { return } err = zfh.DeleteFile(req.Payload["path"].(string), req.Payload["name"].(string)) case ADD_FS_ENTITY_MEMBERS: if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil { return } if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil { return } if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil { return } err = zfh.AddFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{}), req.Payload["read"].(bool), req.Payload["write"].(bool), req.Payload["download"].(bool), req.Payload["rename"].(bool)) case REMOVE_FS_ENTITY_MEMBERS: if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil { return } if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil { return } err = zfh.RemoveFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{})) case string(ZONE_FS_WEBRTC_OFFER): if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil { return } err = zfh.ConnectToFSInstance(req.Payload["channelId"].(string), req.Payload["userId"].(string), req.Payload["sdp"].(string)) case string(ZONE_FS_WEBRTC_COUNTER_OFFER): logger.Println("handling fs instance counter offer") if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil { return } err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { err = zfh.FSInstance.HandleCounterOffer(context.Background(), req.Payload["userId"].(string), zfh.sendDataChannelMessage) return }) case string(ZONE_FS_WEBRTC_RENNEGOTIATION_OFFER): if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil { return } err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { err = zfh.FSInstance.HandleRennegotiationOffer(req.Payload["userId"].(string), req.Payload["sdp"].(string), zfh.sendDataChannelMessage) return }) case string(ZONE_FS_WEBRTC_RENNEGOTIATION_ANSWER): if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil { return } err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { err = zfh.FSInstance.HandleRennegotiationAnswer(req.Payload["userId"].(string), req.Payload["sdp"].(string)) return }) case string(ZONE_FS_WEBRTC_CANDIDATE): logger.Println("handling fs instance webrtc candidate") logger.Println(req.Payload) if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil { return } logger.Println(req.Payload) i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string)) if convErr != nil { return convErr } SDPMLineIndex := uint16(i) sdpMid := req.Payload["sdpMid"].(string) logger.Println(sdpMid, SDPMLineIndex) err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) { err = zfh.FSInstance.AddCandidate(&webrtc.ICECandidateInit{ Candidate: req.Payload["candidate"].(string), SDPMid: &sdpMid, SDPMLineIndex: &SDPMLineIndex, }, req.Payload["userId"].(string)) return }) default: logger.Println("got your request in zone file handler", req) return } return }