Skip to content

Commit

Permalink
Experimental redis-based storage backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
TCB13 committed Sep 17, 2019
1 parent d79c59a commit 9ed1329
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 7 deletions.
6 changes: 2 additions & 4 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,11 @@ protected function handlePATCH(): ResponseInterface
// Detect when the upload is complete
$cache = $this->backend->containerFetch($this->file);
if ($cache->length <= $localSize) {
// Remove the cache container, we don't need
// it anymore
// Remove the cache container, we don't need it anymore
$this->backend->containerDelete($this->file);
// Extension Thunder TUS CrossCheck: verify if the uploaded file is as expected or delete it
if ($this->extCrossCheck) {
$localChecksum = $this->backend->getHash($this->file, $cache->checksum->algorithm);
if ($localChecksum !== $cache->checksum->value) {
if (!$this->backend->hashMatch($this->file, $cache->checksum->algorithm, $cache->checksum->value)) {
$this->backend->delete($this->file);
return $this->response->withStatus(410);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Store/FileSystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ public function getSize(string $name): int
return filesize($this->uploadDir . $name);
}

public function getHash(string $name, string $algo): string
public function hashMatch(string $name, string $algo, string $expectedHash): bool
{
return base64_encode(hash_file($algo, $this->uploadDir . $name, true));
return base64_encode(hash_file($algo, $this->uploadDir . $name, true)) === $expectedHash;
}

public function append(string $name, $data): bool
Expand Down
116 changes: 116 additions & 0 deletions src/Store/Redis.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

namespace ThunderTUS\Store;

use Predis\ClientInterface;

class Redis implements StoreInterface
{
/** @var RedisClient */
private $client;

private static $prefix = "tus:";
private static $containerPrefix = "tuscontainer:";
private static $tusExpire = 3600;

public function __construct(ClientInterface $client)
{
$this->client = $client;
}

public function setTUSKeysPrefix(string $prefix): void
{
static::$prefix = $prefix . ":";
static::$containerPrefix = $prefix . "container:";
}

public function setUploadTTL(int $ttlSeconds): void
{
static::$tusExpire = $ttlSeconds;
}

public function get(string $name): ?string
{
return $this->client->get(static::$prefix . $name);
}

public static function downloadIntoLocalFolder(ClientInterface $client, string $destinationDirectory, string $name): bool
{
$storage = new static($client);
$data = $storage->get($name);
if ($data === null) {
return false;
}

$destinationDirectory = rtrim($destinationDirectory, "/") . "/";
$result = file_put_contents($destinationDirectory . $name, $data);
if ($result === false) {
return false;
}

$storage->delete($name);
return true;
}

/** Implement StoreInterface */
public function exists(string $name): bool
{
return $this->client->exists(static::$prefix . $name) === 1;
}

public function create(string $name): bool
{
return $this->client->setex(static::$prefix . $name, self::$tusExpire, "") == "OK";
}

public function getSize(string $name): int
{
//return ((int)$this->client->bitcount(static::$prefix . $name))/8;
return (int)$this->client->strlen(static::$prefix . $name);
}

public function hashMatch(string $name, string $algo, string $expectedHash): bool
{
// Redis backend storage doesn't support efficient hashing.
// Hashing is only used in the custom CrossCheck extension implemented by
// thunder-tus-php. This isn't a part of the TUS protocol, so it can be skipped safely.
return true;
}

public function append(string $name, $data): bool
{
$result = $this->client->append(static::$prefix . $name, stream_get_contents($data));
return $result;
}

public function delete(string $name): bool
{
return $this->client->del([self::$prefix . $name]);
}

public function containerExists(string $name): bool
{
return $this->client->exists(static::$containerPrefix . $name) == 1;
}

public function containerCreate(string $name, ?\stdClass $data = null): bool
{
return $this->client->setex(static::$containerPrefix . $name, self::$tusExpire, \json_encode($data)) == "OK";
}

public function containerUpdate(string $name, \stdClass $data): bool
{
return $this->containerCreate($name, $data);
}

public function containerFetch(string $name): \stdClass
{
return \json_decode($this->client->get(static::$containerPrefix . $name));
}

public function containerDelete(string $name): bool
{
return $this->client->del([self::$containerPrefix . $name]);
}

}
2 changes: 1 addition & 1 deletion src/Store/StoreInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface StoreInterface
public function exists(string $name): bool;
public function create(string $name): bool;
public function getSize(string $name): int;
public function getHash(string $name, string $algo): string;
public function hashMatch(string $name, string $algo, string $expectedHash): bool;
public function append(string $name, $data): bool;
public function delete(string $name): bool;

Expand Down

0 comments on commit 9ed1329

Please sign in to comment.