Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Also accept io.Channel instances for up- and downloading #8

Merged
merged 4 commits into from
Sep 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,12 @@ Client

```php
use peer\ftp\{FtpConnection, FtpTransfer};
use io\streams\FileInputStream;
use io\File;

$c= (new FtpConnection('ftp://user:[email protected]/'))->connect();

// Upload index.txt to the connection's root directory
$c->rootDir()->file('index.txt')->uploadFrom(
new FileInputStream(new File('index.txt')),
FtpTransfer::ASCII
);
$c->rootDir()->file('index.txt')->uploadFrom(new File('index.txt'), FtpTransfer::ASCII);

$c->close();
```
Expand Down
22 changes: 15 additions & 7 deletions src/main/php/peer/ftp/FtpDownload.class.php
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
<?php namespace peer\ftp;

use io\Channel;
use io\streams\OutputStream;
use lang\IllegalArgumentException;

/**
* Represents an download
*
* @see xp://peer.ftp.FtpFile#downloadTo
* @see peer.ftp.FtpFile::downloadTo()
*/
class FtpDownload extends FtpTransfer {
protected $out= null;

/**
* Constructor
*
* @param peer.ftp.FtpFile remote
* @param io.streams.OutputStream out
* @param peer.ftp.FtpFile $remote
* @param io.streams.OutputStream|io.Channel $target
*/
public function __construct(FtpFile $remote= null, OutputStream $out) {
public function __construct(FtpFile $remote= null, $target) {
$this->remote= $remote;
$this->out= $out;
if ($target instanceof OutputStream) {
$this->out= $target;
} else if ($target instanceof Channel) {
$this->out= $target->out();
} else {
throw new IllegalArgumentException('Expected either an output stream or a channel, have '.typeof($source));
}
}

/**
* Creates a new FtpDownload instance without a remote file
*
* @see xp://peer.ftp.FtpFile#start
* @param io.streams.OutputStream out
* @see peer.ftp.FtpFile::start()
* @param io.streams.OutputStream|io.Channel $target
*/
public static function to(OutputStream $out) {
return new self(null, $out);
Expand Down
11 changes: 5 additions & 6 deletions src/main/php/peer/ftp/FtpFile.class.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?php namespace peer\ftp;

use io\Channel;
use io\streams\{InputStream, OutputStream, Streams};

/**
* FTP file
Expand Down Expand Up @@ -81,13 +80,13 @@ public function refresh($state) {
/**
* Upload to this file from an input stream
*
* @param io.streams.InputStream in
* @param io.streams.InputStream|io.Channel in
* @param int mode default FtpTransfer::ASCII
* @param peer.ftp.FtpTransferListener listener default NULL
* @return peer.ftp.FtpFile this file
* @throws peer.SocketException in case of an I/O error
*/
public function uploadFrom(InputStream $in, $mode= FtpTransfer::ASCII, FtpTransferListener $listener= null) {
public function uploadFrom($in, $mode= FtpTransfer::ASCII, FtpTransferListener $listener= null) {
$transfer= (new FtpUpload($this, $in))->withListener($listener)->start($mode);
while (!$transfer->complete()) $transfer->perform();

Expand Down Expand Up @@ -120,13 +119,13 @@ public function start(FtpTransfer $transfer, $mode= FtpTransfer::ASCII) {
/**
* Download this file to an output stream
*
* @param io.streams.OutputStream out
* @param io.streams.OutputStream|io.Channel out
* @param int mode default FtpTransfer::ASCII
* @param peer.ftp.FtpTransferListener listener default NULL
* @return io.streams.OutputStream the output stream passed
* @throws peer.SocketException in case of an I/O error
*/
public function downloadTo(OutputStream $out, $mode= FtpTransfer::ASCII, FtpTransferListener $listener= null) {
public function downloadTo($out, $mode= FtpTransfer::ASCII, FtpTransferListener $listener= null) {
$transfer= (new FtpDownload($this, $out))->withListener($listener)->start($mode);
while (!$transfer->complete()) $transfer->perform();

Expand All @@ -136,6 +135,6 @@ public function downloadTo(OutputStream $out, $mode= FtpTransfer::ASCII, FtpTran
$in->toString(), $this->name, $mode
));
}
return $out;
return $transfer->outputStream();
}
}
31 changes: 20 additions & 11 deletions src/main/php/peer/ftp/FtpUpload.class.php
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
<?php namespace peer\ftp;

use io\streams\InputStream;
use io\{Channel, IOException};
use lang\IllegalArgumentException;

/**
* Represents an upload
*
* @see xp://peer.ftp.FtpFile#uploadFrom
* @purpose FtpTransfer implementation
* @see peer.ftp.FtpFile::uploadFrom()
*/
class FtpUpload extends FtpTransfer {
protected $in = null;
protected $in;

/**
* Constructor
*
* @param peer.ftp.FtpFile remote
* @param io.streams.InputStream in
* @param peer.ftp.FtpFile $remote
* @param io.streams.InputStream|io.Channel $source
* @throws lang.IllegalArgumentException
*/
public function __construct(FtpFile $remote= null, InputStream $in) {
public function __construct(FtpFile $remote= null, $source) {
$this->remote= $remote;
$this->in= $in;
if ($source instanceof InputStream) {
$this->in= $source;
} else if ($source instanceof Channel) {
$this->in= $source->in();
} else {
throw new IllegalArgumentException('Expected either an input stream or a channel, have '.typeof($source));
}
}

/**
* Creates a new FtpDownload instance without a remote file
*
* @see xp://peer.ftp.FtpFile#start
* @param io.streams.InputStream in
* @see peer.ftp.FtpFile::start()
* @param io.streams.InputStream|io.Channel $source
* @return self
*/
public static function from(InputStream $in) {
public static function from($in) {
return new self(null, $in);
}

Expand Down Expand Up @@ -67,7 +76,7 @@ protected function doTransfer() {
try {
$chunk= $this->in->read(8192);
$this->socket->write($chunk);
} catch (\io\IOException $e) {
} catch (IOException $e) {
$this->listener && $this->listener->failed($this, $e);
$this->close();
throw $e;
Expand Down
86 changes: 42 additions & 44 deletions src/test/php/peer/ftp/unittest/IntegrationTest.class.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php namespace peer\ftp\unittest;

use io\streams\{MemoryInputStream, MemoryOutputStream, Streams};
use io\{FileNotFoundException, IOException};
use io\{FileNotFoundException, IOException, TempFile};
use lang\{IllegalStateException, Throwable};
use peer\AuthenticationException;
use peer\ftp\{FtpConnection, FtpDir, FtpEntry, FtpEntryList, FtpFile};
Expand Down Expand Up @@ -36,6 +36,19 @@ public static function shutdown() {
$c->close();
}

/** @return iterable */
private function uploads() {
yield [new MemoryInputStream($this->name)];

$t= new TempFile();
$t->open(TempFile::READWRITE);
$t->write($this->name);
$t->seek(0, SEEK_SET);
yield [$t];
$t->close();
$t->unlink();
}

/**
* Sets up test case
*/
Expand Down Expand Up @@ -229,25 +242,17 @@ public function fileViaGetDir() {
$this->conn->rootDir()->getDir('htdocs')->getDir('index.html');
}

#[Test]
public function uploadFile() {
#[Test, Values('uploads')]
public function uploadFile($source) {
$this->conn->connect();

try {
$dir= $this->conn->rootDir()->getDir('htdocs');
$file= $dir->file('name.txt')->uploadFrom(new MemoryInputStream($this->name));
$file= $dir->file('name.txt')->uploadFrom($source);
$this->assertTrue($file->exists());
$this->assertEquals(strlen($this->name), $file->getSize());
$file->delete();
} catch (\lang\Throwable $e) {

// Unfortunately, try { } finally does not exist...
try {
$file && $file->delete();
} catch (\io\IOException $ignored) {
// Can't really do anything here
}
throw $e;
} finally {
isset($file) && $file->delete();
}
}

Expand All @@ -263,16 +268,8 @@ public function renameFile() {

$file= $dir->file('renamed.txt');
$this->assertTrue($file->exists(), 'Renamed file does not exist');
$file->delete();
} catch (\lang\Throwable $e) {

// Unfortunately, try { } finally does not exist...
try {
$file && $file->delete();
} catch (\io\IOException $ignored) {
// Can't really do anything here
}
throw $e;
} finally {
isset($file) && $file->delete();
}
}

Expand All @@ -290,21 +287,13 @@ public function moveFile() {

$file= $trash->file('name.txt');
$this->assertTrue($file->exists());
$file->delete();
} catch (\lang\Throwable $e) {

// Unfortunately, try { } finally does not exist...
try {
$file && $file->delete();
} catch (\io\IOException $ignored) {
// Can't really do anything here
}
throw $e;
} finally {
isset($file) && $file->delete();
}
}

#[Test]
public function downloadFile() {
public function download_to_stream() {
$this->conn->connect();

$m= $this->conn
Expand All @@ -317,6 +306,23 @@ public function downloadFile() {
$this->assertEquals("<html/>\n", $m->getBytes());
}

#[Test]
public function download_to_file() {
$this->conn->connect();
$f= new TempFile();
$f->open(TempFile::READWRITE);

$this->conn->rootDir()->getDir('htdocs')->getFile('index.html')->downloadTo($f);

$f->seek(0, SEEK_SET);
try {
$this->assertEquals("<html/>\n", $f->read(8));
} finally {
$f->close();
$f->unlink();
}
}

#[Test]
public function in() {
$this->conn->connect();
Expand Down Expand Up @@ -358,16 +364,8 @@ public function out() {

$this->assertTrue($file->exists());
$this->assertEquals(strlen($this->name), $file->getSize());
} finally {
$file->delete();
} catch (Throwable $e) {

// Unfortunately, try { } finally does not exist...
try {
$file && $file->delete();
} catch (IOException $ignored) {
// Can't really do anything here
}
throw $e;
}
}
}