Zippytal-Node/zoneFSHandler.go
2021-12-08 15:58:40 +01:00

1115 lines
36 KiB
Go

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(hostId 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)
}
}
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)
}
}
}
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 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 = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
return
}
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
}