File System Interface - SilverEzhik/fmtest GitHub Wiki
We should define an interface for file system operations that'd be nice to support.
The way I see it, there are two types of operations in a File Manager:
FS-specific
Operations that involve actually interacting with the file system, such as copying and so on.
"meta" operations
Operations composed of these FS-specific operations, such as Undo/Redo. For example: Inverse of move is move (in the other direction). Inverse of copy is trash.
These are handled on the FM side, and so don't need to be defined per-FS.
The interface
FS navigation tools
Folder
A folder object is used to:
- Get contents of a folder
- Subscribe to updates to a folder
GetFolder(path string) (Folder, error)
type Folder interface {
Path() string
Contents() map[uid]File //need to decide what the uid actually is. uint64 in local fs
Watch() chan bool // ping channel if folder contents changed
Close() // get rid of a folder's watcher
}
File
File objects are used to get information about individual objects in the file system (including folders)
We only bother with basic features that FileInfo gives (name/size/last modify date/write permissions).
The file interface is a simpler version of the os.FileInfo interface. File permissions are an interesting story, and standard UNIX-style permissions are not flexible enough for things like cloud file systems.
For now, the approach is to completely omit permission management, besides checking for read/write permissions.
One possible approach for file permissions and per-FS settings, however, is to provide some simple building blocks that could allow file systems to provide simple UIs for managing those - this has to exist in some form either way for handling things like cloud authentication, for example. Cover a few basics - enough to flip some switches for the FS config and basic permission handling. Could also straight up allow web views for authentication and dealing with the complicated world of cloud sharing.
Remember, this is all for a GUI-based file manager platform.
Stat(path string) (File, error)
type File interface {
Name() string
Size() int64
ModTime() time.Time
IsDir() bool
}
File system operations and actions
Everything besides the navigation tools is based on file paths.
Copy and move
Moving/copying files in a GUI is done through copy/paste or drag and drop. You can have multiple files selected, yes, but there will be a single destination for them. So it would be nice to have file management functions that take in multiple source paths and one destination path. This does come with the problem of handling things like changing the name of the destination parameter.
For now, continuing with the idea of using pairs of source-destination paths.
Copy(files map[string]string) (<-chan IOStatus, chan<- OPStatus, error)
Move(files map[string]string) (<-chan IOStatus, chan<- OPStatus, error)
//Copy(files []string, destination string) (<-chan IOStatus, chan<- OPStatus, error)
//Move(files []string, destination string) (<-chan IOStatus, chan<- OPStatus, error)
Link(files map[string]string) // Create simple shortcuts to the files
Trash(filenames []string) (<-chan IOStatus, chan<- OPStatus, error) // Move to FS trash folder
Delete(filenames []string) (<-chan IOStatus, chan<- OPStatus, error) // Erase files for good
Mkdir(name string) error
Mechanisms are needed for communicating operation progress and handling things such as:
- Cancelling the operation
- Pausing the operation
- Resolving conflicts
// progress tracking
type IOUpdate struct {
Progress int // total progress %
Results map[string]string // get paths of whatever files emerged as a result of completing the operation
Status IOStatus // current status of the operation
// Report errors for individual files
CurrentFile string // get path of file currently worked on
FileProgress int // progress of this individual file %
Error error // need an error type
}
// Knowing currently copied file allows more granular progress reporting and displaying it in the FM.
// Knowing files created as result of an operation allows for undoing it.
// For getting the status of an ongoing operation
type IOStatus int
const (
Ongoing IOStatus = iota
Paused
Cancelled
Failed
Complete
)
// For interacting with an ongoing operation
type IOReply struct {
Action IOAction
Filename string
NewFilename string
}
type IOAction int
const (
Resume IOAction = iota
Pause
Cancel
Retry
RetryFile
SkipFile
RenameFile
)
File open/preview tools
Open and preview operations should also be done on FS level to some degree. For remote FS this'd allow fetching remote thumbnails (as opposed to whole file), or things like opening remote files by downloading them to a temporary directory, and saving by watching changes. Preview mechanisms are not defined yet, neither are mechanisms for opening files.
The open operation might need to be provided by the UI layer - this would make sense, and would allow cloud FS modules to not worry about cross-platform compatibility. This would also allow more granular handling of features such as opening multiple selected files as: app file1 file2 file3
(the correct way), versus app file1; app file2; app file3
(the Windows Explorer way).
On Linux, xdg-open
is stupid and doesn't support multiple arguments. xdg-mime
can tell the defaults, so this can be handled on UI level.
Open(filenames []string)
This can return a string of filenames specifically on the local FS to be opened by a UI-level mechanism.
Preview could in theory only accept images or raw text - then there is no need to worry about what can or can't be handled, as all UIs will be equipped to handle pngs and txt files. Up to FS to provide the actual previews, in this scenario (need to consider how the local FS is supposed to handle this).
Might be nice to have a mechanism for getting multiple images, lower-quality images, placeholders, and so on.
Preview(filename string) //returns some sort of preview object for FM->UI use
Cross-FS operation tools
For moving across filesystems, it might be interesting to use readers/writers. Doing this outside of FM is complicated and may not work all that well with the out-of-process IO that I would like to have at least for the local FS. This is not impossible, but it requires the out-of-process components be implemented on FM level.
That requires dealing with IPC'ing things such as remote connection credentials. This is not very fun.
However, the idea is that these will only be used to move data between filesystems. On FM level, can define a path system that deals with filesystems, then wrappers for IO functions, e.g. Mkdir("/home/user/newfolder")
will call the local FS Mkdir()
, while Mkdir("cloud://newfolder")
will call the cloud FS Mkdir()
.
The FM UI layer would not care about what functions to call, and would always just use the generic Copy, Move, Open, Preview, etc. functions, which will then make the necessary calls.
Then, in this case, in case of cross-FS actions, the FM layer handles all the conflicts, marshalling, and so on.
Download(filename string) //returns some Reader
Upload(filename string) //returns some Writer
For now, though, the focus is on getting the local FS to work.