sftp optimize file_put_contents, writeStream and copy

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2023-08-29 22:15:12 +02:00
parent 9cf732a90b
commit 1dfef9fccf
No known key found for this signature in database
GPG key ID: 42B69D8A64526EFB

View file

@ -36,15 +36,18 @@
*/
namespace OCA\Files_External\Lib\Storage;
use Icewind\Streams\CountWrapper;
use Icewind\Streams\IteratorDirectory;
use Icewind\Streams\RetryWrapper;
use OC\Files\Filesystem;
use OC\Files\Storage\Common;
use phpseclib\Net\SFTP\Stream;
/**
* Uses phpseclib's Net\SFTP class and the Net\SFTP\Stream stream wrapper to
* provide access to SFTP servers.
*/
class SFTP extends \OC\Files\Storage\Common {
class SFTP extends Common {
private $host;
private $user;
private $root;
@ -57,6 +60,8 @@ class SFTP extends \OC\Files\Storage\Common {
*/
protected $client;
const COPY_CHUNK_SIZE = 8 * 1024 * 1024;
/**
* @param string $host protocol://server:port
* @return array [$server, $port]
@ -478,4 +483,53 @@ class SFTP extends \OC\Files\Storage\Common {
$url = 'sftp://' . urlencode($this->user) . '@' . $this->host . ':' . $this->port . $this->root . $path;
return $url;
}
public function file_put_contents($path, $data) {
$result = $this->getConnection()->put($this->absPath($path), $data);
if ($result) {
return strlen($data);
} else {
return false;
}
}
public function writeStream(string $path, $stream, int $size = null): int {
if ($size === null) {
$stream = CountWrapper::wrap($stream, function ($writtenSize) use (&$size) {
$size = $writtenSize;
});
}
$result = $this->getConnection()->put($this->absPath($path), $stream);
fclose($stream);
if ($result) {
return $size;
} else {
throw new \Exception("Failed to write steam to sftp storage");
}
}
public function copy($source, $target) {
if ($this->is_dir($source) || $this->is_dir($target)) {
return parent::copy($source, $target);
} else {
$absSource = $this->absPath($source);
$absTarget = $this->absPath($target);
$connection = $this->getConnection();
$size = $connection->size($absSource);
if ($size === false) {
return false;
}
for ($i = 0; $i < $size; $i += self::COPY_CHUNK_SIZE) {
$chunk = $connection->get($absSource, false, $i, self::COPY_CHUNK_SIZE);
if ($chunk === false) {
return false;
}
if (!$connection->put($absTarget, $chunk, \phpseclib\Net\SFTP::SOURCE_STRING, $i)) {
return false;
}
}
return true;
}
}
}