mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-14 04:20:49 +08:00
Merge remote-tracking branch 'origin/php8' into php8
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Events\NewsCreated;
|
||||
use App\Events\TorrentCreated;
|
||||
use App\Events\TorrentDeleted;
|
||||
use App\Events\TorrentUpdated;
|
||||
use App\Events\UserCreated;
|
||||
use App\Events\UserDestroyed;
|
||||
use App\Events\UserDisabled;
|
||||
use App\Events\UserEnabled;
|
||||
@@ -31,15 +32,18 @@ class FireEvent extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Fire a event, options: --name, --idKey --idKeyOld';
|
||||
protected $description = 'Fire an event, options: --name, --idKey --idKeyOld';
|
||||
|
||||
protected array $eventMaps = [
|
||||
"torrent_created" => ['event' => TorrentCreated::class, 'model' => Torrent::class],
|
||||
"torrent_updated" => ['event' => TorrentUpdated::class, 'model' => Torrent::class],
|
||||
"torrent_deleted" => ['event' => TorrentDeleted::class, 'model' => Torrent::class],
|
||||
|
||||
"user_created" => ['event' => UserCreated::class, 'model' => User::class],
|
||||
"user_destroyed" => ['event' => UserDestroyed::class, 'model' => User::class],
|
||||
"user_disabled" => ['event' => UserDisabled::class, 'model' => User::class],
|
||||
"user_enabled" => ['event' => UserEnabled::class, 'model' => User::class],
|
||||
|
||||
"news_created" => ['event' => NewsCreated::class, 'model' => News::class],
|
||||
];
|
||||
|
||||
@@ -69,6 +73,7 @@ class FireEvent extends Command
|
||||
}
|
||||
$result = call_user_func_array([$eventName, "dispatch"], $params);
|
||||
$log .= ", success call dispatch, result: " . var_export($result, true);
|
||||
publish_model_event($name, $model->id);
|
||||
} else {
|
||||
$log .= ", invalid argument to call, it should be instance of: " . Model::class;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,12 @@ use App\Repositories\UserRepository;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Notifications\Notification;
|
||||
use GeoIp2\Database\Reader;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Encryption\Encrypter;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -59,6 +61,7 @@ use NexusPlugin\Permission\Models\Role;
|
||||
use NexusPlugin\PostLike\PostLikeRepository;
|
||||
use NexusPlugin\StickyPromotion\Models\StickyPromotion;
|
||||
use NexusPlugin\StickyPromotion\Models\StickyPromotionParticipator;
|
||||
use NexusPlugin\Tracker\TrackerRepository;
|
||||
use NexusPlugin\Work\Models\RoleWork;
|
||||
use NexusPlugin\Work\WorkRepository;
|
||||
use PhpIP\IP;
|
||||
@@ -98,7 +101,8 @@ class Test extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
CleanupRepository::checkQueueFailedJobs();
|
||||
$result = \Nexus\Plugin\Plugin::listEnabled();
|
||||
dd($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace App\Console;
|
||||
|
||||
use App\Jobs\CheckCleanup;
|
||||
use App\Jobs\CheckQueueFailedJobs;
|
||||
use App\Jobs\MaintainPluginState;
|
||||
use App\Jobs\ManagePlugin;
|
||||
use App\Utils\ThirdPartyJob;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Scheduling\Event;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
@@ -41,6 +44,8 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->command('meilisearch:import')->weeklyOn(1, "03:00")->withoutOverlapping();
|
||||
$schedule->command('torrent:load_pieces_hash')->dailyAt("01:00")->withoutOverlapping();
|
||||
$schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping();
|
||||
$schedule->job(new ThirdPartyJob())->everyMinute()->withoutOverlapping();
|
||||
$schedule->job(new MaintainPluginState())->everyMinute()->withoutOverlapping();
|
||||
|
||||
$this->registerScheduleCleanup($schedule);
|
||||
}
|
||||
|
||||
39
app/Events/UserCreated.php
Normal file
39
app/Events/UserCreated.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class UserCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ?Model $model = null;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Model $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,32 @@
|
||||
<?php
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Filament\Widgets\AccountInfo;
|
||||
use App\Filament\Widgets\LatestTorrents;
|
||||
use App\Filament\Widgets\LatestUsers;
|
||||
use App\Filament\Widgets\SystemInfo;
|
||||
use App\Filament\Widgets\TorrentStat;
|
||||
use App\Filament\Widgets\TorrentTrend;
|
||||
use App\Filament\Widgets\UserClassStat;
|
||||
use App\Filament\Widgets\UserStat;
|
||||
use App\Filament\Widgets\UserTrend;
|
||||
|
||||
class Dashboard extends \Filament\Pages\Dashboard
|
||||
{
|
||||
protected ?string $maxContentWidth = 'full';
|
||||
|
||||
protected function getWidgets(): array
|
||||
{
|
||||
return [
|
||||
AccountInfo::class,
|
||||
LatestUsers::class,
|
||||
LatestTorrents::class,
|
||||
UserTrend::class,
|
||||
TorrentTrend::class,
|
||||
UserStat::class,
|
||||
UserClassStat::class,
|
||||
TorrentStat::class,
|
||||
SystemInfo::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ class TorrentStateResource extends Resource
|
||||
Tables\Actions\EditAction::make()->after(function () {
|
||||
do_log("cache_del: global_promotion_state");
|
||||
NexusDB::cache_del(Setting::TORRENT_GLOBAL_STATE_CACHE_KEY);
|
||||
do_log("publish_model_event: global_promotion_state_updated");
|
||||
publish_model_event("global_promotion_state_updated", 0);
|
||||
}),
|
||||
// Tables\Actions\DeleteAction::make(),
|
||||
])
|
||||
|
||||
@@ -117,9 +117,4 @@ class ViewExamUser extends ViewRecord
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getProgress()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var array<int, string>|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
protected $proxies = ['*'];
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
|
||||
68
app/Jobs/BuyTorrent.php
Normal file
68
app/Jobs/BuyTorrent.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\TorrentBuyLog;
|
||||
use App\Repositories\BonusRepository;
|
||||
use App\Repositories\TorrentRepository;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class BuyTorrent implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public int $userId;
|
||||
|
||||
public int $torrentId;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(int $userId, int $torrentId)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
$this->torrentId = $torrentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$logPrefix = sprintf("user: %s, torrent: %s", $this->userId, $this->torrentId);
|
||||
$torrentRep = new TorrentRepository();
|
||||
$userId = $this->userId;
|
||||
$torrentId = $this->torrentId;
|
||||
|
||||
$hasBuy = TorrentBuyLog::query()
|
||||
->where("uid", $userId)
|
||||
->where("torrent_id", $torrentId)
|
||||
->exists()
|
||||
;
|
||||
if ($hasBuy) {
|
||||
//标记购买成功
|
||||
do_log("$logPrefix, already bought");
|
||||
$torrentRep->addBuySuccessCache($userId, $torrentId);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$bonusRep = new BonusRepository();
|
||||
$bonusRep->consumeToBuyTorrent($this->userId, $this->torrentId);
|
||||
//标记购买成功
|
||||
do_log("$logPrefix, buy torrent success");
|
||||
$torrentRep->addBuySuccessCache($userId, $torrentId);
|
||||
} catch (\Throwable $throwable) {
|
||||
//标记购买失败,缓存 3600 秒,这个时间内不能再次购买
|
||||
do_log("$logPrefix, buy torrent fail: " . $throwable->getMessage(), "error");
|
||||
$torrentRep->addBuyFailCache($userId, $torrentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Nexus\Database\NexusDB;
|
||||
use Nexus\Nexus;
|
||||
@@ -55,6 +56,16 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
|
||||
public $timeout = 3600;
|
||||
|
||||
/**
|
||||
* 获取任务时,应该通过的中间件。
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function middleware()
|
||||
{
|
||||
return [new WithoutOverlapping($this->idRedisKey)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
@@ -63,7 +74,11 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
$beginTimestamp = time();
|
||||
$logPrefix = sprintf("[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s", $this->requestId, $this->beginUid, $this->endUid);
|
||||
$logPrefix = sprintf(
|
||||
"[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s, idStr: %s, idRedisKey: %s",
|
||||
$this->requestId, $this->beginUid, $this->endUid, $this->idStr, $this->idRedisKey
|
||||
);
|
||||
do_log("$logPrefix, job start ...");
|
||||
$haremAdditionFactor = Setting::get('bonus.harem_addition');
|
||||
$officialAdditionFactor = Setting::get('bonus.official_addition');
|
||||
$donortimes_bonus = Setting::get('bonus.donortimes');
|
||||
@@ -84,6 +99,8 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
$logFile = getLogFile("seed-bonus-points");
|
||||
do_log("$logPrefix, [GET_UID_REAL], count: " . count($results) . ", logFile: $logFile");
|
||||
$fd = fopen($logFile, 'a');
|
||||
$seedPointsUpdates = $seedPointsPerHourUpdates = $seedBonusUpdates = [];
|
||||
$logStr = "";
|
||||
foreach ($results as $userInfo)
|
||||
{
|
||||
$uid = $userInfo['id'];
|
||||
@@ -92,7 +109,7 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
$bonusLog = "[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_USER], user: $uid, seedBonusResult: " . nexus_json_encode($seedBonusResult);
|
||||
$all_bonus = $seedBonusResult['seed_bonus'];
|
||||
$bonusLog .= ", all_bonus: $all_bonus";
|
||||
if ($isDonor) {
|
||||
if ($isDonor && $donortimes_bonus != 0) {
|
||||
$all_bonus = $all_bonus * $donortimes_bonus;
|
||||
$bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus";
|
||||
}
|
||||
@@ -112,13 +129,17 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
$all_bonus += $medalAddition;
|
||||
$bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus";
|
||||
}
|
||||
do_log($bonusLog);
|
||||
$dividend = 3600 / $autoclean_interval_one;
|
||||
$all_bonus = $all_bonus / $dividend;
|
||||
$seed_points = $seedBonusResult['seed_points'] / $dividend;
|
||||
$updatedAt = now()->toDateTimeString();
|
||||
$sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seed_points_per_hour = {$seedBonusResult['seed_points']}, seedbonus = seedbonus + $all_bonus, seed_points_updated_at = '$updatedAt' where id = $uid limit 1";
|
||||
do_log("$bonusLog, query: $sql");
|
||||
NexusDB::statement($sql);
|
||||
// $updatedAt = now()->toDateTimeString();
|
||||
// $sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seed_points_per_hour = {$seedBonusResult['seed_points']}, seedbonus = seedbonus + $all_bonus, seed_points_updated_at = '$updatedAt' where id = $uid limit 1";
|
||||
// do_log("$bonusLog, query: $sql");
|
||||
// NexusDB::statement($sql);
|
||||
$seedPointsUpdates[] = sprintf("when %d then ifnull(seed_points, 0) + %f", $uid, $seed_points);
|
||||
$seedPointsPerHourUpdates[] = sprintf("when %d then %f", $uid, $seedBonusResult['seed_points']);
|
||||
$seedBonusUpdates[] = sprintf("when %d then seedbonus + %f", $uid, $all_bonus);
|
||||
if ($fd) {
|
||||
$log = sprintf(
|
||||
'%s|%s|%s|%s|%s|%s|%s|%s',
|
||||
@@ -126,16 +147,28 @@ class CalculateUserSeedBonus implements ShouldQueue
|
||||
$userInfo['seed_points'], number_format($seed_points, 1, '.', ''), number_format($userInfo['seed_points'] + $seed_points, 1, '.', ''),
|
||||
$userInfo['seedbonus'], number_format($all_bonus, 1, '.', ''), number_format($userInfo['seedbonus'] + $all_bonus, 1, '.', '')
|
||||
);
|
||||
fwrite($fd, $log . PHP_EOL);
|
||||
// fwrite($fd, $log . PHP_EOL);
|
||||
$logStr .= $log . PHP_EOL;
|
||||
} else {
|
||||
do_log("logFile: $logFile is not writeable!", 'error');
|
||||
}
|
||||
}
|
||||
$nowStr = now()->toDateTimeString();
|
||||
$sql = sprintf(
|
||||
"update users set seed_points = case id %s end, seed_points_per_hour = case id %s end, seedbonus = case id %s end, seed_points_updated_at = '%s' where id in (%s)",
|
||||
implode(" ", $seedPointsUpdates), implode(" ", $seedPointsPerHourUpdates), implode(" ", $seedBonusUpdates), $nowStr, $idStr
|
||||
);
|
||||
$result = NexusDB::statement($sql);
|
||||
if ($delIdRedisKey) {
|
||||
NexusDB::cache_del($this->idRedisKey);
|
||||
}
|
||||
fwrite($fd, $logStr);
|
||||
$costTime = time() - $beginTimestamp;
|
||||
do_log("$logPrefix, [DONE], cost time: $costTime seconds");
|
||||
do_log(sprintf(
|
||||
"$logPrefix, [DONE], update user count: %s, result: %s, cost time: %s seconds",
|
||||
count($seedPointsUpdates), var_export($result, true), $costTime
|
||||
));
|
||||
do_log("$logPrefix, sql: $sql", "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,10 @@ class LoadTorrentBoughtUsers implements ShouldQueue
|
||||
|
||||
private int $torrentId;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $timeout = 1800;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
|
||||
44
app/Jobs/MaintainPluginState.php
Normal file
44
app/Jobs/MaintainPluginState.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Nexus\Database\NexusDB;
|
||||
use Nexus\Plugin\Plugin;
|
||||
|
||||
class MaintainPluginState implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$enabled = Plugin::listEnabled();
|
||||
$key = "nexus_plugin_enabled";
|
||||
NexusDB::redis()->del($key);
|
||||
$nowStr = now()->toDateTimeString();
|
||||
foreach ($enabled as $name => $value) {
|
||||
NexusDB::redis()->hSet($key, $name, $nowStr);
|
||||
}
|
||||
do_log("$key: " . nexus_json_encode($enabled));
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
@@ -55,6 +56,16 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
|
||||
|
||||
public $timeout = 1800;
|
||||
|
||||
/**
|
||||
* 获取任务时,应该通过的中间件。
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function middleware()
|
||||
{
|
||||
return [new WithoutOverlapping($this->idRedisKey)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
@@ -63,7 +74,11 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
$beginTimestamp = time();
|
||||
$logPrefix = sprintf("[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_JOB], commonRequestId: %s, beginTorrentId: %s, endTorrentId: %s", $this->requestId, $this->beginTorrentId, $this->endTorrentId);
|
||||
$logPrefix = sprintf(
|
||||
"[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_JOB], commonRequestId: %s, beginTorrentId: %s, endTorrentId: %s, idStr: %s, idRedisKey: %s",
|
||||
$this->requestId, $this->beginTorrentId, $this->endTorrentId, $this->idStr, $this->idRedisKey
|
||||
);
|
||||
do_log("$logPrefix, job start ...");
|
||||
|
||||
$idStr = $this->idStr;
|
||||
$delIdRedisKey = false;
|
||||
@@ -76,44 +91,51 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
$torrentIdArr = explode(",", $idStr);
|
||||
foreach ($torrentIdArr as $torrentId) {
|
||||
if ($torrentId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$peerResult = NexusDB::table('peers')
|
||||
->where('torrent', $torrentId)
|
||||
->selectRaw("count(*) as count, seeder")
|
||||
->groupBy('seeder')
|
||||
->get()
|
||||
;
|
||||
$commentResult = NexusDB::table('comments')
|
||||
->where('torrent',$torrentId)
|
||||
->selectRaw("count(*) as count")
|
||||
->first()
|
||||
;
|
||||
$update = [
|
||||
'comments' => $commentResult && $commentResult->count !== null ? $commentResult->count : 0,
|
||||
'seeders' => 0,
|
||||
'leechers' => 0,
|
||||
];
|
||||
foreach ($peerResult as $item) {
|
||||
if ($item->seeder == 'yes') {
|
||||
$update['seeders'] = $item->count;
|
||||
} elseif ($item->seeder == 'no') {
|
||||
$update['leechers'] = $item->count;
|
||||
}
|
||||
}
|
||||
NexusDB::table('torrents')->where('id', $torrentId)->update($update);
|
||||
do_log("[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_TORRENT], [SUCCESS]: $torrentId => " . json_encode($update));
|
||||
//批量取,简单化
|
||||
$torrents = array();
|
||||
// $res = sql_query("SELECT torrent, seeder, COUNT(*) AS c FROM peers GROUP BY torrent, seeder where torrent in ($idStr)");
|
||||
$res = NexusDB::table("peers")
|
||||
->selectRaw("torrent, seeder, COUNT(*) AS c")
|
||||
->whereRaw("torrent in ($idStr)")
|
||||
->groupBy(['torrent', 'seeder'])
|
||||
->get();
|
||||
foreach ($res as $row) {
|
||||
if ($row->seeder == "yes")
|
||||
$key = "seeders";
|
||||
else
|
||||
$key = "leechers";
|
||||
$torrents[$row->torrent][$key] = $row->c;
|
||||
}
|
||||
|
||||
// $res = sql_query("SELECT torrent, COUNT(*) AS c FROM comments GROUP BY torrent where torrent in ($idStr)");
|
||||
$res = NexusDB::table("comments")
|
||||
->selectRaw("torrent, COUNT(*) AS c")
|
||||
->whereRaw("torrent in ($idStr)")
|
||||
->groupBy(['torrent'])
|
||||
->get();
|
||||
foreach ($res as $row) {
|
||||
$torrents[$row->torrent]["comments"] = $row->c;
|
||||
}
|
||||
$seedersUpdates = $leechersUpdates = $commentsUpdates = [];
|
||||
foreach ($torrentIdArr as $id) {
|
||||
$seedersUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["seeders"] ?? 0);
|
||||
$leechersUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["leechers"] ?? 0);
|
||||
$commentsUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["comments"] ?? 0);
|
||||
}
|
||||
$sql = sprintf(
|
||||
"update torrents set seeders = case id %s end, leechers = case id %s end, comments = case id %s end where id in (%s)",
|
||||
implode(" ", $seedersUpdates), implode(" ", $leechersUpdates), implode(" ", $commentsUpdates), $idStr
|
||||
);
|
||||
$result = NexusDB::statement($sql);
|
||||
if ($delIdRedisKey) {
|
||||
NexusDB::cache_del($this->idRedisKey);
|
||||
}
|
||||
$costTime = time() - $beginTimestamp;
|
||||
do_log(sprintf(
|
||||
"$logPrefix, [DONE], update torrent count: %s, cost time: %s seconds",
|
||||
count($torrentIdArr), $costTime
|
||||
"$logPrefix, [DONE], update torrent count: %s, result: %s, cost time: %s seconds",
|
||||
count($torrentIdArr), var_export($result, true), $costTime
|
||||
));
|
||||
do_log("$logPrefix, sql: $sql", "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
@@ -55,6 +56,16 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
|
||||
|
||||
public $timeout = 3600;
|
||||
|
||||
/**
|
||||
* 获取任务时,应该通过的中间件。
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function middleware()
|
||||
{
|
||||
return [new WithoutOverlapping($this->idRedisKey)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
@@ -63,9 +74,12 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
$beginTimestamp = time();
|
||||
$logPrefix = sprintf("[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s", $this->requestId, $this->beginUid, $this->endUid);
|
||||
$logPrefix = sprintf(
|
||||
"[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s, idStr: %s, idRedisKey: %s",
|
||||
$this->requestId, $this->beginUid, $this->endUid, $this->idStr, $this->idRedisKey,
|
||||
);
|
||||
do_log("$logPrefix, job start ...");
|
||||
|
||||
$count = 0;
|
||||
$idStr = $this->idStr;
|
||||
$delIdRedisKey = false;
|
||||
if (empty($idStr) && !empty($this->idRedisKey)) {
|
||||
@@ -76,33 +90,35 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
|
||||
do_log("$logPrefix, no idStr or idRedisKey", "error");
|
||||
return;
|
||||
}
|
||||
$uidArr = explode(",", $idStr);
|
||||
foreach ($uidArr as $uid) {
|
||||
if ($uid <= 0) {
|
||||
continue;
|
||||
}
|
||||
$sumInfo = NexusDB::table('snatched')
|
||||
->selectRaw('sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum')
|
||||
->where('userid', $uid)
|
||||
->first();
|
||||
if ($sumInfo && $sumInfo->seedtime_sum !== null) {
|
||||
$update = [
|
||||
'seedtime' => $sumInfo->seedtime_sum ?? 0,
|
||||
'leechtime' => $sumInfo->leechtime_sum ?? 0,
|
||||
'seed_time_updated_at' => Carbon::now()->toDateTimeString(),
|
||||
];
|
||||
NexusDB::table('users')
|
||||
->where('id', $uid)
|
||||
->update($update);
|
||||
do_log("[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_USER], [SUCCESS]: $uid => " . json_encode($update));
|
||||
$count++;
|
||||
}
|
||||
//批量取,简单化
|
||||
// $res = sql_query("select userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum from snatched group by userid where userid in ($idStr)");
|
||||
$res = NexusDB::table("snatched")
|
||||
->selectRaw("userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum")
|
||||
->whereRaw("userid in ($idStr)")
|
||||
->groupBy("userid")
|
||||
->get();
|
||||
$seedtimeUpdates = $leechTimeUpdates = [];
|
||||
$nowStr = now()->toDateTimeString();
|
||||
$count = 0;
|
||||
foreach ($res as $row) {
|
||||
$count++;
|
||||
$seedtimeUpdates = sprintf("when %d then %d", $row->userid, $row->seedtime_sum ?? 0);
|
||||
$leechTimeUpdates = sprintf("when %d then %d", $row->userid, $row->leechtime_sum ?? 0);
|
||||
}
|
||||
$sql = sprintf(
|
||||
"update users set seedtime = case id %s end, leechtime = case id %s end, seed_time_updated_at = '%s' where id in (%s)",
|
||||
implode(" ", $seedtimeUpdates), implode(" ", $leechTimeUpdates), $nowStr, $idStr
|
||||
);
|
||||
$result = NexusDB::statement($sql);
|
||||
if ($delIdRedisKey) {
|
||||
NexusDB::cache_del($this->idRedisKey);
|
||||
}
|
||||
$costTime = time() - $beginTimestamp;
|
||||
do_log("$logPrefix, [DONE], user total count: " . count($uidArr) . ", success update count: $count, cost time: $costTime seconds");
|
||||
do_log(sprintf(
|
||||
"$logPrefix, [DONE], update user count: %s, result: %s, cost time: %s seconds",
|
||||
$count, var_export($result, true), $costTime
|
||||
));
|
||||
do_log("$logPrefix, sql: $sql", "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -184,7 +184,8 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
protected $fillable = [
|
||||
'username', 'email', 'passhash', 'secret', 'stylesheet', 'editsecret', 'added', 'modcomment', 'enabled', 'status',
|
||||
'leechwarn', 'leechwarnuntil', 'page', 'class', 'uploaded', 'downloaded', 'clientselect', 'showclienterror', 'last_home',
|
||||
'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card', 'seed_points_per_hour'
|
||||
'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card',
|
||||
'seed_points_per_hour', 'passkey',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Http\Middleware\Locale;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
@@ -37,8 +38,11 @@ class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
global $plugin;
|
||||
$plugin->start();
|
||||
// JsonResource::withoutWrapping();
|
||||
DB::connection(config('database.default'))->enableQueryLog();
|
||||
$forceScheme = strtolower(env('FORCE_SCHEME'));
|
||||
if (env('APP_ENV') == "production" && in_array($forceScheme, ['https', 'http'])) {
|
||||
URL::forceScheme($forceScheme);
|
||||
}
|
||||
|
||||
Filament::serving(function () {
|
||||
Filament::registerNavigationGroups([
|
||||
|
||||
@@ -169,7 +169,10 @@ for k, v in pairs(batchList) do
|
||||
local isBatchKeyNew = false
|
||||
if batchKey == false then
|
||||
batchKey = v .. ":" .. ARGV[4]
|
||||
redis.call("SET", v, batchKey, "EX", ARGV[5])
|
||||
redis.call("SET", v, batchKey)
|
||||
if (k > 1) then
|
||||
redis.call("EXPIRE", v, ARGV[5])
|
||||
end
|
||||
isBatchKeyNew = true
|
||||
end
|
||||
local hashKey
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
class DashboardRepository extends BaseRepository
|
||||
{
|
||||
@@ -51,18 +52,26 @@ class DashboardRepository extends BaseRepository
|
||||
'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
'value' => DB::select(DB::raw('select version() as info'))[0]->info,
|
||||
];
|
||||
$name = 'os';
|
||||
// $name = 'os';
|
||||
// $result[$name] = [
|
||||
// 'name' => $name,
|
||||
// 'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
// 'value' => PHP_OS,
|
||||
// ];
|
||||
$name = 'redis_version';
|
||||
$result[$name] = [
|
||||
'name' => $name,
|
||||
'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
'value' => PHP_OS,
|
||||
'value' => NexusDB::redis()->info()['redis_version'],
|
||||
];
|
||||
|
||||
$name = 'server_software';
|
||||
$result[$name] = [
|
||||
'name' => $name,
|
||||
'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
'value' => $_SERVER['SERVER_SOFTWARE'] ?? '',
|
||||
];
|
||||
|
||||
$name = 'load_average';
|
||||
$result[$name] = [
|
||||
'name' => $name,
|
||||
|
||||
@@ -1327,32 +1327,4 @@ class ExamRepository extends BaseRepository
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function fixIndexUploadTorrentCount()
|
||||
{
|
||||
$page = 1;
|
||||
$size = 2000;
|
||||
$examUserTable = (new ExamUser())->getTable();
|
||||
$examProgressTable = (new ExamProgress())->getTable();
|
||||
while (true) {
|
||||
$offset = ($page - 1)*$size;
|
||||
$list = NexusDB::table($examProgressTable)
|
||||
->select("$examProgressTable.*, $examUserTable.created_at as exam_created_at")
|
||||
->join($examUserTable, "$examProgressTable.exam_user_id", "=", "$examUserTable.id", "left")
|
||||
->where("$examUserTable.status", ExamUser::STATUS_NORMAL)
|
||||
->where("$examProgressTable.index", Exam::INDEX_UPLOAD_TORRENT_COUNT)
|
||||
->limit($size)
|
||||
->offset($offset)
|
||||
->get()
|
||||
;
|
||||
if ($list->count() == 0) {
|
||||
do_log("page: $page, offset: $offset, no more data...");
|
||||
return;
|
||||
}
|
||||
foreach ($list as $item) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class SeedBoxRepository extends BaseRepository
|
||||
$params = $this->formatParams($params);
|
||||
$seedBoxRecord = SeedBoxRecord::query()->create($params);
|
||||
$this->clearCache();
|
||||
publish_model_event("seed_box_record_created", $seedBoxRecord->id);
|
||||
return $seedBoxRecord;
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@ class SeedBoxRepository extends BaseRepository
|
||||
$params = $this->formatParams($params);
|
||||
$model->update($params);
|
||||
$this->clearCache();
|
||||
publish_model_event("seed_box_record_updated", $id);
|
||||
return $model;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Http\Middleware\Locale;
|
||||
use App\Models\Invite;
|
||||
use App\Models\Message;
|
||||
use App\Models\News;
|
||||
@@ -503,4 +504,25 @@ class ToolRepository extends BaseRepository
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sendAlarmEmail(string $subjectTransKey, array $subjectTransContext, string $msgTransKey, array $msgTransContext): void
|
||||
{
|
||||
$receiverUid = get_setting("system.alarm_email_receiver");
|
||||
if (empty($receiverUid)) {
|
||||
$locale = Locale::getDefault();
|
||||
$subject = nexus_trans($subjectTransKey, $subjectTransContext, $locale);
|
||||
$msg = nexus_trans($msgTransKey, $msgTransContext, $locale);
|
||||
do_log(sprintf("%s - %s", $subject, $msg), "error");
|
||||
} else {
|
||||
$receiverUidArr = preg_split("/[\r\n\s,,]+/", $receiverUid);
|
||||
$users = User::query()->whereIn("id", $receiverUidArr)->get(User::$commonFields);
|
||||
foreach ($users as $user) {
|
||||
$locale = $user->locale;
|
||||
$subject = nexus_trans($subjectTransKey, $subjectTransContext, $locale);
|
||||
$msg = nexus_trans($msgTransKey, $msgTransContext, $locale);
|
||||
$result = $this->sendMail($user->email, $subject, $msg);
|
||||
do_log(sprintf("send msg: %s result: %s", $msg, var_export($result, true)), $result ? "info" : "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +36,23 @@ use Illuminate\Support\Str;
|
||||
use Nexus\Database\NexusDB;
|
||||
use Nexus\Imdb\Imdb;
|
||||
use Rhilip\Bencode\Bencode;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
class TorrentRepository extends BaseRepository
|
||||
{
|
||||
const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers:";
|
||||
const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers";
|
||||
|
||||
const BUY_FAIL_CACHE_KEY_PREFIX = "torrent_purchase_fails";
|
||||
|
||||
const PIECES_HASH_CACHE_KEY = "torrent_pieces_hash";
|
||||
|
||||
const BUY_STATUS_SUCCESS = 0;
|
||||
const BUY_STATUS_NOT_YET = -1;
|
||||
const BUY_STATUS_UNKNOWN = -2;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* fetch torrent list
|
||||
*
|
||||
@@ -334,13 +344,23 @@ class TorrentRepository extends BaseRepository
|
||||
public function encryptDownHash($id, $user): string
|
||||
{
|
||||
$key = $this->getEncryptDownHashKey($user);
|
||||
return (new Hashids($key))->encode($id);
|
||||
$payload = [
|
||||
'id' => $id,
|
||||
'exp' => time() + 3600
|
||||
];
|
||||
return JWT::encode($payload, $key, 'HS256');
|
||||
}
|
||||
|
||||
public function decryptDownHash($downHash, $user)
|
||||
{
|
||||
$key = $this->getEncryptDownHashKey($user);
|
||||
return (new Hashids($key))->decode($downHash);
|
||||
try {
|
||||
$decoded = JWT::decode($downHash, new Key($key, 'HS256'));
|
||||
return [$decoded->id];
|
||||
} catch (\Exception $e) {
|
||||
do_log("Invalid down hash: $downHash, " . $e->getMessage(), "error");
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private function getEncryptDownHashKey($user)
|
||||
@@ -752,15 +772,94 @@ HTML;
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function addBoughtUserToCache($torrentId, $uid)
|
||||
/**
|
||||
* 购买成功缓存,保存为 hash,一个种子一个 hash,永久有效
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return void
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function addBuySuccessCache($uid, $torrentId): void
|
||||
{
|
||||
NexusDB::redis()->hSet($this->getBoughtUserCacheKey($torrentId), $uid, 1);
|
||||
}
|
||||
|
||||
|
||||
private function getBoughtUserCacheKey($torrentId): string
|
||||
public function hasBuySuccessCache($uid, $torrentId): bool
|
||||
{
|
||||
return self::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentId;
|
||||
return NexusDB::redis()->hGet($this->getBoughtUserCacheKey($torrentId), $uid) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取购买种子的缓存状态
|
||||
*
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return int
|
||||
*/
|
||||
public function getBuyStatus($uid, $torrentId): int
|
||||
{
|
||||
//查询是否已经购买
|
||||
if ($this->hasBuySuccessCache($uid, $torrentId)) {
|
||||
return self::BUY_STATUS_SUCCESS;
|
||||
}
|
||||
//是否购买失败过
|
||||
$buyFailCount = $this->getBuyFailCache($uid, $torrentId);
|
||||
if ($buyFailCount > 0) {
|
||||
//根据失败次数,禁用下载权限并做提示等
|
||||
return $buyFailCount;
|
||||
}
|
||||
//不是成功或失败,直接返回未知
|
||||
return self::BUY_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加购买失败缓存, 结果累加
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return void
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function addBuyFailCache($uid, $torrentId): void
|
||||
{
|
||||
$key = $this->getBuyFailCacheKey($uid, $torrentId);
|
||||
$result = NexusDB::redis()->incr($key);
|
||||
if ($result == 1) {
|
||||
NexusDB::redis()->expire($key, 3600);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取失败缓存 ,结果是失败的次数
|
||||
*
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return int
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function getBuyFailCache($uid, $torrentId): int
|
||||
{
|
||||
return intval(NexusDB::redis()->get($this->getBuyFailCacheKey($uid, $torrentId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买成功缓存 key
|
||||
* @param $torrentId
|
||||
* @return string
|
||||
*/
|
||||
public function getBoughtUserCacheKey($torrentId): string
|
||||
{
|
||||
return sprintf("%s:%s", self::BOUGHT_USER_CACHE_KEY_PREFIX, $torrentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买失败缓存 key
|
||||
* @param int $userId
|
||||
* @param int $torrentId
|
||||
* @return string
|
||||
*/
|
||||
public function getBuyFailCacheKey(int $userId, int $torrentId): string
|
||||
{
|
||||
return sprintf("%s:%s:%s", self::BUY_FAIL_CACHE_KEY_PREFIX, $userId, $torrentId);
|
||||
}
|
||||
|
||||
public function addPiecesHashCache(int $torrentId, string $piecesHash): bool|int|\Redis
|
||||
|
||||
@@ -132,7 +132,8 @@ class UserRepository extends BaseRepository
|
||||
'stylesheet' => $setting['defstylesheet'],
|
||||
'added' => now()->toDateTimeString(),
|
||||
'status' => User::STATUS_CONFIRMED,
|
||||
'class' => $class
|
||||
'class' => $class,
|
||||
'passkey' => md5($username.date("Y-m-d H:i:s").$passhash)
|
||||
];
|
||||
$user = new User($data);
|
||||
if (!empty($params['id'])) {
|
||||
@@ -143,7 +144,7 @@ class UserRepository extends BaseRepository
|
||||
$user->id = $params['id'];
|
||||
}
|
||||
$user->save();
|
||||
|
||||
fire_event("user_created", $user);
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
85
app/Utils/MsgAlert.php
Normal file
85
app/Utils/MsgAlert.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
namespace App\Utils;
|
||||
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
final class MsgAlert {
|
||||
|
||||
private static ?self $instance = null;
|
||||
|
||||
private static array $alerts = [];
|
||||
|
||||
private string $redisKeyPrefix = "nexus_alerts";
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$redis = NexusDB::redis();
|
||||
$result = $redis->lRange($this->getListKey(), 0, 10);
|
||||
if (!empty($result)) {
|
||||
$nowTimestamp = time();
|
||||
$valid = [];
|
||||
foreach ($result as $item) {
|
||||
$arr = json_decode($item, true);
|
||||
if (is_array($arr) && $arr['deadline'] > $nowTimestamp) {
|
||||
$valid[$arr['name']] = $arr;
|
||||
} else {
|
||||
$redis->lRem($this->getListKey(), $item, 0);
|
||||
}
|
||||
}
|
||||
self::$alerts = $valid;
|
||||
}
|
||||
}
|
||||
|
||||
private function __clone()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function getInstance(): MsgAlert
|
||||
{
|
||||
if (isset(self::$instance)) {
|
||||
return self::$instance;
|
||||
}
|
||||
return self::$instance = new self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function add(string $name, int $deadline, string $text, string $url = "", string $color = "red"): void
|
||||
{
|
||||
if (!isset(self::$alerts[$name])) {
|
||||
$params = compact('name', 'deadline', 'text', 'url', 'color');
|
||||
self::$alerts[$name] = $params;
|
||||
NexusDB::redis()->rPush($this->getListKey(), json_encode($params));
|
||||
}
|
||||
}
|
||||
|
||||
private function getListKey(): string
|
||||
{
|
||||
return sprintf("%s:%s", $this->redisKeyPrefix, get_user_id());
|
||||
}
|
||||
|
||||
|
||||
public static function render(): void
|
||||
{
|
||||
$nowTimestamp = time();
|
||||
foreach (self::$alerts as $item) {
|
||||
if ($item['deadline'] > $nowTimestamp) {
|
||||
msgalert($item['url'] ?: '', $item['text'], $item['color'] ?: 'red');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function remove($name): void
|
||||
{
|
||||
foreach (self::$alerts as $item) {
|
||||
if ($item['name'] = $name) {
|
||||
unset(self::$alerts[$name]);
|
||||
NexusDB::redis()->lRem($this->getListKey(), json_encode($item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
70
app/Utils/ThirdPartyJob.php
Normal file
70
app/Utils/ThirdPartyJob.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use App\Jobs\BuyTorrent;
|
||||
use http\Exception\InvalidArgumentException;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Nexus\Database\NexusDB;
|
||||
use Nexus\Database\NexusLock;
|
||||
|
||||
final class ThirdPartyJob {
|
||||
private static string $queueKey = "nexus_third_party_job";
|
||||
|
||||
private static int $size = 20;
|
||||
|
||||
const JOB_BUY_TORRENT = "buyTorrent";
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$lockName = convertNamespaceToSnake(__METHOD__);
|
||||
$lock = new NexusLock($lockName, 600);
|
||||
if (!$lock->get()) {
|
||||
do_log("can not get lock: $lockName, return ...");
|
||||
return;
|
||||
}
|
||||
$list = NexusDB::redis()->lRange(self::$queueKey, 0, self::$size);
|
||||
$successCount = 0;
|
||||
foreach ($list as $item) {
|
||||
$data = json_decode($item, true);
|
||||
if (!empty($data['name'])) {
|
||||
$successCount++;
|
||||
match ($data['name']) {
|
||||
self::JOB_BUY_TORRENT => self::enqueueJobBuyTorrent($data),
|
||||
default => throw new InvalidArgumentException("invalid name: {$data['name']}")
|
||||
};
|
||||
} else {
|
||||
do_log(sprintf("%s no name, skip", $item), "error");
|
||||
}
|
||||
NexusDB::redis()->lRem(self::$queueKey, $item);
|
||||
}
|
||||
do_log(sprintf("success dispatch %s jobs", $successCount));
|
||||
$lock->release();
|
||||
}
|
||||
|
||||
public static function addBuyTorrent(int $userId, int $torrentId): void
|
||||
{
|
||||
$key = sprintf("%s:%s_%s", self::$queueKey, $userId, $torrentId);
|
||||
if (NexusDB::redis()->set($key, now()->toDateTimeString(), ['nx', 'ex' => 3600])) {
|
||||
$value = [
|
||||
'name' => self::JOB_BUY_TORRENT,
|
||||
'userId' => $userId,
|
||||
'torrentId' => $torrentId,
|
||||
];
|
||||
NexusDB::redis()->rPush(self::$queueKey, json_encode($value));
|
||||
do_log("success addBuyTorrent: $key", "debug");
|
||||
} else {
|
||||
do_log("no need to addBuyTorrent: $key", "debug");
|
||||
}
|
||||
}
|
||||
|
||||
private static function enqueueJobBuyTorrent(array $params): void
|
||||
{
|
||||
if (!empty($params['userId']) && !empty($params['torrentId'])) {
|
||||
$job = new BuyTorrent($params['userId'], $params['torrentId']);
|
||||
Queue::push($job);
|
||||
} else {
|
||||
do_log("no userId or torrentId: " . json_encode($params), "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user