Browse Source

支持新版检测;freenom 支持使用代理访问

luolongfei 4 years ago
parent
commit
3e76d37cf4

+ 10 - 4
.env.example

@@ -12,17 +12,20 @@
 #####################################################################
 
 # .env 文件版本
-ENV_FILE_VERSION='v1'
+ENV_FILE_VERSION='v2'
 
 ######################  账户配置 Account config  #########################
-# Freenom账户 Freenom Account
+# Freenom 账户 Freenom Account
 [email protected]
 
-# Freenom密码 Freenom password
+# Freenom 密码 Freenom password
 FREENOM_PASSWORD=''
 
 # 多账户支持 Support for multiple accounts
 MULTIPLE_ACCOUNTS=''
+
+# Freenom 代理 e.g. http://127.0.0.1:1081 or socks5://127.0.0.1:1080
+FREENOM_PROXY=''
 ######################  end 账户配置  #########################
 
 ######################  通知邮件配置 Email config  #########################
@@ -64,7 +67,7 @@ TELEGRAM_CHAT_ID=''
 # 你的Telegram bot的token Token for your Telegram bot
 TELEGRAM_BOT_TOKEN=''
 
-# Telegram 代理 e.g. http://127.0.0.1:1081
+# Telegram 代理 e.g. http://127.0.0.1:1081 or socks5://127.0.0.1:1080
 TELEGRAM_PROXY=''
 
 # 是否启用 Telegram Bot 功能 1:启用 0:不启用 Whether to enable Telegram Bot features 1: enabled 0: not enabled
@@ -119,3 +122,6 @@ VERIFY_SSL=0
 
 # 是否开启 Debug 模式 1:开启 0:关闭 Whether to turn on Debug mode 1: On 0: Off
 DEBUG=0
+
+# 检测是否有新版本可用,发现新版本时推送消息通知 1:开启 0:关闭 Automatically detects if a new version is available and pushes a message notification when a new version is found 1: On 0: Off
+NEW_VERSION_DETECTION=1

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@ app/tmp/
 app/num_limit/
 .idea/
 app/Data/
+.env.old

+ 5 - 4
app/Console/FreeNom.php

@@ -18,7 +18,7 @@ use Luolongfei\Libs\Message;
 
 class FreeNom extends Base
 {
-    const VERSION = 'v0.4.1';
+    const VERSION = 'v0.4.2';
 
     const TIMEOUT = 33;
 
@@ -89,7 +89,8 @@ class FreeNom extends Base
             CURLOPT_FOLLOWLOCATION => true,
             CURLOPT_AUTOREFERER => true,
             'verify' => config('verify_ssl'),
-            'debug' => config('debug')
+            'debug' => config('debug'),
+            'proxy' => config('freenom_proxy'),
         ]);
 
         system_log(sprintf('当前程序版本 %s', self::VERSION));
@@ -268,7 +269,7 @@ class FreeNom extends Base
             system_log('当前通知频率为「仅当有续期操作时」,故本次不会推送通知');
         }
 
-        system_log(sprintf('%s:<green>执行成功,今次没有需要续期的域名</green>', $this->username));
+        system_log(sprintf('%s:<green>执行成功,今次没有需要续期的域名</green>', $this->username));
 
         return true;
     }
@@ -408,7 +409,7 @@ class FreeNom extends Base
     {
         $accounts = $this->getAccounts();
 
-        system_log(sprintf('共发现 <green>%d</green> 个账户,正在处理...', count($accounts)));
+        system_log(sprintf('共发现 <green>%d</green> 个账户,处理中', count($accounts)));
 
         foreach ($accounts as $account) {
             try {

+ 251 - 0
app/Console/Upgrade.php

@@ -0,0 +1,251 @@
+<?php
+/**
+ * 升级
+ *
+ * @author mybsdc <[email protected]>
+ * @date 2021/11/5
+ * @time 10:52
+ */
+
+namespace Luolongfei\App\Console;
+
+use GuzzleHttp\Client;
+use Luolongfei\Libs\Log;
+use Luolongfei\Libs\Message;
+
+class Upgrade extends Base
+{
+    const TIMEOUT = 33;
+
+    /**
+     * @var Upgrade
+     */
+    private static $instance;
+
+    /**
+     * @var array 与发布相关的信息
+     */
+    public $releaseInfo = [];
+
+    /**
+     * @var string 最新版本号
+     */
+    public $latestVer;
+
+    /**
+     * @var string 当前版本号
+     */
+    public $currVer;
+
+    /**
+     * @var string 记录已推送版本的文件
+     */
+    public $pushedVerFile;
+
+    /**
+     * @return Upgrade
+     */
+    public static function getInstance()
+    {
+        if (!self::$instance instanceof self) {
+            self::$instance = new self();
+        }
+
+        return self::$instance;
+    }
+
+    private function __construct()
+    {
+        $this->pushedVerFile = DATA_PATH . DS . 'pushed_version.txt';
+
+        $this->client = new Client([
+            'base_uri' => 'https://api.github.com',
+            'headers' => [
+                'Accept' => 'application/vnd.github.v3+json'
+            ],
+            'cookies' => false,
+            'timeout' => self::TIMEOUT,
+            'verify' => config('verify_ssl'),
+            'debug' => config('debug'),
+        ]);
+    }
+
+    private function __clone()
+    {
+    }
+
+    /**
+     * 是否需要升级
+     *
+     * @return bool
+     */
+    public function needToUpgrade()
+    {
+        try {
+            $resp = $this->client->get('/repos/luolongfei/freenom/releases/latest', [
+                'timeout' => 5,
+            ]);
+
+            $resp = $resp->getBody()->getContents();
+            $resp = (array)json_decode($resp, true);
+
+            if (!isset($resp['tag_name'])
+                || !isset($resp['body'])
+                || !isset($resp['name'])
+                || !isset($resp['published_at'])
+                || !isset($resp['html_url'])) {
+                throw new \Exception('Github 返回的数据与预期不一致:' . json_encode($resp, JSON_UNESCAPED_UNICODE));
+            }
+
+            $this->releaseInfo = $resp;
+
+            $this->latestVer = $this->getVerNum($resp['tag_name']);
+            $this->currVer = $this->getVerNum(FreeNom::VERSION);
+
+            return version_compare($this->latestVer, $this->currVer, '>');
+        } catch (\Exception $e) {
+            Log::error('检测升级出错:' . $e->getMessage());
+
+            return false;
+        }
+    }
+
+    /**
+     * 此版本是否已推送过
+     *
+     * @param $ver
+     *
+     * @return bool
+     */
+    public function isPushed($ver)
+    {
+        if (!file_exists($this->pushedVerFile)) {
+            return false;
+        }
+
+        $pushedVerFile = file_get_contents($this->pushedVerFile);
+
+        return stripos($pushedVerFile, $ver) !== false;
+    }
+
+    /**
+     * 记住版本号
+     *
+     * @param $ver
+     *
+     * @return bool
+     */
+    public function rememberVer($ver)
+    {
+        return (bool)file_put_contents($this->pushedVerFile, $ver . "\n", FILE_APPEND);
+    }
+
+    /**
+     * 生成升级送信内容
+     *
+     * @return string
+     */
+    public function genMsgContent()
+    {
+        $content = sprintf(
+            "见信好,我们在 %s 发布了新版 FreeNom 续期工具 v%s,而你当前正在使用的版本为 v%s,你可以根据自己的实际需要决定是否升级到新版本。今次新版有以下更新或改进:\n\n",
+            $this->friendlyDateFormat($this->releaseInfo['published_at'], 'UTC'),
+            $this->latestVer,
+            $this->currVer
+        );
+
+        $content .= $this->releaseInfo['body'];
+
+        $content .= "\n\n" . '欲知更多信息,请访问:' . $this->releaseInfo['html_url'];
+
+        $content .= "\n\n" . '(本消息针对同一个新版只会推送一次,如果你不想收到新版本通知,将 .env 文件中的 NEW_VERSION_DETECTION 的值设为 0 即可)';
+
+        return $content;
+    }
+
+    /**
+     * 人类友好时间
+     *
+     * @param string $date 传入时间
+     * @param null|string $timezone 传入时间的时区
+     *
+     * @return string
+     */
+    public function friendlyDateFormat($date, $timezone = null)
+    {
+        try {
+            $d = (new \DateTime($date, $timezone ? new \DateTimeZone($timezone) : null))->setTimezone(new \DateTimeZone('Asia/Shanghai'));
+
+            $time = $d->getTimestamp();
+            $diff = time() - $time;
+
+            if ($diff < 86400) {
+                if ($d->format('d') === date('d')) {
+                    return $diff < 60 ? '刚刚' : ($diff < 3600 ? floor($diff / 60) . '分钟前' : floor($diff / 3600) . '小时前');
+                } else {
+                    return '昨天 ' . $d->format('H:i');
+                }
+            } else {
+                return $d->format($d->format('Y') === date('Y') ? 'Y-m-d H:i' : 'Y-m-d');
+            }
+        } catch (\Exception $e) {
+            Log::error('转人类友好时间出错:' . $e->getMessage());
+
+            return $date;
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    public function handle()
+    {
+        try {
+            if (!$this->needToUpgrade()) {
+                return true;
+            }
+
+            if ($this->isPushed($this->latestVer)) {
+                return true;
+            }
+
+            if (IS_SCF) {
+                system_log(sprintf(
+                    'FreeNom 续期工具有新的版本可用,你当前版本为 v%s,最新版本为 v%s。关于新版的详细信息,请访问:%s',
+                    $this->currVer,
+                    $this->latestVer,
+                    $this->releaseInfo['html_url']
+                ));
+            } else {
+                system_log(sprintf(
+                    '<green>FreeNom 续期工具有新的版本可用,最新版本为 v%s(%s)</green>',
+                    $this->latestVer,
+                    $this->releaseInfo['html_url']
+                ));
+
+                $result = Message::send(
+                    $this->genMsgContent(),
+                    sprintf('主人,FreeNom 续期工具有新的版本(v%s)可用,新版相关情况已给到你', $this->latestVer),
+                    4
+                );
+
+                if ($result) {
+                    $this->rememberVer($this->latestVer);
+                    system_log('有关新版的信息已送信给到你,请注意查收。');
+                }
+            }
+
+            return true;
+        } catch (\Exception $e) {
+            system_log('升级出错:' . $e->getMessage());
+
+            return false;
+        }
+    }
+
+    public function doUpgrade()
+    {
+        // TODO 自动升级
+//        system_log('<green>恭喜,已完成升级。</green>');
+    }
+}

+ 8 - 0
app/helpers.php

@@ -15,6 +15,7 @@ use Luolongfei\Libs\Env;
 use Luolongfei\Libs\Lang;
 use Luolongfei\Libs\PhpColor;
 use Luolongfei\App\Console\MigrateEnvFile;
+use Luolongfei\App\Console\Upgrade;
 
 if (!function_exists('config')) {
     /**
@@ -251,6 +252,13 @@ if (!function_exists('system_check')) {
             MigrateEnvFile::getInstance()->handle();
         }
 
+        // 是否有新版可用
+        if (config('new_version_detection')) {
+            Upgrade::getInstance()->handle();
+        } else {
+            system_log('由于你没有开启升级提醒功能,故无法在有新版本可用时第一时间收到通知。将 .env 文件中 NEW_VERSION_DETECTION 的值改为 1 即可重新开启相关功能。');
+        }
+
         if (!extension_loaded('curl')) {
             throw new LlfException(34520010);
         }

+ 2 - 0
config.php

@@ -104,4 +104,6 @@ return [
     'notice_freq' => (int)env('NOTICE_FREQ', 1), // 通知频率 0:仅当有续期操作的时候 1:每次执行
     'verify_ssl' => (bool)env('VERIFY_SSL'), // 请求时验证 SSL 证书行为,默认不验证,防止服务器证书过期或证书颁布者信息不全导致无法发出请求
     'debug' => (bool)env('DEBUG'),
+    'freenom_proxy' => env('FREENOM_PROXY') ?: null, // FreeNom 代理,针对国内网络情况,可选择代理访问
+    'new_version_detection' => (bool)env('NEW_VERSION_DETECTION'),
 ];

+ 1 - 1
index.php

@@ -51,7 +51,7 @@ function customize_error_handler()
 {
     if (!is_null($error = error_get_last())) {
         Log::error('程序意外终止', $error);
-        Message::send('具体情况我也不清楚,请查看服务器日志定位问题。', '主人,程序意外终止');
+        Message::send('可能存在错误,这边收集到的错误信息为:' . json_encode($error, JSON_UNESCAPED_UNICODE), '主人,程序意外终止');
     }
 }
 

+ 12 - 0
libs/Connector/MessageGateway.php

@@ -42,4 +42,16 @@ abstract class MessageGateway implements MessageServiceInterface
             throw new \Exception(lang('error_msg.100004'));
         }
     }
+
+    /**
+     * 换行转 <br>
+     *
+     * @param string $content
+     *
+     * @return string
+     */
+    public function newLine2Br(string $content)
+    {
+        return preg_replace("/\n/u", '<br>', $content);
+    }
 }

+ 1 - 1
libs/Connector/MessageServiceInterface.php

@@ -18,7 +18,7 @@ interface MessageServiceInterface
      *
      * @param string $content
      * @param string $subject
-     * @param integer $type 消息类型 1:普通消息 2:域名续期结果 3:无需续期,域名状态信件
+     * @param integer $type 消息类型 1:普通消息 2:域名续期结果 3:无需续期,域名状态信件 4:升级通知
      * @param array $data
      * @param string|null $recipient
      * @param ...$params

+ 8 - 1
libs/Message.php

@@ -16,6 +16,11 @@ use Luolongfei\Libs\Connector\MessageServiceInterface;
  */
 abstract class Message extends Base
 {
+    /**
+     * @var bool 防止同一个执行周期里每次送信都提示未启用
+     */
+    protected static $notEnabledTips = true;
+
     /**
      * @param $method
      * @param $params
@@ -29,7 +34,7 @@ abstract class Message extends Base
 
         foreach (config('message') as $conf) {
             if ($conf['enable'] !== 1) {
-                if ($conf['not_enabled_tips']) { // 仅在存在配置的送信项未启用的情况下提醒
+                if ($conf['not_enabled_tips'] && self::$notEnabledTips) { // 仅在存在配置的送信项未启用的情况下提醒
                     system_log(sprintf('由于没有启用「%s」功能,故本次不通过「%s」送信,尽管检测到相关配置。', $conf['name'], $conf['name']));
                 }
 
@@ -47,6 +52,8 @@ abstract class Message extends Base
             }
         }
 
+        self::$notEnabledTips = false;
+
         return $result;
     }
 }

+ 1 - 1
libs/MessageServices/Bark.php

@@ -217,7 +217,7 @@ class Bark extends MessageGateway
     {
         $this->check($content, $data);
 
-        if ($type === 1) {
+        if ($type === 1 || $type === 4) {
             // Do nothing
         } else if ($type === 2) {
             $content = $this->genDomainRenewalResultsText($data['username'], $data['renewalSuccessArr'], $data['renewalFailuresArr'], $data['domainStatusArr']);

+ 3 - 0
libs/MessageServices/Mail.php

@@ -213,6 +213,9 @@ class Mail extends MessageGateway
                 $this->genDomainStatusHtml($data['domainStatusArr'])
             ];
             $message = $this->genMessageContent($realData, $template);
+        } else if ($type === 4) {
+            $template = file_get_contents(RESOURCES_PATH . '/mail/notice.html');
+            $message = sprintf($template, $this->newLine2Br($content));
         } else {
             throw new \Exception(lang('error_msg.100003'));
         }

+ 1 - 1
libs/MessageServices/ServerChan.php

@@ -165,7 +165,7 @@ class ServerChan extends MessageGateway
     {
         $this->check($content, $data);
 
-        if ($type === 1) {
+        if ($type === 1 || $type === 4) {
             // Do nothing
         } else if ($type === 2) {
             $content = $this->genDomainRenewalResultsMarkDownText($data['username'], $data['renewalSuccessArr'], $data['renewalFailuresArr'], $data['domainStatusArr']);

+ 3 - 3
libs/MessageServices/TelegramBot.php

@@ -220,7 +220,7 @@ class TelegramBot extends MessageGateway
      * 需要注意的是,普通 markdown 语法中加粗字体使用的是“**正文**”的形式,但是 Telegram Bot 中是“*加粗我*”的形式
      * 更多相关信息请参考官网:https://core.telegram.org/bots/api#sendmessage
      * 另外我干掉了“_”、“~”、“-”、“.”和“>”关键字,分别对应斜体、删除线、无序列表、有序列表和引用符号,因为这几个比较容易在正常文本里出现,而
-     * 我又不想每次都手动转义传入,故做了自动转义处理
+     * 我又不想每次都手动转义传入,故做了自动转义处理,况且 telegram 大多不支持
      *
      * 由于 telegram bot 的 markdown 语法不支持表格(https://core.telegram.org/bots/api#markdownv2-style),故表格部分由我自行解析
      * 为字符形式的表格,坐等 telegram bot 支持表格
@@ -231,7 +231,7 @@ class TelegramBot extends MessageGateway
     {
         $this->check($content, $data);
 
-        if ($type === 1) {
+        if ($type === 1 || $type === 4) {
             // Do nothing
         } else if ($type === 2) {
             $content = $this->genDomainRenewalResultsMarkDownText($data['username'], $data['renewalSuccessArr'], $data['renewalFailuresArr'], $data['domainStatusArr']);
@@ -254,7 +254,7 @@ class TelegramBot extends MessageGateway
 
         if ($isMarkdown) {
             // 这几个比较容易在正常文本里出现,而我不想每次都手动转义传入,所以直接干掉了
-            $content = preg_replace('/([.>~_-])/i', '\\\\$1', $content);
+            $content = preg_replace('/([.>~_-])/u', '\\\\$1', $content);
 
             // 转义非链接格式的 [] 以及 ()
             $content = preg_replace_callback_array(

+ 1 - 1
libs/MessageServices/WeChat.php

@@ -263,7 +263,7 @@ class WeChat extends MessageGateway
     {
         $this->check($content, $data);
 
-        if ($type === 1) {
+        if ($type === 1 || $type === 4) {
             // Do nothing
         } else if ($type === 2) {
             $content = $this->genDomainRenewalResultsText($data['username'], $data['renewalSuccessArr'], $data['renewalFailuresArr'], $data['domainStatusArr']);

+ 1 - 1
run

@@ -52,7 +52,7 @@ function customize_error_handler()
 {
     if (!is_null($error = error_get_last())) {
         Log::error('程序意外终止', $error);
-        Message::send('具体情况我也不清楚,请查看服务器日志定位问题。', '主人,程序意外终止');
+        Message::send('可能存在错误,这边收集到的错误信息为:' . json_encode($error, JSON_UNESCAPED_UNICODE), '主人,程序意外终止');
     }
 }