فهرست منبع

优化系统任务管理

Anyon 4 سال پیش
والد
کامیت
7879b61953

+ 5 - 11
app/admin/controller/Queue.php

@@ -45,19 +45,13 @@ class Queue extends Controller
      */
     public function index()
     {
-        // 检查进程状态
-        if (AdminService::instance()->isSuper()) try {
-            $this->process = ProcessService::instance();
-            if ($this->process->iswin() || empty($_SERVER['USER'])) {
-                $this->command = $this->process->think('xadmin:queue start');
+        if (AdminService::instance()->isSuper()) {
+            $process = ProcessService::instance();
+            if ($process->iswin() || empty($_SERVER['USER'])) {
+                $this->command = $process->think('xadmin:queue start');
             } else {
-                $this->command = "sudo -u {$_SERVER['USER']} {$this->process->think('xadmin:queue start')}";
+                $this->command = "sudo -u {$_SERVER['USER']} {$process->think('xadmin:queue start')}";
             }
-            $this->message = $this->app->console->call('xadmin:queue', ['status'])->fetch();
-            $this->listen = preg_match('/process.*?\d+.*?running/', $this->message, $attr);
-        } catch (\Exception $exception) {
-            $this->listen = false;
-            $this->message = $exception->getMessage();
         }
         // 任务状态统计
         $this->total = ['dos' => 0, 'pre' => 0, 'oks' => 0, 'ers' => 0];

+ 21 - 0
app/admin/controller/api/Plugs.php

@@ -17,6 +17,7 @@ namespace app\admin\controller\api;
 
 use think\admin\Controller;
 use think\admin\service\AdminService;
+use think\admin\service\ProcessService;
 use think\admin\service\SystemService;
 use think\exception\HttpResponseException;
 
@@ -100,6 +101,26 @@ class Plugs extends Controller
     }
 
     /**
+     * 检查任务状态
+     * @login true
+     */
+    public function queue()
+    {
+        if (AdminService::instance()->isSuper()) try {
+            $message = $this->app->console->call('xadmin:queue', ['status'])->fetch();
+            if (preg_match('/process.*?\d+.*?running/', $message, $attrs)) {
+                echo '<span class="color-green">' . $message . '</span>';
+            } else {
+                echo '<span class="color-red">' . $message . '</span>';
+            }
+        } catch (\Exception $exception) {
+            echo '<span class="color-red">' . $exception->getMessage() . '</span>';
+        } else {
+            $this->error('只有超级管理员才能操作!');
+        }
+    }
+
+    /**
      * 优化数据库
      * @login true
      */

+ 16 - 19
app/admin/view/queue/index_search.html

@@ -3,14 +3,11 @@
     <legend class="notselect">守护状态</legend>
     <div class="layui-code border-0 margin-top-0">
         <h4 class="color-desc margin-top-10 notselect">守护进程运行状态</h4>
-        {if $listen}
-        <span class="color-green">{$message|raw|default='--'}</span>
-        {else}
-        <span class="color-red">{$message|raw|default='--'}</span>
-        {/if}
+        <div data-queue-message>Checking task process running status ...</div>
         <h4 class="color-desc margin-top-10 notselect">配置定时任务来检查并启动进程(建议每分钟执行)</h4>
         <p>{$command|default='--'}</p>
     </div>
+    <script>$('[data-queue-message]').load('{:url("@admin/api.plugs/queue")}')</script>
 </fieldset>
 {/if}
 
@@ -19,25 +16,25 @@
     <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">任务编号</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input name="code" value="{:input('get.code')}" placeholder="请输入任务编号" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">任务名称</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input name="title" value="{:input('get.title')}" placeholder="请输入任务名称" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">任务指令</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input name="command" value="{:input('get.command')}" placeholder="请输入任务指令" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">任务状态</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <select name="status" class="layui-select">
                     {foreach [''=>'-- 全部状态 --','1'=>'等待处理','2'=>'正在处理','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
                     {if input('get.status') eq $k}
@@ -46,25 +43,25 @@
                     <option value="{$k}">{$v}</option>
                     {/if}{/foreach}
                 </select>
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">计划时间</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input data-date-range name="exec_time" value="{:input('get.exec_time')}" placeholder="请选择计划时间" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">执行时间</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input data-date-range name="enter_time" value="{:input('get.enter_time')}" placeholder="请选择执行时间" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <label class="layui-form-label">创建时间</label>
-            <div class="layui-input-inline">
+            <label class="layui-input-inline">
                 <input data-date-range name="create_at" value="{:input('get.create_at')}" placeholder="请选择创建时间" class="layui-input">
-            </div>
+            </label>
         </div>
         <div class="layui-form-item layui-inline">
             <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>

+ 1 - 0
vendor/composer/autoload_classmap.php

@@ -324,6 +324,7 @@ return array(
     'think\\admin\\storage\\AliossStorage' => $vendorDir . '/zoujingli/think-library/src/storage/AliossStorage.php',
     'think\\admin\\storage\\LocalStorage' => $vendorDir . '/zoujingli/think-library/src/storage/LocalStorage.php',
     'think\\admin\\storage\\QiniuStorage' => $vendorDir . '/zoujingli/think-library/src/storage/QiniuStorage.php',
+    'think\\admin\\storage\\TxcosStorage' => $vendorDir . '/zoujingli/think-library/src/storage/TxcosStorage.php',
     'think\\cache\\Driver' => $vendorDir . '/topthink/framework/src/think/cache/Driver.php',
     'think\\cache\\TagSet' => $vendorDir . '/topthink/framework/src/think/cache/TagSet.php',
     'think\\cache\\driver\\File' => $vendorDir . '/topthink/framework/src/think/cache/driver/File.php',

+ 1 - 0
vendor/composer/autoload_static.php

@@ -452,6 +452,7 @@ class ComposerStaticInit33b66ed99ea8fcca84c95dfb0e7ed409
         'think\\admin\\storage\\AliossStorage' => __DIR__ . '/..' . '/zoujingli/think-library/src/storage/AliossStorage.php',
         'think\\admin\\storage\\LocalStorage' => __DIR__ . '/..' . '/zoujingli/think-library/src/storage/LocalStorage.php',
         'think\\admin\\storage\\QiniuStorage' => __DIR__ . '/..' . '/zoujingli/think-library/src/storage/QiniuStorage.php',
+        'think\\admin\\storage\\TxcosStorage' => __DIR__ . '/..' . '/zoujingli/think-library/src/storage/TxcosStorage.php',
         'think\\cache\\Driver' => __DIR__ . '/..' . '/topthink/framework/src/think/cache/Driver.php',
         'think\\cache\\TagSet' => __DIR__ . '/..' . '/topthink/framework/src/think/cache/TagSet.php',
         'think\\cache\\driver\\File' => __DIR__ . '/..' . '/topthink/framework/src/think/cache/driver/File.php',

+ 4 - 4
vendor/composer/installed.json

@@ -893,12 +893,12 @@
         "source": {
             "type": "git",
             "url": "https://github.com/zoujingli/ThinkLibrary.git",
-            "reference": "97fc43a5d602d7477c61022003042b1e3535ebce"
+            "reference": "213b606ab9906914296f475324538b93c18406dd"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/97fc43a5d602d7477c61022003042b1e3535ebce",
-            "reference": "97fc43a5d602d7477c61022003042b1e3535ebce",
+            "url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/213b606ab9906914296f475324538b93c18406dd",
+            "reference": "213b606ab9906914296f475324538b93c18406dd",
             "shasum": "",
             "mirrors": [
                 {
@@ -915,7 +915,7 @@
             "ext-mbstring": "*",
             "topthink/framework": "^6.0"
         },
-        "time": "2020-10-13T08:48:27+00:00",
+        "time": "2020-10-15T01:37:16+00:00",
         "type": "library",
         "extra": {
             "think": {

+ 1 - 1
vendor/services.php

@@ -1,5 +1,5 @@
 <?php 
-// This file is automatically generated at:2020-10-13 18:52:29
+// This file is automatically generated at:2020-10-15 09:55:40
 declare (strict_types = 1);
 return array (
   0 => 'think\\admin\\Library',

+ 4 - 4
vendor/zoujingli/think-library/src/Library.php

@@ -49,11 +49,11 @@ class Library extends Service
     public function boot()
     {
         // 多应用中间键处理
-        $this->app->event->listen('HttpRun', function () {
+        $this->app->event->listen('HttpRun', function (Request $request) {
             $this->app->middleware->add(App::class);
-            // 解决 HTTP 模式下调用 Console 之后 URL 生成问题
-            if (!$this->app->request->isCli() && !$this->app->config->get('app.url')) {
-                $this->app->config->set(['url' => $this->app->request->url(true)], 'app');
+            // 解决 HTTP 调用 Console 之后 URL 问题
+            if (!$this->app->request->isCli()) {
+                $request->setHost($request->host());
             }
         });
         // 替换 ThinkPHP 地址

+ 283 - 0
vendor/zoujingli/think-library/src/storage/TxcosStorage.php

@@ -0,0 +1,283 @@
+<?php
+
+declare (strict_types=1);
+
+namespace think\admin\storage;
+
+use think\admin\extend\HttpExtend;
+use think\admin\Storage;
+
+/**
+ * 腾讯云COS存储支持
+ * Class TxcosStorage
+ * @package think\admin\storage
+ */
+class TxcosStorage extends Storage
+{
+    /**
+     * 数据中心
+     * @var string
+     */
+    private $point;
+
+    /**
+     * 存储空间名称
+     * @var string
+     */
+    private $bucket;
+
+    /**
+     * $secretId
+     * @var string
+     */
+    private $secretId;
+
+    /**
+     * secretKey
+     * @var string
+     */
+    private $secretKey;
+
+    /**
+     * 初始化入口
+     * @throws \think\admin\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    protected function initialize()
+    {
+        // 读取配置文件
+        $this->point = sysconf('storage.txcos_point');
+        $this->bucket = sysconf('storage.txcos_bucket');
+        $this->secretId = sysconf('storage.txcos_secret_id');
+        $this->secretKey = sysconf('storage.txcos_secret_key');
+        // 计算链接前缀
+        $type = strtolower(sysconf('storage.txcos_http_protocol'));
+        $domain = strtolower(sysconf('storage.txcos_http_domain'));
+        if ($type === 'auto') $this->prefix = "//{$domain}";
+        elseif ($type === 'http') $this->prefix = "http://{$domain}";
+        elseif ($type === 'https') $this->prefix = "https://{$domain}";
+        else throw new \think\admin\Exception('未配置腾讯云COS访问域名哦');
+    }
+
+    /**
+     * 获取当前实例对象
+     * @param null|string $name
+     * @return static
+     * @throws \think\admin\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public static function instance(?string $name = null)
+    {
+        return parent::instance('txcos');
+    }
+
+    /**
+     * 上传文件内容
+     * @param string $name 文件名称
+     * @param string $file 文件内容
+     * @param boolean $safe 安全模式
+     * @param null|string $attname 下载名称
+     * @return array
+     */
+    public function set(string $name, string $file, bool $safe = false, ?string $attname = null)
+    {
+        $token = $this->buildUploadToken($name);
+        $data = ['key' => $name];
+        $data['policy'] = $token['policy'];
+        $data['q-sign-algorithm'] = $token['q-sign-algorithm'];
+        $data['q-ak'] = $token['q-ak'];
+        $data['q-key-time'] = $token['q-key-time'];
+        $data['q-signature'] = $token['d-signature'];
+        $data['success_action_status'] = '200';
+        if (is_string($attname) && strlen($attname) > 0) {
+            $filename = urlencode($attname);
+            $data['Content-Disposition'] = "inline;filename={$filename}";
+        }
+        $file = ['field' => 'file', 'name' => $name, 'content' => $file];
+        if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
+            return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
+        } else {
+            return [];
+        }
+    }
+
+    /**
+     * 根据文件名读取文件内容
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @return false|string
+     */
+    public function get(string $name, bool $safe = false)
+    {
+        return static::curlGet($this->url($name, $safe));
+    }
+
+    /**
+     * 删除存储的文件
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @return boolean
+     */
+    public function del(string $name, bool $safe = false)
+    {
+        [$file] = explode('?', $name);
+        $result = HttpExtend::request('DELETE', "http://{$this->bucket}.{$this->point}/{$file}", [
+            'returnHeader' => true, 'headers' => $this->headerSign('DELETE', $file),
+        ]);
+        return is_numeric(stripos($result, '204 No Content'));
+    }
+
+    /**
+     * 判断文件是否存在
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @return boolean
+     */
+    public function has(string $name, bool $safe = false)
+    {
+        $file = $this->delSuffix($name);
+        $result = HttpExtend::request('HEAD', "http://{$this->bucket}.{$this->point}/{$file}", [
+            'returnHeader' => true, 'headers' => $this->headerSign('HEAD', $name),
+        ]);
+        return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
+    }
+
+    /**
+     * 获取文件当前URL地址
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @param null|string $attname 下载名称
+     * @return string
+     */
+    public function url(string $name, bool $safe = false, ?string $attname = null): string
+    {
+        return "{$this->prefix}/{$this->delSuffix($name)}{$this->getSuffix($attname)}";
+    }
+
+    /**
+     * 获取文件存储路径
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @return string
+     */
+    public function path(string $name, bool $safe = false): string
+    {
+        return $this->url($name, $safe);
+    }
+
+    /**
+     * 获取文件存储信息
+     * @param string $name 文件名称
+     * @param boolean $safe 安全模式
+     * @param null|string $attname 下载名称
+     * @return array
+     */
+    public function info(string $name, bool $safe = false, ?string $attname = null): array
+    {
+        return $this->has($name, $safe) ? [
+            'url' => $this->url($name, $safe, $attname),
+            'key' => $name, 'file' => $this->path($name, $safe),
+        ] : [];
+    }
+
+    /**
+     * 获取文件上传地址
+     * @return string
+     */
+    public function upload(): string
+    {
+        $http = $this->app->request->isSsl() ? 'https' : 'http';
+        return "{$http}://{$this->bucket}.{$this->point}";
+    }
+
+    /**
+     * 获取文件上传令牌
+     * @param null|string $name 文件名称
+     * @param integer $expires 有效时间
+     * @param null|string $attname 下载名称
+     * @return array
+     */
+    public function buildUploadToken(?string $name = null, int $expires = 3600, ?string $attname = null): array
+    {
+        $startTimestamp = time();
+        $endTimestamp = $startTimestamp + $expires;
+        $keyTime = "{$startTimestamp};{$endTimestamp}";
+        $siteurl = $this->url($name, false, $attname);
+        $policy = json_encode([
+            'expiration' => date('Y-m-d\TH:i:s.000\Z', $endTimestamp),
+            'conditions' => [
+                ['q-sign-algorithm' => 'sha1'],
+                ['q-ak' => $this->secretId],
+                ['q-sign-time' => $keyTime]
+            ],
+        ]);
+        $data = [
+            'policy'           => base64_encode($policy),
+            'q-sign-algorithm' => 'sha1',
+            'q-ak'             => $this->secretId,
+            'q-key-time'       => $keyTime,
+            'siteurl'          => $siteurl
+        ];
+        $signKey = hash_hmac('sha1', $keyTime, $this->secretKey);
+        $stringToSign = sha1($policy);
+        $data['q-signature'] = hash_hmac('sha1', $stringToSign, $signKey);
+        return $data;
+    }
+
+    /**
+     * 操作请求头信息签名
+     * @param string $method 请求方式
+     * @param string $soruce 资源名称
+     * @param array $header 请求头信息
+     * @return array
+     */
+    private function headerSign(string $method, string $soruce, array $header = []): array
+    {
+        // 1.生成KeyTime
+        $startTimestamp = time();
+        $endTimestamp = $startTimestamp + 3600;
+        $keyTime = "{$startTimestamp};{$endTimestamp}";
+        // 2.生成 SignKey
+        $signKey = hash_hmac('sha1', $keyTime, $this->secretKey);
+        // 3.生成UrlParamList,HttpParameters
+        list($parse_url, $urlParamList, $httpParameters) = [parse_url($soruce), '', ''];
+        if (!empty($parse_url['query'])) {
+            parse_str($parse_url['query'], $params);
+            uksort($params, 'strnatcasecmp');
+            $urlParamList = join(';', array_keys($params));
+            $httpParameters = http_build_query($params);
+        }
+        // 4.生成HeaderList,HttpHeaders
+        list($headerList, $httpHeaders) = ['', ''];
+        if (!empty($header)) {
+            uksort($header, 'strnatcasecmp');
+            $headerList = join(';', array_keys($header));
+            $httpHeaders = http_build_query($header);
+        }
+        // 5.生成HttpString
+        $httpString = strtolower($method) . "\n/{$parse_url['path']}\n{$httpParameters}\n{$httpHeaders}\n";
+        // 6.生成StringToSign
+        $httpStringSha1 = sha1($httpString);
+        $stringToSign = "sha1\n{$keyTime}\n{$httpStringSha1}\n";
+        // 7.生成Signature
+        $signature = hash_hmac('sha1', $stringToSign, $signKey);
+        // 8.生成签名
+        $signArray = [
+            'q-sign-algorithm' => 'sha1',
+            'q-ak'             => $this->secretId,
+            'q-sign-time'      => $keyTime,
+            'q-key-time'       => $keyTime,
+            'q-header-list'    => $headerList,
+            'q-url-param-list' => $urlParamList,
+            'q-signature'      => $signature
+        ];
+        $header['Authorization'] = urldecode(http_build_query($signArray));
+        foreach ($header as $key => $value) $header[$key] = ucfirst($key) . ": {$value}";
+        return array_values($header);
+    }
+
+}