-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of the new chunked upload - as specified in ht…
- Loading branch information
1 parent
8ad3df9
commit d137941
Showing
7 changed files
with
514 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
<?php | ||
|
||
namespace OCA\DAV\Upload; | ||
|
||
use Sabre\DAV\IFile; | ||
|
||
class AssemblyStream implements \Icewind\Streams\File { | ||
|
||
/** @var resource */ | ||
private $context; | ||
|
||
/** @var IFile[] */ | ||
private $nodes; | ||
|
||
/** @var int */ | ||
private $pos = 0; | ||
|
||
/** @var array */ | ||
private $sortedNodes; | ||
|
||
/** @var int */ | ||
private $size; | ||
|
||
/** | ||
* @param string $path | ||
* @param string $mode | ||
* @param int $options | ||
* @param string &$opened_path | ||
* @return bool | ||
*/ | ||
public function stream_open($path, $mode, $options, &$opened_path) { | ||
$this->loadContext('assembly'); | ||
|
||
// sort the nodes | ||
$nodes = $this->nodes; | ||
@usort($nodes, function(IFile $a, IFile $b) { | ||
return strcmp($a->getName(), $b->getName()); | ||
}); | ||
$this->nodes = $nodes; | ||
|
||
// build additional information | ||
$this->sortedNodes = []; | ||
$start = 0; | ||
foreach($this->nodes as $node) { | ||
$size = $node->getSize(); | ||
$name = $node->getName(); | ||
$this->sortedNodes[$name] = ['node' => $node, 'start' => $start, 'end' => $start + $size]; | ||
$start += $size; | ||
$this->size = $start; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* @param string $offset | ||
* @param int $whence | ||
* @return bool | ||
*/ | ||
public function stream_seek($offset, $whence = SEEK_SET) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @return int | ||
*/ | ||
public function stream_tell() { | ||
return $this->pos; | ||
} | ||
|
||
/** | ||
* @param int $count | ||
* @return string | ||
*/ | ||
public function stream_read($count) { | ||
|
||
list($node, $posInNode) = $this->getNodeForPosition($this->pos); | ||
if (is_null($node)) { | ||
return null; | ||
} | ||
$stream = $this->getStream($node); | ||
|
||
fseek($stream, $posInNode); | ||
$data = fread($stream, $count); | ||
$read = strlen($data); | ||
|
||
// update position | ||
$this->pos += $read; | ||
return $data; | ||
} | ||
|
||
/** | ||
* @param string $data | ||
* @return int | ||
*/ | ||
public function stream_write($data) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @param int $option | ||
* @param int $arg1 | ||
* @param int $arg2 | ||
* @return bool | ||
*/ | ||
public function stream_set_option($option, $arg1, $arg2) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @param int $size | ||
* @return bool | ||
*/ | ||
public function stream_truncate($size) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function stream_stat() { | ||
return []; | ||
} | ||
|
||
/** | ||
* @param int $operation | ||
* @return bool | ||
*/ | ||
public function stream_lock($operation) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function stream_flush() { | ||
return false; | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function stream_eof() { | ||
return $this->pos >= $this->size; | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function stream_close() { | ||
} | ||
|
||
|
||
/** | ||
* Load the source from the stream context and return the context options | ||
* | ||
* @param string $name | ||
* @return array | ||
* @throws \Exception | ||
*/ | ||
protected function loadContext($name) { | ||
$context = stream_context_get_options($this->context); | ||
if (isset($context[$name])) { | ||
$context = $context[$name]; | ||
} else { | ||
throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set'); | ||
} | ||
if (isset($context['nodes']) and is_array($context['nodes'])) { | ||
$this->nodes = $context['nodes']; | ||
} else { | ||
throw new \BadMethodCallException('Invalid context, nodes not set'); | ||
} | ||
return $context; | ||
} | ||
|
||
/** | ||
* @param IFile[] $nodes | ||
* @return resource | ||
* | ||
* @throws \BadMethodCallException | ||
*/ | ||
public static function wrap(array $nodes) { | ||
$context = stream_context_create([ | ||
'assembly' => [ | ||
'nodes' => $nodes] | ||
]); | ||
stream_wrapper_register('assembly', '\OCA\DAV\Upload\AssemblyStream'); | ||
try { | ||
$wrapped = fopen('assembly://', 'r', null, $context); | ||
} catch (\BadMethodCallException $e) { | ||
stream_wrapper_unregister('assembly'); | ||
throw $e; | ||
} | ||
stream_wrapper_unregister('assembly'); | ||
return $wrapped; | ||
} | ||
|
||
/** | ||
* @param $pos | ||
* @return IFile | null | ||
*/ | ||
private function getNodeForPosition($pos) { | ||
foreach($this->sortedNodes as $node) { | ||
if ($pos >= $node['start'] && $pos < $node['end']) { | ||
return [$node['node'], $pos - $node['start']]; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* @param IFile $node | ||
* @return mixed | ||
*/ | ||
private function getStream(IFile $node) { | ||
$data = $node->get(); | ||
if (is_resource($data)) { | ||
return $data; | ||
} | ||
|
||
return fopen('data://text/plain,' . $data,'r'); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
namespace OCA\DAV\Upload; | ||
|
||
use OCA\DAV\Connector\Sabre\Directory; | ||
use Sabre\DAV\Exception\Forbidden; | ||
use Sabre\DAV\IFile; | ||
|
||
class FutureFile implements \Sabre\DAV\IFile { | ||
|
||
function __construct(Directory $root, $name) { | ||
$this->root = $root; | ||
$this->name = $name; | ||
} | ||
|
||
function put($data) { | ||
throw new Forbidden('Permission denied to put into this file'); | ||
} | ||
|
||
function get() { | ||
$nodes = $this->root->getChildren(); | ||
return \OCA\DAV\Upload\AssemblyStream::wrap($nodes); | ||
} | ||
|
||
function getContentType() { | ||
return 'application/octet-stream'; | ||
} | ||
|
||
function getETag() { | ||
return $this->root->getETag(); | ||
} | ||
|
||
function getSize() { | ||
$children = $this->root->getChildren(); | ||
$sizes = array_map(function($node) { | ||
/** @var IFile $node */ | ||
return $node->getSize(); | ||
}, $children); | ||
|
||
return array_sum($sizes); | ||
} | ||
|
||
/** | ||
* Deleted the current node | ||
* | ||
* @throws Forbidden | ||
*/ | ||
function delete() { | ||
throw new Forbidden('Permission denied to delete this file'); | ||
} | ||
|
||
/** | ||
* Returns the name of the node. | ||
* | ||
* This is used to generate the url. | ||
* | ||
* @return string | ||
*/ | ||
function getName() { | ||
return $this->name; | ||
} | ||
|
||
/** | ||
* Renames the node | ||
* | ||
* @param string $name The new name | ||
* @return void | ||
*/ | ||
function setName($name) { | ||
throw new Forbidden('Permission denied to rename this file'); | ||
} | ||
|
||
/** | ||
* Returns the last modification time, as a unix timestamp | ||
* | ||
* @return int | ||
*/ | ||
function getLastModified() { | ||
return $this->root->getLastModified(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace OCA\DAV\Upload; | ||
|
||
use Sabre\DAVACL\AbstractPrincipalCollection; | ||
use Sabre\DAVACL\IPrincipal; | ||
|
||
class RootCollection extends AbstractPrincipalCollection { | ||
|
||
/** | ||
* This method returns a node for a principal. | ||
* | ||
* The passed array contains principal information, and is guaranteed to | ||
* at least contain a uri item. Other properties may or may not be | ||
* supplied by the authentication backend. | ||
* | ||
* @param array $principalInfo | ||
* @return IPrincipal | ||
*/ | ||
function getChildForPrincipal(array $principalInfo) { | ||
return new UploadHome($principalInfo); | ||
} | ||
|
||
function getName() { | ||
return 'upload'; | ||
} | ||
|
||
} |
Oops, something went wrong.