Skip to content
This repository has been archived by the owner on Nov 2, 2020. It is now read-only.

Commit

Permalink
feat(Torrent): Save Torrent File Structure in Table torrents
Browse files Browse the repository at this point in the history
We may not need to save torrent's file structure in redis , just deal it
when they upload their torrent
  • Loading branch information
Rhilip committed Feb 7, 2019
1 parent 5bffbd9 commit 96e110e
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 88 deletions.
98 changes: 14 additions & 84 deletions apps/models/Torrent.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Torrent
private $torrent_name;
private $torrent_type;
private $torrent_size;
private $torrent_structure;

const TORRENT_TYPE_SINGLE = 'single';
const TORRENT_TYPE_MULTI = 'multi';
Expand Down Expand Up @@ -231,95 +232,24 @@ public function getUplver()
return $this->uplver;
}

/**
* if $type is "list" (Or other value not `tree`), we will return the default list like:
*
* [
* ["filename" => "f1/f2.text" , "size" => 1234],
* ["filename" => "f1/f3.text" , "size" => 2234],
* ]
*
* elseif $type is "tree" , the return array is like this when it's `single` torrent
*
* [
* "f1.text" => 1234
* ]
*
* And will convert to `tree` like this when it's `multi` torrent by using the
* private static function getFileTree($array, $delimiter = '/')
*
* [
* "f1" => [
* "f2.text" => 1234,
* "f3.text" => 2234
* ]
* ]
*
* Each result will be cached in redis since it will never change.
*
* @param string $type enum("list","tree") The format of fileList
* @return array|bool|string
*/
public function getFileList($type = "list")
public function getFileList($type = 'list')
{
if (!in_array($type, ["list", "tree"]))
$type = "list";

$list = app()->redis->get("TORRENT:" . $this->id . ":file_list");
if ($list === false) {
$list = app()->pdo->createCommand("SELECT `filename`,`size` FROM `files` WHERE `torrent_id` = :tid ORDER BY `filename` ASC;")->bindParams([
"tid" => $this->id
])->queryAll();
app()->redis->set("TORRENT:" . $this->id . ":file_list", $list);
}

if ($type == "tree") {
$tree = app()->redis->get("TORRENT:" . $this->id . ":file_list_tree");
if ($tree === false) {
$tree = array_column($list, 'size', 'filename');
if (!in_array($type, ['list', 'tree']))
$type = 'list';

// Only when Torrent Type is "multi" , We need to use `getFileTree` to convert file list to tree
if ($this->getTorrentType() == self::TORRENT_TYPE_MULTI) {
$tree = [$this->getTorrentName() => self::getFileTree($tree)];
}

app()->redis->set("TORRENT:" . $this->id . ":file_list_tree", $tree);
}
return $tree;
}

return $list;
}

private static function getFileTree($array, $delimiter = '/')
{
if (!is_array($array)) return array();

$splitRE = '/' . preg_quote($delimiter, '/') . '/';
$returnArr = array();
foreach ($array as $key => $val) {
// Get parent parts and the current leaf
$parts = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY);
$leafPart = array_pop($parts);

// Build parent structure
// Might be slow for really deep and large structures
$parentArr = &$returnArr;
foreach ($parts as $part) {
if (!isset($parentArr[$part])) {
$parentArr[$part] = array();
} elseif (!is_array($parentArr[$part])) {
$parentArr[$part] = array();
}
$parentArr = &$parentArr[$part];
if ($type == 'tree') {
return json_decode($this->torrent_structure, true);
} else {
$list = app()->redis->get('TORRENT:' . $this->id . ':file_list');
if ($list === false) {
$list = app()->pdo->createCommand("SELECT `filename`,`size` FROM `files` WHERE `torrent_id` = :tid ORDER BY `filename` ASC;")->bindParams([
"tid" => $this->id
])->queryAll();
app()->redis->set('TORRENT:' . $this->id . ':file_list', $list);
}

// Add the final part to the structure
if (empty($parentArr[$leafPart])) {
$parentArr[$leafPart] = $val;
}
return $list;
}
return $returnArr;
}

/**
Expand Down
70 changes: 68 additions & 2 deletions apps/models/form/TorrentUploadForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ class TorrentUploadForm extends Validator
private $torrent_dict;
private $torrent_name; // the $torrent_dict['info']['name'] field
private $torrent_list = []; // the file list like ["filename" => "example.txt" , "size" => 12345]
private $torrent_structure = [];
private $torrent_type = 'single'; // only in ['single','multi']
private $torrent_size = 0; // the count of torrent's content size

const TORRENT_TYPE_SINGLE = 'single';
const TORRENT_TYPE_MULTI = 'multi';


// 规则
public static function rules()
{
Expand Down Expand Up @@ -113,6 +118,7 @@ public function isValidTorrent(ExecutionContextInterface $context, $payload)
}

$this->torrent_name = $info['name'];
$this->torrent_structure = $this->getFileTree();
}

public function makePrivateTorrent()
Expand Down Expand Up @@ -168,17 +174,18 @@ public function flush()
'status' => $this->status,
'title' => $this->title,
'subtitle' => $this->subtitle,
'category' => 1, // FIXME add category support
'filename' => $this->file->getBaseName(),
'torrent_name' => $this->torrent_name,
'torrent_type' => $this->torrent_type,
'torrent_size' => $this->torrent_size,
'torrent_structure' => $this->torrent_structure,
'descr' => $this->descr,
'uplver' => $this->uplver,
])->execute();
$this->id = app()->pdo->getLastInsertId();

// Insert files table
app()->pdo->delete('files', [['torrent_id', '=', $this->id]])->execute();
app()->pdo->batchInsert('files', $this->torrent_list)->execute();

$this->setBuff();
Expand All @@ -192,7 +199,7 @@ public function flush()
app()->pdo->commit();
} catch (\Exception $e) {
app()->pdo->rollback();
if ($this->id != 0) {
if (isset($dump_status) && $dump_status == false) {
unlink(Torrent::TorrentFileLoc($this->id));
}

Expand All @@ -216,6 +223,65 @@ private function setBuff()

}

/**
* the return array is like this when it's `single` torrent
*
* [
* "f1.text" => 1234
* ]
*
* And will convert to `tree` like this when it's `multi` torrent by using the
* private static function makeFileTree($array, $delimiter = '/')
*
* [
* "f1" => [
* "f2.text" => 1234,
* "f3.text" => 2234
* ]
* ]
*
* Each result will be cached in redis since it will never change.
*
* @return bool|string
*/
private function getFileTree() {
$structure = array_column($this->torrent_list, 'size', 'filename');
if ($this->torrent_type == self::TORRENT_TYPE_MULTI) {
$structure = [$this->torrent_name => self::makeFileTree($structure)];
}
return json_encode($structure);
}

private static function makeFileTree($array, $delimiter = '/')
{
if (!is_array($array)) return array();

$splitRE = '/' . preg_quote($delimiter, '/') . '/';
$returnArr = array();
foreach ($array as $key => $val) {
// Get parent parts and the current leaf
$parts = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY);
$leafPart = array_pop($parts);

// Build parent structure
// Might be slow for really deep and large structures
$parentArr = &$returnArr;
foreach ($parts as $part) {
if (!isset($parentArr[$part])) {
$parentArr[$part] = array();
} elseif (!is_array($parentArr[$part])) {
$parentArr[$part] = array();
}
$parentArr = &$parentArr[$part];
}

// Add the final part to the structure
if (empty($parentArr[$leafPart])) {
$parentArr[$leafPart] = $val;
}
}
return $returnArr;
}

/**
* @param $dict
Expand Down
5 changes: 3 additions & 2 deletions migration/ridpt.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: Feb 03, 2019 at 08:50 AM
-- Generation Time: Feb 07, 2019 at 08:27 AM
-- Server version: 8.0.14
-- PHP Version: 7.3.1

Expand Down Expand Up @@ -483,13 +483,14 @@ CREATE TABLE IF NOT EXISTS `torrents` (
`torrent_name` varchar(255) NOT NULL DEFAULT '',
`torrent_type` enum('single','multi') NOT NULL DEFAULT 'multi',
`torrent_size` bigint(20) NOT NULL DEFAULT '0',
`torrent_structure` json NOT NULL,
`descr` text,
`uplver` enum('yes','no') NOT NULL DEFAULT 'no',
PRIMARY KEY (`id`),
UNIQUE KEY `info_hash` (`info_hash`),
KEY `FK_torrent_categories` (`category`),
KEY `FK_torrent_owner` (`owner_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT;

--
-- RELATIONSHIPS FOR TABLE `torrents`:
Expand Down

0 comments on commit 96e110e

Please sign in to comment.