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:

  1. Cancelling the operation
  2. Pausing the operation
  3. 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.