作者 竞泽

add:session live

  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Command;
  4 +
  5 +use Illuminate\Console\Command;
  6 +use Lackoxygen\TiktokShop\Supervisor\Session\SessionHeart;
  7 +
  8 +class RefreshToken extends Command
  9 +{
  10 + /**
  11 + * The name and signature of the console command.
  12 + *
  13 + * @var string
  14 + */
  15 + protected $signature = 'tiktok-shop:refresh.token';
  16 +
  17 + /**
  18 + * The console command description.
  19 + *
  20 + * @var string
  21 + */
  22 + protected $description = 'The refresh tiktok shop token';
  23 +
  24 + /**
  25 + * Create a new command instance.
  26 + *
  27 + * @return void
  28 + */
  29 + public function __construct()
  30 + {
  31 + parent::__construct();
  32 + }
  33 +
  34 + /**
  35 + * Execute the console command.
  36 + *
  37 + * @return int
  38 + */
  39 + public function handle(): int
  40 + {
  41 + SessionHeart::new()->keepalive();
  42 +
  43 + return 0;
  44 + }
  45 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Contracts;
  4 +
  5 +interface SessionInterface
  6 +{
  7 + public function id(): string;
  8 +
  9 + public function unEffective(): bool;
  10 +
  11 + public function effective(): bool;
  12 +
  13 + public function discard();
  14 +
  15 + public function watch(): bool;
  16 +
  17 + public function appKey(): string;
  18 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Lackoxygen\TiktokShop\Util\Json;
  6 +
  7 +class Factory
  8 +{
  9 + protected \Closure $callback;
  10 +
  11 + public function __construct(\Closure $callback)
  12 + {
  13 + $this->callback = $callback;
  14 + }
  15 +
  16 + public function load(string $raw)
  17 + {
  18 + if (!$raw) {
  19 + return;
  20 + }
  21 + $array = Json::unmarshal($raw);
  22 +
  23 + $callback = $this->callback;
  24 + foreach ($array as $row) {
  25 + $callback($this->create($row));
  26 + }
  27 + }
  28 +
  29 + protected function create($row)
  30 + {
  31 + return unserialize($row);
  32 + }
  33 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Carbon\Carbon;
  6 +use Lackoxygen\TiktokShop\Contracts\SessionInterface;
  7 +
  8 +class Session implements SessionInterface
  9 +{
  10 + use Swap;
  11 +
  12 + protected Store $store;
  13 +
  14 + protected string $index = '';
  15 +
  16 + protected string $appKey = '';
  17 +
  18 + public function __construct(string $appKey, Store $store)
  19 + {
  20 + $this->appKey = $appKey;
  21 +
  22 + $this->store = $store;
  23 +
  24 + $this->index = $this->id();
  25 + }
  26 +
  27 + public function id(): string
  28 + {
  29 + return md5(serialize($this->store));
  30 + }
  31 +
  32 + public function unEffective(): bool
  33 + {
  34 + return !$this->effective();
  35 + }
  36 +
  37 + public function effective(): bool
  38 + {
  39 + return $this->store->getExpiredAt()->gt(Carbon::now());
  40 + }
  41 +
  42 + public function discard()
  43 + {
  44 + $this->store->setExpiredAt(Carbon::now()->subMinutes(30));
  45 + }
  46 +
  47 + public function watch(): bool
  48 + {
  49 + return $this->index !== $this->id();
  50 + }
  51 +
  52 + public function appKey(): string
  53 + {
  54 + return $this->appKey;
  55 + }
  56 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Illuminate\Cache\CacheManager;
  6 +use Lackoxygen\TiktokShop\Contracts\SessionInterface;
  7 +use Lackoxygen\TiktokShop\Util\Json;
  8 +
  9 +class SessionHeart
  10 +{
  11 + protected static ?SessionHeart $sessionHeart = null;
  12 +
  13 + protected CacheManager $cacheManager;
  14 +
  15 + public function __construct()
  16 + {
  17 + SessionMemory::init();
  18 + }
  19 +
  20 + public static function new(): SessionHeart
  21 + {
  22 + if (is_null(static::$sessionHeart)) {
  23 + static::$sessionHeart = new static;
  24 + }
  25 +
  26 + return static::$sessionHeart;
  27 + }
  28 +
  29 + public function keepalive()
  30 + {
  31 + SessionMemory::each(function (SessionInterface $session) {
  32 + if ($session->effective()) {
  33 + return;
  34 + }
  35 + $session->refresh();
  36 + });
  37 + }
  38 +
  39 + public function __destruct()
  40 + {
  41 + $watch = false;
  42 + $serializes = [];
  43 + SessionMemory::each(function (SessionInterface $session) use (&$watch, &$serializes) {
  44 + $serializes[] = serialize($session);
  45 + if (!$watch && $session->watch()) {
  46 + $watch = true;
  47 + }
  48 + });
  49 + if ($watch) {
  50 + SessionMemory::persistence(Json::marshal($serializes));
  51 + }
  52 + }
  53 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Lackoxygen\TiktokShop\Contracts\SessionInterface;
  6 +
  7 +class SessionMemory
  8 +{
  9 + /**
  10 + * @var Session [] $sessions
  11 + */
  12 + protected static array $sessions = [];
  13 +
  14 + /**
  15 + * @var string
  16 + */
  17 + protected static string $cachePrefix = 'tiktok.shop:session:';
  18 +
  19 +
  20 + protected static function cache()
  21 + {
  22 + static $cacheManager;
  23 + if (is_null($cacheManager)) {
  24 + $cacheManager = app('cache');
  25 + }
  26 +
  27 + return $cacheManager;
  28 + }
  29 +
  30 + public static function init()
  31 + {
  32 + $factory = new Factory(function (Session $session) {
  33 + static::$sessions[$session->appKey()] = $session;
  34 + });
  35 +
  36 + $factory->load(static::persistence());
  37 + }
  38 +
  39 + public static function persistence()
  40 + {
  41 + $key = static::$cachePrefix.'keepalive_table';
  42 + try {
  43 + if (func_get_args()) {
  44 + static::cache()->set($key, func_get_arg(0));
  45 + } else {
  46 + $raw = static::cache()->get($key);
  47 +
  48 + if (is_null($raw)) {
  49 + return null;
  50 + }
  51 +
  52 + return $raw;
  53 + }
  54 + } catch (\Exception $e) {
  55 + }
  56 + }
  57 +
  58 + public static function each(\Closure $callback)
  59 + {
  60 + foreach (static::$sessions as $session) {
  61 + $callback($session);
  62 + }
  63 + }
  64 +
  65 + public static function get(string $appKey = null)
  66 + {
  67 + if (is_null($appKey)) {
  68 + return static::$sessions;
  69 + }
  70 +
  71 + return static::exist($appKey) ? static::$sessions[$appKey] : null;
  72 + }
  73 +
  74 + public static function exist(string $appKey): bool
  75 + {
  76 + return array_key_exists($appKey, static::$sessions);
  77 + }
  78 +
  79 + public static function put(SessionInterface $session, $force = true)
  80 + {
  81 + if (static::exist($session->appKey()) && !$force) {
  82 + return;
  83 + }
  84 + static::$sessions[$session->appKey()] = $session;
  85 + }
  86 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Carbon\Carbon;
  6 +use Illuminate\Queue\SerializesModels;
  7 +
  8 +class Store
  9 +{
  10 + use SerializesModels;
  11 +
  12 + /**
  13 + * The ID.
  14 + *
  15 + * @var string
  16 + */
  17 + protected string $id;
  18 +
  19 + /**
  20 + * The access token.
  21 + *
  22 + * @var string
  23 + */
  24 + protected string $accessToken;
  25 +
  26 + /**
  27 + * The refresh token.
  28 + *
  29 + * @var string
  30 + */
  31 + protected string $refreshToken;
  32 +
  33 + /**
  34 + * The created at.
  35 + *
  36 + * @var Carbon
  37 + */
  38 + protected Carbon $createdAt;
  39 +
  40 + /**
  41 + * The expired at.
  42 + *
  43 + * @var Carbon
  44 + */
  45 + protected Carbon $expiredAt;
  46 +
  47 + /**
  48 + * The expires in.
  49 + *
  50 + * @var int
  51 + */
  52 + protected int $expiresIn;
  53 +
  54 + /**
  55 + * the more data.
  56 + *
  57 + * @var array
  58 + */
  59 + protected array $extras = [];
  60 +
  61 + /**
  62 + * the refresh num.
  63 + *
  64 + * @var int
  65 + */
  66 + protected int $refreshNum = 0;
  67 +
  68 + /**
  69 + * @return string
  70 + */
  71 + public function getId(): string
  72 + {
  73 + return $this->id;
  74 + }
  75 +
  76 + /**
  77 + * @param string $id
  78 + */
  79 + public function setId(string $id): void
  80 + {
  81 + $this->id = $id;
  82 + }
  83 +
  84 + /**
  85 + * @return string
  86 + */
  87 + public function getAccessToken(): string
  88 + {
  89 + return $this->accessToken;
  90 + }
  91 +
  92 + /**
  93 + * @param string $accessToken
  94 + */
  95 + public function setAccessToken(string $accessToken): void
  96 + {
  97 + $this->accessToken = $accessToken;
  98 + }
  99 +
  100 + /**
  101 + * @return string
  102 + */
  103 + public function getRefreshToken(): string
  104 + {
  105 + return $this->refreshToken;
  106 + }
  107 +
  108 + /**
  109 + * @param string $refreshToken
  110 + */
  111 + public function setRefreshToken(string $refreshToken): void
  112 + {
  113 + $this->refreshToken = $refreshToken;
  114 + }
  115 +
  116 + /**
  117 + * @return Carbon
  118 + */
  119 + public function getCreatedAt(): Carbon
  120 + {
  121 + return $this->createdAt;
  122 + }
  123 +
  124 + /**
  125 + * @param Carbon $createdAt
  126 + */
  127 + public function setCreatedAt(Carbon $createdAt): void
  128 + {
  129 + $this->createdAt = $createdAt;
  130 + }
  131 +
  132 + /**
  133 + * @return Carbon
  134 + */
  135 + public function getExpiredAt(): Carbon
  136 + {
  137 + return $this->expiredAt;
  138 + }
  139 +
  140 + /**
  141 + * @param Carbon $expiredAt
  142 + */
  143 + public function setExpiredAt(Carbon $expiredAt): void
  144 + {
  145 + $this->expiredAt = $expiredAt;
  146 + }
  147 +
  148 + /**
  149 + * @return int
  150 + */
  151 + public function getExpiresIn(): int
  152 + {
  153 + return $this->expiresIn;
  154 + }
  155 +
  156 + /**
  157 + * @param int $expiresIn
  158 + */
  159 + public function setExpiresIn(int $expiresIn): void
  160 + {
  161 + $this->expiresIn = $expiresIn;
  162 + }
  163 +
  164 + /**
  165 + * @return array
  166 + */
  167 + public function getExtras(): array
  168 + {
  169 + return $this->extras;
  170 + }
  171 +
  172 + /**
  173 + * @param array $extras
  174 + */
  175 + public function setExtras(array $extras): void
  176 + {
  177 + $this->extras = $extras;
  178 + }
  179 +
  180 + /**
  181 + * @return int
  182 + */
  183 + public function getRefreshNum(): int
  184 + {
  185 + return $this->refreshNum;
  186 + }
  187 +
  188 + /**
  189 + * @param int $refreshNum
  190 + */
  191 + public function setRefreshNum(int $refreshNum): void
  192 + {
  193 + $this->refreshNum = $refreshNum;
  194 + }
  195 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\TiktokShop\Supervisor\Session;
  4 +
  5 +use Lackoxygen\TiktokShop\Exception\ClientException;
  6 +use Lackoxygen\TiktokShop\Passage\ResultSet;
  7 +
  8 +trait Swap
  9 +{
  10 + public function refresh()
  11 + {
  12 + $app = app('tiktok.shop');
  13 + try {
  14 + /**
  15 + * @var ResultSet $result
  16 + */
  17 + $result = $app->authorize->refresh($this->store->getRefreshToken());
  18 +
  19 + if ($result->isSuccess()) {
  20 + $this->store->setAccessToken($result->get('access_token'));
  21 + $this->store->setRefreshToken($result->get('refresh_token'));
  22 + $this->store->setRefreshNum($this->store->getRefreshNum() + 1);
  23 + $this->store->setCreatedAt(now());
  24 + $this->store->setExpiredAt(now()->addMicroseconds($result->get('expired_in')));
  25 + }
  26 + } catch (ClientException $exception) {
  27 + $this->discard();
  28 + }
  29 + }
  30 +}