Skip to content

Cloud filesystem (s3, spaces) optimizations #754

@Plytas

Description

@Plytas

First of all, thank you for this package, really amazing work you put in so far.

That said, using cloud filesystem (s3, spaces) requires some optimizations, because right now it makes multiple requests for every LfmItem when trying to fill() the attributes. I've been playing around and managed to get the /jsonitems request with 20 folders and 1 image from over 1 min (it would timeout after 1 min) down to around 2 seconds. Here are my insights:

Avoid extra isDirectory() and isFile() requests

Right now isDirectory() does this weird check:

public function isDirectory()
{
    $working_dir = $this->path('working_dir');
    $parent_dir = substr($working_dir, 0, strrpos($working_dir, '/'));

    $parent_directories = array_map(function ($directory_path) {
        return app(static::class)->translateToLfmPath($directory_path);
    }, app(static::class)->dir($parent_dir)->directories());

    return in_array($this->path('url'), $parent_directories);
}

Since it's already making 2 different calls to filesystem to fetch folders and files separately, it can be implemented like this:

LfmPath.php

public function folders()
{
	$all_folders = array_map(function ($directory_path) {
		return $this->pretty($directory_path, true);
	}, $this->storage->directories());

	$folders = array_filter($all_folders, function ($directory) {
		return $directory->name !== $this->helper->getThumbFolderName();
	});

	return $this->sortByColumn($folders);
}

public function files()
{
	$files = array_map(function ($file_path) {
		return $this->pretty($file_path);
	}, $this->storage->files());

	return $this->sortByColumn($files);
}

public function pretty($item_path, bool $isDirectory = false)
{
	return Container::getInstance()->makeWith(LfmItem::class, [
		'lfm' => (clone $this)->setName($this->helper->getNameFromPath($item_path)),
		'helper' => $this->helper,
		'isDirectory' => $isDirectory
	]);
}

Note: I only added $isDirectory variable to pretty() function and passing true from folders() function.

LfmItem.php

class LfmItem
{
    private $lfm;
    private $helper;
    private $isDirectory;

    private $columns = ['name', 'url', 'time', 'icon', 'is_file', 'is_image', 'thumb_url'];
    public $attributes = [];

    public function __construct(LfmPath $lfm, Lfm $helper, bool $isDirectory = false)
    {
        $this->lfm = $lfm->thumb(false);
        $this->helper = $helper;
        $this->isDirectory = $isDirectory;
    }

...

    public function isDirectory()
    {
    	return $this->isDirectory;
    }

    public function isFile()
    {
        return ! $this->isDirectory();
    }

Folders do not need an isImage() check

This can be easily avoided adding an isFile() check first:
LfmItem.php

public function isImage()
{
	return $this->isFile() && starts_with($this->mimeType(), 'image');
}

Avoid extra mimeType() requests

Mime time request gets called at least 3 times when trying to fill is_mage, icon and thumb_url.
This can be optimized by including another private property $mimeType and requesting mimeType like this:

public function mimeType()
{
	if (is_null($this->mimeType))
		$this->mimeType = $this->lfm->mimeType();

	return $this->mimeType;
}

Note: I left out uploaded file comment since it was not implemented yet.

I've also removed time property (lastModified()) since I don't need it and it isn't visible in thumbnails mode.

These optimizations made this package somewhat usable with cloud disks. Further improvements are needed with files though, because they are still making a lot of requests for icons, thumbs and urls. IMO these can be optimized using lazy loading, by showing a generic file on load and then doing ajax requests and loading extra data separately. Also cache would be a nice boost in user experience, because right now when you navigate back to a folder you already were before, it has to load the same stuff again.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions