mirror of
https://github.com/netcccyun/dnsmgr.git
synced 2024-11-16 11:42:35 +08:00
新增CF优选IP
This commit is contained in:
parent
ad85fa7c22
commit
f20b132d97
11
README.md
11
README.md
|
@ -9,7 +9,12 @@
|
|||
- DNSLA
|
||||
- CloudFlare
|
||||
|
||||
本系统支持多用户,每个用户可分配不同的域名解析权限;支持API接口,支持获取域名独立DNS控制面板登录链接,方便各种IDC系统对接。
|
||||
### 功能特性
|
||||
|
||||
- 多用户管理,可为每个用户可分配不同的域名解析权限
|
||||
- 提供API接口,可获取域名单独的登录链接,方便各种IDC系统对接
|
||||
- 容灾切换功能,支持ping、tcp、http(s)检测协议并自动暂停/修改域名解析,并支持邮件、微信公众号通知
|
||||
- CF优选IP功能,支持获取最新的Cloudflare优选IP,并自动更新到解析记录
|
||||
|
||||
### 演示截图
|
||||
|
||||
|
@ -29,6 +34,10 @@
|
|||
|
||||
![](https://p0.meituan.net/csc/d1bd90bedca9b6cbc5da40286bdb5cd5228438.png)
|
||||
|
||||
CF优选IP功能,添加优选IP任务
|
||||
|
||||
![](https://p1.meituan.net/csc/da70c76753aee4bce044d16fadd56e5f217660.png)
|
||||
|
||||
### 部署方法
|
||||
|
||||
* 从[Release](https://github.com/netcccyun/dnsmgr/releases)页面下载安装包
|
||||
|
|
28
app/command/Opiptask.php
Normal file
28
app/command/Opiptask.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use Exception;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
use app\lib\OptimizeService;
|
||||
|
||||
class Opiptask extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('opiptask')
|
||||
->setDescription('CF优选IP任务');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
(new OptimizeService())->execute();
|
||||
}
|
||||
}
|
|
@ -157,7 +157,7 @@ class Dmonitor extends BaseController
|
|||
if($action == 'edit'){
|
||||
$id = input('get.id/d');
|
||||
$task = Db::name('dmtask')->where('id', $id)->find();
|
||||
if(empty($task)) return $this->alert('error', '任务不存在');
|
||||
if(empty($task)) return $this->alert('error', '切换策略不存在');
|
||||
}
|
||||
|
||||
$domains = [];
|
||||
|
@ -169,7 +169,7 @@ class Dmonitor extends BaseController
|
|||
View::assign('info', $task);
|
||||
View::assign('action', $action);
|
||||
View::assign('support_ping', function_exists('exec')?'1':'0');
|
||||
return View::fetch('taskform');
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function taskinfo()
|
||||
|
@ -177,14 +177,16 @@ class Dmonitor extends BaseController
|
|||
if(!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$id = input('param.id/d');
|
||||
$task = Db::name('dmtask')->where('id', $id)->find();
|
||||
if(empty($task)) return $this->alert('error', '任务不存在');
|
||||
if(empty($task)) return $this->alert('error', '切换策略不存在');
|
||||
|
||||
$switch_count = Db::name('dmlog')->where('taskid', $id)->where('date', '>=', date("Y-m-d H:i:s",strtotime("-1 days")))->count();
|
||||
$fail_count = Db::name('dmlog')->where('taskid', $id)->where('date', '>=', date("Y-m-d H:i:s",strtotime("-1 days")))->where('action', 1)->count();
|
||||
|
||||
$task['switch_count'] = $switch_count;
|
||||
$task['fail_count'] = $fail_count;
|
||||
if($task['type'] == 2){
|
||||
if($task['type'] == 3){
|
||||
$task['action_name'] = ['未知', '<font color="red">开启解析</font>', '<font color="green">暂停解析</font>'];
|
||||
}elseif($task['type'] == 2){
|
||||
$task['action_name'] = ['未知', '<font color="red">切换备用解析记录</font>', '<font color="green">恢复主解析记录</font>'];
|
||||
}else{
|
||||
$task['action_name'] = ['未知', '<font color="red">暂停解析</font>', '<font color="green">启用解析</font>'];
|
||||
|
|
|
@ -220,6 +220,7 @@ class Domain extends BaseController
|
|||
$id = input('post.id/d');
|
||||
Db::name('domain')->where('id', $id)->delete();
|
||||
Db::name('dmtask')->where('did', $id)->delete();
|
||||
Db::name('optimizeip')->where('did', $id)->delete();
|
||||
return json(['code'=>0]);
|
||||
}
|
||||
return json(['code'=>-3]);
|
||||
|
@ -232,9 +233,16 @@ class Domain extends BaseController
|
|||
$page = input('?post.page') ? input('post.page/d') : 1;
|
||||
$pagesize = input('?post.pagesize') ? input('post.pagesize/d') : 10;
|
||||
$dns = DnsHelper::getModel($aid);
|
||||
$list = $dns->getDomainList($kw, $page, $pagesize);
|
||||
if(!$list) return json(['code'=>-1, 'msg'=>'获取域名列表失败,'.$dns->getError()]);
|
||||
return json(['code'=>0, 'data'=>$list]);
|
||||
$result = $dns->getDomainList($kw, $page, $pagesize);
|
||||
if(!$result) return json(['code'=>-1, 'msg'=>'获取域名列表失败,'.$dns->getError()]);
|
||||
|
||||
$newlist = [];
|
||||
foreach($result['list'] as $row){
|
||||
if(!Db::name('domain')->where('aid', $aid)->where('name', $row['Domain'])->find()){
|
||||
$newlist[] = $row;
|
||||
}
|
||||
}
|
||||
return json(['code'=>0, 'data'=>['total'=>$result['total'], 'list'=>$newlist]]);
|
||||
}
|
||||
|
||||
//获取解析线路和最小TTL
|
||||
|
@ -244,10 +252,10 @@ class Domain extends BaseController
|
|||
if(empty($recordLine)){
|
||||
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
|
||||
if(!$dns) return $this->alert('error', 'DNS模块不存在');
|
||||
$recordLine = $dns->getRecordLine($drow['name']);
|
||||
$recordLine = $dns->getRecordLine();
|
||||
if(!$recordLine) return $this->alert('error', '获取解析线路列表失败,'.$dns->getError());
|
||||
cache('record_line_'.$drow['id'], $recordLine, 604800);
|
||||
$minTTL = $dns->getMinTTL($drow['name']);
|
||||
$minTTL = $dns->getMinTTL();
|
||||
if($minTTL){
|
||||
cache('min_ttl_'.$drow['id'], $minTTL, 604800);
|
||||
}
|
||||
|
|
|
@ -112,4 +112,7 @@ class Index extends BaseController
|
|||
return view();
|
||||
}
|
||||
|
||||
public function test(){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
174
app/controller/Optimizeip.php
Normal file
174
app/controller/Optimizeip.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use Exception;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Cache;
|
||||
use app\lib\OptimizeService;
|
||||
|
||||
class Optimizeip extends BaseController
|
||||
{
|
||||
public function opipset()
|
||||
{
|
||||
if(!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
if(request()->isPost()){
|
||||
$params = input('post.');
|
||||
foreach ($params as $key=>$value){
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
Cache::delete('configs');
|
||||
}
|
||||
return json(['code'=>0, 'msg'=>'succ']);
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function opiplist()
|
||||
{
|
||||
if(!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function opiplist_data(){
|
||||
if(!checkPermission(2)) return json(['total'=>0, 'rows'=>[]]);
|
||||
$type = input('post.type/d', 1);
|
||||
$kw = input('post.kw', null, 'trim');
|
||||
$offset = input('post.offset/d');
|
||||
$limit = input('post.limit/d');
|
||||
|
||||
$select = Db::name('optimizeip')->alias('A')->join('domain B','A.did = B.id');
|
||||
if(!empty($kw)){
|
||||
if($type == 1){
|
||||
$select->whereLike('rr|B.name', '%'.$kw.'%');
|
||||
}elseif($type == 2){
|
||||
$select->whereLike('remark', '%'.$kw.'%');
|
||||
}
|
||||
}
|
||||
$total = $select->count();
|
||||
$list = $select->order('A.id','desc')->limit($offset, $limit)->field('A.*,B.name domain')->select();
|
||||
|
||||
return json(['total'=>$total, 'rows'=>$list]);
|
||||
}
|
||||
|
||||
public function opipform()
|
||||
{
|
||||
if(!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$action = input('param.action');
|
||||
if(request()->isPost()){
|
||||
if($action == 'add'){
|
||||
$task = [
|
||||
'did' => input('post.did/d'),
|
||||
'rr' => input('post.rr', null, 'trim'),
|
||||
'type' => input('post.type/d'),
|
||||
'ip_type' => input('post.ip_type', null, 'trim'),
|
||||
'cdn_type' => input('post.cdn_type/d'),
|
||||
'recordnum' => input('post.recordnum/d'),
|
||||
'ttl' => input('post.ttl/d'),
|
||||
'remark' => input('post.remark', null, 'trim'),
|
||||
'addtime' => time(),
|
||||
'active' => 1
|
||||
];
|
||||
|
||||
if(empty($task['did']) || empty($task['rr']) || empty($task['ip_type']) || empty($task['recordnum']) || empty($task['ttl'])){
|
||||
return json(['code'=>-1, 'msg'=>'必填项不能为空']);
|
||||
}
|
||||
if($task['recordnum'] > 5){
|
||||
return json(['code'=>-1, 'msg'=>'解析数量不能超过5个']);
|
||||
}
|
||||
if(Db::name('optimizeip')->where('did', $task['did'])->where('rr', $task['rr'])->find()){
|
||||
return json(['code'=>-1, 'msg'=>'当前域名的优选IP任务已存在']);
|
||||
}
|
||||
Db::name('optimizeip')->insert($task);
|
||||
return json(['code'=>0, 'msg'=>'添加成功']);
|
||||
}elseif($action == 'edit'){
|
||||
$id = input('post.id/d');
|
||||
$task = [
|
||||
'did' => input('post.did/d'),
|
||||
'rr' => input('post.rr', null, 'trim'),
|
||||
'type' => input('post.type/d'),
|
||||
'ip_type' => input('post.ip_type', null, 'trim'),
|
||||
'cdn_type' => input('post.cdn_type/d'),
|
||||
'recordnum' => input('post.recordnum/d'),
|
||||
'ttl' => input('post.ttl/d'),
|
||||
'remark' => input('post.remark', null, 'trim'),
|
||||
];
|
||||
|
||||
if(empty($task['did']) || empty($task['rr']) || empty($task['ip_type']) || empty($task['recordnum']) || empty($task['ttl'])){
|
||||
return json(['code'=>-1, 'msg'=>'必填项不能为空']);
|
||||
}
|
||||
if($task['recordnum'] > 5){
|
||||
return json(['code'=>-1, 'msg'=>'解析数量不能超过5个']);
|
||||
}
|
||||
if(Db::name('optimizeip')->where('did', $task['did'])->where('rr', $task['rr'])->where('id', '<>', $id)->find()){
|
||||
return json(['code'=>-1, 'msg'=>'当前域名的优选IP任务已存在']);
|
||||
}
|
||||
Db::name('optimizeip')->where('id', $id)->update($task);
|
||||
return json(['code'=>0, 'msg'=>'修改成功']);
|
||||
}elseif($action == 'setactive'){
|
||||
$id = input('post.id/d');
|
||||
$active = input('post.active/d');
|
||||
Db::name('optimizeip')->where('id', $id)->update(['active'=>$active]);
|
||||
return json(['code'=>0, 'msg'=>'设置成功']);
|
||||
}elseif($action == 'del'){
|
||||
$id = input('post.id/d');
|
||||
Db::name('optimizeip')->where('id', $id)->delete();
|
||||
return json(['code'=>0, 'msg'=>'删除成功']);
|
||||
}elseif($action == 'run'){
|
||||
$id = input('post.id/d');
|
||||
$task = Db::name('optimizeip')->where('id', $id)->find();
|
||||
if(empty($task)) return json(['code'=>-1, 'msg'=>'任务不存在']);
|
||||
try{
|
||||
$result = (new OptimizeService())->execute_one($task);
|
||||
Db::name('optimizeip')->where('id', $id)->update(['status' => 1, 'errmsg' => null, 'updatetime' => date('Y-m-d H:i:s')]);
|
||||
return json(['code'=>0, 'msg'=>'优选任务执行成功:'.$result]);
|
||||
}catch(Exception $e){
|
||||
Db::name('optimizeip')->where('id', $id)->update(['status' => 2, 'errmsg' => $e->getMessage(), 'updatetime' => date('Y-m-d H:i:s')]);
|
||||
return json(['code'=>-1, 'msg'=>'优选任务执行失败:'.$e->getMessage(), 'stack'=>$e->__toString()]);
|
||||
}
|
||||
}else{
|
||||
return json(['code'=>-1, 'msg'=>'参数错误']);
|
||||
}
|
||||
}
|
||||
$task = null;
|
||||
if($action == 'edit'){
|
||||
$id = input('get.id/d');
|
||||
$task = Db::name('optimizeip')->where('id', $id)->find();
|
||||
if(empty($task)) return $this->alert('error', '任务不存在');
|
||||
}
|
||||
|
||||
$domains = [];
|
||||
foreach(Db::name('domain')->alias('A')->join('account B','A.aid = B.id')->field('A.*')->where('B.type', '<>', 'cloudflare')->select() as $row){
|
||||
$domains[$row['id']] = $row['name'];
|
||||
}
|
||||
View::assign('domains', $domains);
|
||||
|
||||
View::assign('info', $task);
|
||||
View::assign('action', $action);
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function queryapi()
|
||||
{
|
||||
if(!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$optimize_ip_api = input('post.optimize_ip_api/d');
|
||||
$optimize_ip_key = input('post.optimize_ip_key', null, 'trim');
|
||||
if(empty($optimize_ip_key)) return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
||||
try{
|
||||
$result = (new OptimizeService())->get_license($optimize_ip_api, $optimize_ip_key);
|
||||
return json(['code'=>0, 'msg'=>'当前积分余额:'.$result]);
|
||||
}catch(Exception $e){
|
||||
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function status()
|
||||
{
|
||||
$run_time = Db::name('optimizeip')->where('active', 1)->order('updatetime', 'desc')->value('updatetime');
|
||||
$run_state = $run_time ? (time()-strtotime($run_time) > 3600 ? 0 : 1) : 0;
|
||||
return $run_state == 1 ? 'ok' : 'error';
|
||||
}
|
||||
}
|
204
app/lib/OptimizeService.php
Normal file
204
app/lib/OptimizeService.php
Normal file
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
use Exception;
|
||||
use think\facade\Db;
|
||||
|
||||
class OptimizeService
|
||||
{
|
||||
private static $line_name = [
|
||||
'aliyun' => ['DEF'=>'default', 'CT'=>'telecom', 'CU'=>'unicom', 'CM'=>'mobile', 'AB'=>'oversea'],
|
||||
'dnspod' => ['DEF'=>'0', 'CT'=>'10=0', 'CU'=>'10=1', 'CM'=>'10=3', 'AB'=>'3=0'],
|
||||
'huawei' => ['DEF'=>'default_view', 'CT'=>'Dianxin', 'CU'=>'Liantong', 'CM'=>'Yidong', 'AB'=>'Abroad'],
|
||||
'west' => ['DEF'=>'', 'CT'=>'LTEL', 'CU'=>'LCNC', 'CM'=>'LMOB', 'AB'=>'LFOR'],
|
||||
'dnsla' => ['DEF'=>'', 'CT'=>'84613316902921216', 'CU'=>'84613316923892736', 'CM'=>'84613316953252864', 'AB'=>''],
|
||||
];
|
||||
|
||||
private $ip_address = [];
|
||||
private $add_num = 0;
|
||||
private $change_num = 0;
|
||||
private $del_num = 0;
|
||||
|
||||
public static function get_license($api, $key){
|
||||
if($api == 1){
|
||||
$url = 'https://api.hostmonit.com/get_license?license='.$key;
|
||||
}else{
|
||||
$url = 'https://monitor.gacjie.cn/api/client/get_account_integral?license='.$key;
|
||||
}
|
||||
$response = get_curl($url);
|
||||
$arr = json_decode($response, true);
|
||||
if(isset($arr['code']) && $arr['code'] == 200 && isset($arr['count'])){
|
||||
return $arr['count'];
|
||||
}elseif(isset($arr['info'])){
|
||||
throw new Exception('获取剩余请求次数失败,'.$arr['info']);
|
||||
}else{
|
||||
throw new Exception('获取剩余请求次数失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function get_ip_address($cdn_type = 1, $ip_type = 'v4'){
|
||||
$api = config_get('optimize_ip_api', 0);
|
||||
if($api == 1){
|
||||
$url = 'https://api.hostmonit.com/get_optimization_ip';
|
||||
}else{
|
||||
$url = 'https://monitor.gacjie.cn/api/client/get_ip_address';
|
||||
}
|
||||
$params = [
|
||||
'key' => config_get('optimize_ip_key', 'o1zrmHAF'),
|
||||
'type' => $ip_type,
|
||||
];
|
||||
if($api == 0){
|
||||
$params['cdn_server'] = $cdn_type;
|
||||
}
|
||||
$response = get_curl($url, json_encode($params), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=UTF-8']);
|
||||
$arr = json_decode($response, true);
|
||||
if(isset($arr['code']) && $arr['code'] == 200){
|
||||
return $arr['info'];
|
||||
}elseif(isset($arr['info'])){
|
||||
throw new Exception('获取优选IP数据失败,'.$arr['info']);
|
||||
}elseif(isset($arr['msg'])){
|
||||
throw new Exception('获取优选IP数据失败,'.$arr['msg']);
|
||||
}else{
|
||||
throw new Exception('获取优选IP数据失败,原因未知');
|
||||
}
|
||||
}
|
||||
|
||||
public function get_ip_address2($cdn_type = 1, $ip_type = 'v4'){
|
||||
$key = $cdn_type.'_'.$ip_type;
|
||||
if(!isset($this->ip_address[$key])){
|
||||
$info = $this->get_ip_address($cdn_type, $ip_type);
|
||||
$res = [];
|
||||
if(isset($info['DEF'])) $res['DEF'] = $info['DEF'];
|
||||
if(isset($info['CT'])) $res['CT'] = $info['CT'];
|
||||
if(isset($info['CU'])) $res['CU'] = $info['CU'];
|
||||
if(isset($info['CM'])) $res['CM'] = $info['CM'];
|
||||
$this->ip_address[$key] = $res;
|
||||
}
|
||||
return $this->ip_address[$key];
|
||||
}
|
||||
|
||||
//批量执行优选任务
|
||||
public function execute(){
|
||||
$list = Db::name('optimizeip')->where('active', 1)->select();
|
||||
echo '开始执行IP优选任务,共获取到'.count($list).'个待执行任务'."\n";
|
||||
foreach($list as $row){
|
||||
try{
|
||||
$result = $this->execute_one($row);
|
||||
Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 1, 'errmsg' => null, 'updatetime' => date('Y-m-d H:i:s')]);
|
||||
echo '优选任务'.$row['id'].'执行成功:'.$result."\n";
|
||||
}catch(Exception $e){
|
||||
Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 2, 'errmsg' => $e->getMessage(), 'updatetime' => date('Y-m-d H:i:s')]);
|
||||
echo '优选任务'.$row['id'].'执行失败:'.$e->getMessage()."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//执行单个优选任务
|
||||
public function execute_one($row){
|
||||
$this->add_num = 0;
|
||||
$this->change_num = 0;
|
||||
$this->del_num = 0;
|
||||
$ip_types = explode(',', $row['ip_type']);
|
||||
foreach($ip_types as $ip_type){
|
||||
if(empty($ip_type)) continue;
|
||||
|
||||
$drow = Db::name('domain')->alias('A')->join('account B','A.aid = B.id')->where('A.id', $row['did'])->field('A.*,B.type,B.ak,B.sk,B.ext')->find();
|
||||
if(!$drow){
|
||||
throw new Exception('域名不存在(ID:'.$row['did'].')');
|
||||
}
|
||||
if(!isset(self::$line_name[$drow['type']])){
|
||||
throw new Exception('不支持的DNS服务商');
|
||||
}
|
||||
|
||||
$info = $this->get_ip_address2($row['cdn_type'], $ip_type);
|
||||
|
||||
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
|
||||
$domainRecords = $dns->getSubDomainRecords($row['rr'], 1, 100);
|
||||
if(!$domainRecords){
|
||||
throw new Exception('获取记录列表失败,'.$dns->getError());
|
||||
}
|
||||
|
||||
if($row['type'] == 1 && isset($info['DEF']) && !empty($info['DEF'])) $row['type'] = 0;
|
||||
|
||||
foreach($info as $line=>$iplist){
|
||||
if(empty($iplist)) continue;
|
||||
$get_ips = array_column($iplist, 'ip');
|
||||
if($drow['type']=='huawei') {sort($get_ips); $get_ips = [implode(',',$get_ips)]; $row['recordnum'] = 1;}
|
||||
if($row['type'] == 1 && $line == 'CT') $line = 'DEF';
|
||||
$line_name = self::$line_name[$drow['type']][$line];
|
||||
$this->process_dns_line($dns, $row, $domainRecords['list'], $get_ips, $line_name, $ip_type);
|
||||
}
|
||||
}
|
||||
|
||||
return '成功添加'.$this->add_num.'条记录,修改'.$this->change_num.'条记录,删除'.$this->del_num.'条记录';
|
||||
}
|
||||
|
||||
//处理单个线路的解析记录
|
||||
private function process_dns_line($dns, $row, $record_list, $get_ips, $line_name, $ip_type){
|
||||
$record_num = $row['recordnum'];
|
||||
$records = array_filter($record_list, function($v) use($line_name){
|
||||
return $v['Line'] == $line_name;
|
||||
});
|
||||
|
||||
//删除CNAME记录
|
||||
$cname_records = array_filter($records, function($v){
|
||||
return $v['Type'] == 'CNAME';
|
||||
});
|
||||
if(!empty($cname_records)){
|
||||
foreach($cname_records as $record){
|
||||
$dns->deleteDomainRecord($record['RecordId']);
|
||||
}
|
||||
}
|
||||
|
||||
//处理A/AAAA记录
|
||||
$ip_records = array_filter($records, function($v) use ($ip_type){
|
||||
return $v['Type'] == ($ip_type == 'v6' ? 'AAAA' : 'A');
|
||||
});
|
||||
|
||||
if(!empty($ip_records) && is_array($ip_records[array_key_first($ip_records)]['Value'])){ //处理华为云记录
|
||||
foreach($ip_records as &$ip_record){
|
||||
sort($ip_record['Value']);
|
||||
$ip_record['Value'] = implode(',', $ip_record['Value']);
|
||||
}
|
||||
}
|
||||
|
||||
$exist_ips = array_column($ip_records, 'Value');
|
||||
$add_ips = array_diff($get_ips, $exist_ips);
|
||||
$del_ips = array_diff($exist_ips, $get_ips);
|
||||
$correct_ips = array_diff($exist_ips, $del_ips);
|
||||
$correct_count = count($correct_ips);
|
||||
if(!empty($del_ips)){
|
||||
foreach($ip_records as $record){
|
||||
if(in_array($record['Value'], $del_ips)){
|
||||
$add_ip = array_pop($add_ips);
|
||||
if($add_ip){
|
||||
$res = $dns->updateDomainRecord($record['RecordId'], $row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']);
|
||||
if(!$res){
|
||||
throw new Exception('修改解析失败,'.$dns->getError());
|
||||
}
|
||||
$this->change_num++;
|
||||
$correct_count++;
|
||||
}else{
|
||||
$res = $dns->deleteDomainRecord($record['RecordId']);
|
||||
if(!$res){
|
||||
throw new Exception('删除解析失败,'.$dns->getError());
|
||||
}
|
||||
$this->del_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($correct_count < $record_num && !empty($add_ips)){
|
||||
foreach($add_ips as $add_ip){
|
||||
$res = $dns->addDomainRecord($row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']);
|
||||
if(!$res){
|
||||
throw new Exception('添加解析失败,'.$dns->getError());
|
||||
}
|
||||
$this->add_num++;
|
||||
$correct_count++;
|
||||
if($correct_count >= $record_num) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,17 @@ class TaskRunner
|
|||
|
||||
public function execute($row)
|
||||
{
|
||||
if($row['type'] == 3){ //条件开启解析
|
||||
$action = 0;
|
||||
$remain = $this->db()->name('dmtask')->where(['did'=>$row['did'], 'rr'=>$row['rr'], 'type'=>1, 'status'=>0])->count();
|
||||
if($remain<=$row['cycle'] && $row['status']==0){
|
||||
$action = 2;
|
||||
$this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>1, 'errcount'=>0, 'switchtime'=>time()]);
|
||||
}elseif($remain>$row['cycle'] && $row['status']==1){
|
||||
$action = 1;
|
||||
$this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>0, 'errcount'=>0, 'switchtime'=>time()]);
|
||||
}
|
||||
}else{
|
||||
if($row['checktype'] == 2){
|
||||
$result = CheckUtils::curl($row['checkurl'], $row['timeout'], $row['main_value']);
|
||||
}else if($row['checktype'] == 1){
|
||||
|
@ -53,6 +64,7 @@ class TaskRunner
|
|||
}elseif($row['errcount'] > 0){
|
||||
$this->db()->name('dmtask')->where('id', $row['id'])->update(['errcount'=>0]);
|
||||
}
|
||||
}
|
||||
|
||||
if($action > 0){
|
||||
$drow = $this->db()->name('domain')->alias('A')->join('account B','A.aid = B.id')->where('A.id', $row['did'])->field('A.*,B.type,B.ak,B.sk,B.ext')->find();
|
||||
|
@ -71,7 +83,7 @@ class TaskRunner
|
|||
if(!$res){
|
||||
$this->db()->name('log')->insert(['uid' => 0, 'domain' => $drow['name'], 'action' => '修改解析失败', 'data' => $dns->getError(), 'addtime' => date("Y-m-d H:i:s")]);
|
||||
}
|
||||
}elseif($row['type'] == 1){
|
||||
}elseif($row['type'] == 1 || $row['type'] == 3){
|
||||
$dns = DnsHelper::getModel2($drow);
|
||||
$res = $dns->setDomainRecordStatus($row['recordid'], '0');
|
||||
if(!$res){
|
||||
|
@ -86,7 +98,7 @@ class TaskRunner
|
|||
if(!$res){
|
||||
$this->db()->name('log')->insert(['uid' => 0, 'domain' => $drow['name'], 'action' => '修改解析失败', 'data' => $dns->getError(), 'addtime' => date("Y-m-d H:i:s")]);
|
||||
}
|
||||
}elseif($row['type'] == 1){
|
||||
}elseif($row['type'] == 1 || $row['type'] == 3){
|
||||
$dns = DnsHelper::getModel2($drow);
|
||||
$res = $dns->setDomainRecordStatus($row['recordid'], '1');
|
||||
if(!$res){
|
||||
|
@ -101,11 +113,13 @@ class TaskRunner
|
|||
$this->db()->name('dmlog')->insert([
|
||||
'taskid' => $row['id'],
|
||||
'action' => $action,
|
||||
'errmsg' => $result['status'] ? null : $result['errmsg'],
|
||||
'errmsg' => isset($result) ? ($result['status'] ? null : $result['errmsg']) : null,
|
||||
'date' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
$this->closeDb();
|
||||
|
||||
if($row['type'] != 3){
|
||||
MsgNotice::send($action, $row, $result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,6 +84,8 @@ class dnspod implements DnsInterface {
|
|||
];
|
||||
}
|
||||
return ['total' => $data['RecordCountInfo']['TotalCount'], 'list' => $list];
|
||||
}elseif($this->error == '记录列表为空。'){
|
||||
return ['total' => 0, 'list' => []];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ class huawei implements DnsInterface {
|
|||
public function getDomainRecordInfo($RecordId){
|
||||
$data = $this->send_reuqest('GET', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId);
|
||||
if($data){
|
||||
if($data['name'] == $data['zone_name']) $data['name'] = '@';
|
||||
return [
|
||||
'RecordId' => $data['id'],
|
||||
'Domain' => rtrim($data['zone_name'], '.'),
|
||||
|
|
|
@ -5,7 +5,7 @@ CREATE TABLE `dnsmgr_config` (
|
|||
PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO `dnsmgr_config` VALUES ('version', '1003');
|
||||
INSERT INTO `dnsmgr_config` VALUES ('version', '1005');
|
||||
INSERT INTO `dnsmgr_config` VALUES ('notice_mail', '0');
|
||||
INSERT INTO `dnsmgr_config` VALUES ('notice_wxtpl', '0');
|
||||
INSERT INTO `dnsmgr_config` VALUES ('mail_smtp', 'smtp.qq.com');
|
||||
|
@ -64,7 +64,7 @@ CREATE TABLE `dnsmgr_permission` (
|
|||
|
||||
DROP TABLE IF EXISTS `dnsmgr_log`;
|
||||
CREATE TABLE `dnsmgr_log` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uid` int(11) unsigned NOT NULL,
|
||||
`action` varchar(40) NOT NULL,
|
||||
`domain` varchar(128) NOT NULL DEFAULT '',
|
||||
|
@ -77,7 +77,7 @@ CREATE TABLE `dnsmgr_log` (
|
|||
|
||||
DROP TABLE IF EXISTS `dnsmgr_dmtask`;
|
||||
CREATE TABLE `dnsmgr_dmtask` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`did` int(11) unsigned NOT NULL,
|
||||
`rr` varchar(128) NOT NULL,
|
||||
`recordid` varchar(60) NOT NULL,
|
||||
|
@ -105,7 +105,7 @@ CREATE TABLE `dnsmgr_dmtask` (
|
|||
|
||||
DROP TABLE IF EXISTS `dnsmgr_dmlog`;
|
||||
CREATE TABLE `dnsmgr_dmlog` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`taskid` int(11) unsigned NOT NULL,
|
||||
`action` tinyint(4) NOT NULL DEFAULT 0,
|
||||
`errmsg` varchar(100) DEFAULT NULL,
|
||||
|
@ -114,3 +114,23 @@ CREATE TABLE `dnsmgr_dmlog` (
|
|||
KEY `taskid` (`taskid`),
|
||||
KEY `date` (`date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
DROP TABLE IF EXISTS `dnsmgr_optimizeip`;
|
||||
CREATE TABLE `dnsmgr_optimizeip` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`did` int(11) unsigned NOT NULL,
|
||||
`rr` varchar(128) NOT NULL,
|
||||
`type` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`ip_type` varchar(10) NOT NULL,
|
||||
`cdn_type` tinyint(5) NOT NULL DEFAULT 1,
|
||||
`recordnum` tinyint(5) NOT NULL DEFAULT 2,
|
||||
`ttl` int(5) NOT NULL DEFAULT 600,
|
||||
`remark` varchar(100) DEFAULT NULL,
|
||||
`addtime` datetime NOT NULL,
|
||||
`updatetime` datetime DEFAULT NULL,
|
||||
`status` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`errmsg` varchar(100) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `did` (`did`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_config` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dnsmgr_dmtask` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`did` int(11) unsigned NOT NULL,
|
||||
`rr` varchar(128) NOT NULL,
|
||||
`recordid` varchar(60) NOT NULL,
|
||||
|
@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_dmtask` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dnsmgr_dmlog` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`taskid` int(11) unsigned NOT NULL,
|
||||
`action` tinyint(4) NOT NULL DEFAULT 0,
|
||||
`errmsg` varchar(100) DEFAULT NULL,
|
||||
|
@ -41,3 +41,22 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_dmlog` (
|
|||
KEY `taskid` (`taskid`),
|
||||
KEY `date` (`date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dnsmgr_optimizeip` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`did` int(11) unsigned NOT NULL,
|
||||
`rr` varchar(128) NOT NULL,
|
||||
`type` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`ip_type` varchar(10) NOT NULL,
|
||||
`cdn_type` tinyint(5) NOT NULL DEFAULT 1,
|
||||
`recordnum` tinyint(5) NOT NULL DEFAULT 2,
|
||||
`ttl` int(5) NOT NULL DEFAULT 600,
|
||||
`remark` varchar(100) DEFAULT NULL,
|
||||
`addtime` datetime NOT NULL,
|
||||
`updatetime` datetime DEFAULT NULL,
|
||||
`status` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`errmsg` varchar(100) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `did` (`did`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
@ -121,6 +121,19 @@
|
|||
<li><a href="/dmonitor/noticeset"><i class="fa fa-circle-o"></i> 通知设置</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="treeview {:checkIfActive('opipset,opiplist,opipform')}">
|
||||
<a href="javascript:;">
|
||||
<i class="fa fa-globe fa-fw"></i>
|
||||
<span>CF优选IP</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li><a href="/optimizeip/opipset"><i class="fa fa-circle-o"></i> 优选设置</a></li>
|
||||
<li><a href="/optimizeip/opiplist"><i class="fa fa-circle-o"></i> 任务管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="{:checkIfActive('account')}">
|
||||
<a href="/account"><i class="fa fa-lock fa-fw"></i> <span>域名账户</span></a>
|
||||
</li>
|
||||
|
|
|
@ -75,6 +75,8 @@ $(document).ready(function(){
|
|||
return '暂停解析';
|
||||
} else if(value == 2) {
|
||||
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="备用:'+row.backup_value+'" class="tips">切换备用</span>';
|
||||
} else if(value == 3) {
|
||||
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="同域名正常数量<='+row.cycle+'" class="tips">条件开启</span>';
|
||||
} else {
|
||||
return '无操作';
|
||||
}
|
||||
|
@ -84,12 +86,16 @@ $(document).ready(function(){
|
|||
field: 'frequency',
|
||||
title: '检测间隔',
|
||||
formatter: function(value, row, index) {
|
||||
if(row.type <= 2){
|
||||
var checktype = 'PING';
|
||||
if(row.checktype == 2){
|
||||
checktype = row.checkurl;
|
||||
}else if(row.checktype == 1){
|
||||
checktype = 'TCP('+row.tcpport+'端口)';
|
||||
}
|
||||
}else{
|
||||
var checktype = '';
|
||||
}
|
||||
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+checktype+'" class="tips">' + value + '秒</span>';
|
||||
}
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
.tips{color: #f6a838; padding-left: 5px;}
|
||||
</style>
|
||||
<div class="row" id="app">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
|
@ -49,7 +50,7 @@
|
|||
<input type="text" name="backup_value" v-model="set.backup_value" placeholder="支持填写IPv4或CNAME地址" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" v-show="set.type<=2">
|
||||
<label class="col-sm-3 control-label no-padding-right">检测协议</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="option in checktypeList">
|
||||
|
@ -57,19 +58,19 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.checktype==1">
|
||||
<div class="form-group" v-show="set.type<=2&&set.checktype==1">
|
||||
<label class="col-sm-3 control-label no-padding-right">TCP检测端口</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="tcpport" v-model="set.tcpport" placeholder="填写TCP端口号" class="form-control" data-bv-integer="true" min="1" max="65535" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.checktype==2">
|
||||
<div class="form-group" v-show="set.type<=2&&set.checktype==2">
|
||||
<label class="col-sm-3 control-label no-padding-right">检测URL地址</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="checkurl" v-model="set.checkurl" placeholder="填写以http(s)://开头的完整地址,http状态码须为2xx/3xx" class="form-control" data-bv-uri="true" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.checktype>0">
|
||||
<div class="form-group" v-show="set.type<=2&&set.checktype>0">
|
||||
<label class="col-sm-3 control-label no-padding-right">最大超时时间</label>
|
||||
<div class="col-sm-3">
|
||||
<div class="input-group">
|
||||
|
@ -78,6 +79,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.type==3">
|
||||
<label class="col-sm-3 control-label no-padding-right">同域名正常数量<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="与暂停解析配合使用,当同域名正常记录数量<=几条时开启解析"><i class="fa fa-question-circle"></i></span></label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" name="cycle" v-model="set.cycle" placeholder="同域名正常记录数量<=几条时开启解析" class="form-control" data-bv-integer="true" min="0" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">检测间隔</label>
|
||||
<div class="col-sm-3">
|
||||
|
@ -87,7 +94,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" v-show="set.type<=2">
|
||||
<label class="col-sm-3 control-label no-padding-right">确认次数</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" name="cycle" v-model="set.cycle" placeholder="连续失败几次后进行切换" class="form-control" data-bv-integer="true" min="1" required>
|
||||
|
@ -128,7 +135,7 @@ new Vue({
|
|||
main_value: '',
|
||||
type: 1,
|
||||
backup_value: '',
|
||||
checktype: 2,
|
||||
checktype: 1,
|
||||
tcpport: 80,
|
||||
checkurl: '',
|
||||
frequency: 5,
|
||||
|
@ -140,6 +147,7 @@ new Vue({
|
|||
{value:0, label:'无操作'},
|
||||
{value:1, label:'暂停解析'},
|
||||
{value:2, label:'切换备用解析'},
|
||||
{value:3, label:'条件开启解析'},
|
||||
],
|
||||
checktypeList: [
|
||||
{value:0, label:'PING', disabled: support_ping=='0'},
|
||||
|
@ -169,6 +177,7 @@ new Vue({
|
|||
$("#taskform").bootstrapValidator({
|
||||
live: 'submitted',
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
},
|
||||
methods: {
|
||||
getRecordList(){
|
||||
|
|
|
@ -169,6 +169,10 @@ function speedModeNotice(){
|
|||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\">当前浏览器是兼容模式,为确保后台功能正常使用,请切换到<b style='color:#51b72f'>极速模式</b>!<br>操作方法:点击浏览器地址栏右侧的IE符号<b style='color:#51b72f;'><i class='fa fa-internet-explorer fa-fw'></i></b>→选择“<b style='color:#51b72f;'><i class='fa fa-flash fa-fw'></i></b><b style='color:#51b72f;'>极速模式</b>”</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
else if(window.location.protocol.indexOf("https")==-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\"><b style='color:#CC3022;'><i class='fa fa-info-circle fa-fw'></i></b>当前正在使用HTTP访问,可能存在被窃取敏感信息风险,请使用HTTPS访问!</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
}
|
||||
speedModeNotice();
|
||||
</script>
|
||||
|
|
181
app/view/optimizeip/opipform.html
Normal file
181
app/view/optimizeip/opipform.html
Normal file
|
@ -0,0 +1,181 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}优选IP任务{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
.dselect::before{
|
||||
content: '.';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
.tips{color: #f6a838; padding-left: 5px;}
|
||||
</style>
|
||||
<div class="row" id="app">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h3 class="panel-title"><a href="/optimizeip/opiplist" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}优选IP任务</h3></div>
|
||||
<div class="panel-body">
|
||||
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-xs-12 control-label no-padding-right">域名选择</label>
|
||||
<div class="col-sm-3 col-xs-5"><input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required></div>
|
||||
<div class="col-sm-3 col-xs-7 dselect"><select name="did" v-model="set.did" class="form-control" required>
|
||||
<option value="">--主域名--</option>
|
||||
{foreach $domains as $k=>$v}
|
||||
<option value="{$k}">{$v}</option>
|
||||
{/foreach}
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">CDN服务商</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="(value,key) in cdntypeList">
|
||||
<input type="radio" name="cdntype" :value="key" v-model="set.cdn_type"> {{value}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">解析线路类型</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="type" value="0" v-model="set.type"> 电信/联通/移动线路<span class="tips" title="用于已在CF添加,需优化三网访问速度的域名" data-toggle="tooltip" data-placement="bottom" data-original-title=""><i class="fa fa-question-circle"></i></span>
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="type" value="1" v-model="set.type"> 默认/联通/移动线路<span class="tips" title="将电信优选IP解析到默认线路,用于给其他域名提供CNAME服务" data-toggle="tooltip" data-placement="bottom" data-original-title=""><i class="fa fa-question-circle"></i></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">解析IP类型<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="同时开启IPv6&IPv4将会请求2次接口消耗双倍积分"><i class="fa fa-question-circle"></i></span></label>
|
||||
<div class="col-sm-6">
|
||||
<label class="checkbox-inline" v-for="option in iptypeList">
|
||||
<input type="checkbox" name="ip_type" :value="option.value" v-model="set.ip_type_select" required> {{option.label}}
|
||||
</label><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">每线路解析数量<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="数量不要超过当前域名套餐允许的最大数量,否则会添加解析失败"><i class="fa fa-question-circle"></i></span></label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="recordnum" v-model="set.recordnum" placeholder="填写每线路解析数量" class="form-control" data-bv-integer="true" min="1" max="5" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">TTL<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL不要低于当前域名套餐允许的最小值,否则会添加解析失败"><i class="fa fa-question-circle"></i></span></label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="ttl" v-model="set.ttl" placeholder="填写TTL" class="form-control" data-bv-integer="true" min="1" max="3600" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">备注</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.type==0">
|
||||
<div class="col-sm-offset-3 col-sm-6">
|
||||
<div class="alert alert-dismissible alert-info">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<strong>提示:</strong>所选域名需保留一个默认线路的解析记录,指向{{cdntypeList[set.cdn_type]}}提供的CNAME地址,其他线路的解析记录需要删除,添加任务后将自动为当前域名添加电信/联通/移动线路的解析记录。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.type==1">
|
||||
<div class="col-sm-offset-3 col-sm-6">
|
||||
<div class="alert alert-dismissible alert-info">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<strong>提示:</strong>所选域名需删除全部解析记录,添加任务后将自动为当前域名添加解析记录。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="/static/js/bootstrapValidator.min.js"></script>
|
||||
<script>
|
||||
var action = '{$action}';
|
||||
var info = {$info|json_encode|raw};
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
action: '{$action}',
|
||||
set: {
|
||||
id: '',
|
||||
remark: '',
|
||||
rr: '',
|
||||
did: '',
|
||||
type: 0,
|
||||
cdn_type: 1,
|
||||
ip_type_select: ['v4'],
|
||||
ip_type: 'v4',
|
||||
recordnum: 2,
|
||||
ttl: 600,
|
||||
},
|
||||
iptypeList: [
|
||||
{value:'v4', label:'IPv4(A记录)'},
|
||||
{value:'v6', label:'IPv6(AAAA记录)'},
|
||||
],
|
||||
cdntypeList: {
|
||||
1:'CloudFlare',
|
||||
2:"CloudFront",
|
||||
3:'Gcore'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'set.ip_type_select': function(val){
|
||||
this.set.ip_type = val.join(',');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if(this.action == 'edit'){
|
||||
Object.keys(info).forEach((key) => {
|
||||
this.$set(this.set, key, info[key])
|
||||
})
|
||||
this.set.ip_type_select = this.set.ip_type.split(',')
|
||||
}
|
||||
$("#taskform").bootstrapValidator({
|
||||
live: 'submitted',
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
},
|
||||
methods: {
|
||||
submit(){
|
||||
var that=this;
|
||||
$("#taskform").data("bootstrapValidator").validate();
|
||||
if(!$("#taskform").data("bootstrapValidator").isValid()){
|
||||
return false;
|
||||
}
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "",
|
||||
data: this.set,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg, {icon: 1}, function(){
|
||||
if(document.referrer.indexOf('/opiplist?') > 0)
|
||||
window.location.href = document.referrer;
|
||||
else
|
||||
window.location.href = '/optimizeip/opiplist';
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
},
|
||||
error: function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{/block}
|
184
app/view/optimizeip/opiplist.html
Normal file
184
app/view/optimizeip/opiplist.html
Normal file
|
@ -0,0 +1,184 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}CF优选IP任务管理{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
|
||||
</style>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<div class="form-group">
|
||||
<select name="type" class="form-control"><option value="1">域名</option><option value="2">备注</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="kw" placeholder="">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名账户列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
<a href="/optimizeip/opipform/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/optimizeip/opiplist/data',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID'
|
||||
},
|
||||
{
|
||||
field: 'rr',
|
||||
title: '域名',
|
||||
formatter: function(value, row, index) {
|
||||
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right" title="Tooltip on right">' + value + '.' + row.domain + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'cdn_type',
|
||||
title: 'CDN运营商',
|
||||
formatter: function(value, row, index) {
|
||||
if(value == 1){
|
||||
return 'CloudFlare';
|
||||
}else if(value == 2){
|
||||
return 'CloudFront';
|
||||
}else if(value == 3){
|
||||
return 'Gcore';
|
||||
}else{
|
||||
return '未知';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'recordnum',
|
||||
title: '解析数量',
|
||||
formatter: function(value, row, index) {
|
||||
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL:'+row.ttl+'" class="tips">'+value+'</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'ip_type',
|
||||
title: '解析IP类型',
|
||||
formatter: function(value, row, index) {
|
||||
var value = value.split(',')
|
||||
value.forEach((element, index) => {
|
||||
if(element == 'v4') value[index] = 'IPv4'
|
||||
else if(element == 'v6') value[index] = 'IPv6'
|
||||
});
|
||||
return value.join(',');
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'active',
|
||||
title: '任务开关',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '';
|
||||
if(value == 1) {
|
||||
html += '<span class="btn btn-success btn-xs" onclick="setActive('+row.id+', 0)">开启</span>';
|
||||
} else {
|
||||
html += '<span class="btn btn-warning btn-xs" onclick="setActive('+row.id+', 1)">关闭</span>';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'updatetime',
|
||||
title: '上次更新时间',
|
||||
formatter: function(value, row, index) {
|
||||
return value ? value : '无';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '上次更新结果',
|
||||
formatter: function(value, row, index) {
|
||||
if(value == 1) {
|
||||
return '<span class="label label-success">成功</span>';
|
||||
} else if(value == 2) {
|
||||
return '<span class="label label-danger">失败</span> <span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+row.errmsg+'" class="tips"><i class="fa fa-info-circle"></i></span>';
|
||||
} else {
|
||||
return '<span class="label label-warning">未运行</span>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:runTask(\''+row.id+'\')" class="btn btn-success btn-xs">手动更新</a> ';
|
||||
html += '<a href="/optimizeip/opipform/edit?id='+row.id+'" class="btn btn-primary btn-xs">修改</a> ';
|
||||
html += '<a href="/record/'+row.did+'?keyword='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a> ';
|
||||
html += '<a href="javascript:delItem(\''+row.id+'\')" class="btn btn-danger btn-xs">删除</a> ';
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
onLoadSuccess: function(data) {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
}
|
||||
})
|
||||
})
|
||||
function setActive(id, active){
|
||||
$.post('/optimizeip/opipform/setactive', {id: id, active: active}, function(data){
|
||||
if(data.code == 0) {
|
||||
layer.msg('修改成功', {icon: 1, time:800});
|
||||
$('#listTable').bootstrapTable('refresh');
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
function delItem(id){
|
||||
layer.confirm('确定要删除此切换策略吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
$.post('/optimizeip/opipform/del', {id: id}, function(data){
|
||||
if(data.code == 0) {
|
||||
layer.msg('删除成功', {icon: 1, time:800});
|
||||
$('#listTable').bootstrapTable('refresh');
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
});
|
||||
}
|
||||
function runTask(id){
|
||||
var ii = layer.msg('正在更新中...', {icon: 16,shade: 0.1,time: 0});
|
||||
$.post('/optimizeip/opipform/run', {id: id}, function(data){
|
||||
layer.close(ii);
|
||||
if(data.code == 0) {
|
||||
layer.alert(data.msg, {icon: 1});
|
||||
$('#listTable').bootstrapTable('refresh');
|
||||
} else {
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
</script>
|
||||
{/block}
|
105
app/view/optimizeip/opipset.html
Normal file
105
app/view/optimizeip/opipset.html
Normal file
|
@ -0,0 +1,105 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}CF优选IP设置{/block}
|
||||
{block name="main"}
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading"><h3 class="panel-title">功能简介</h3></div>
|
||||
<div class="panel-body">
|
||||
<p>由于CloudFlare官方IP是泛播路由,同一个IP在不同地区不同运营商所链接的机房是不同的,速度或延迟也会有区别。目前网上也有很多CF优选CNAME服务,然而公共的CNAME可能无法满足稳定性和安全性的需要。</p>
|
||||
<p>本功能可以获取CloudFlare最新的优选IP地址(分为电信/联通/移动线路),并自动更新到域名解析记录。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-warning">
|
||||
<div class="panel-heading"><h3 class="panel-title">使用说明</h3></div>
|
||||
<div class="panel-body">
|
||||
<p><li>数据接口:<a href="https://monitor.gacjie.cn/" target="_blank" rel="noreferrer">GacJieMonitor</a> 数据接口支持CloudFlare、CloudFront、Gcore;<a href="https://hostmonit.com/" target="_blank" rel="noreferrer">HostMonit</a> 只支持CloudFlare。</li></p>
|
||||
<p><li>接口密钥:默认o1zrmHAF为免费KEY可永久免费使用。</li></p>
|
||||
<p><li>计划任务:将以下命令添加到计划任务,周期设置为15分钟以上</li></p>
|
||||
<p><code>cd {:app()->getRootPath()} && php think opiptask</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading"><h3 class="panel-title">数据接口设置</h3></div>
|
||||
<div class="panel-body">
|
||||
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">数据接口</label>
|
||||
<div class="col-sm-9"><select class="form-control" name="optimize_ip_api" default="{:config_get('optimize_ip_api')}"><option value="0">GacJieMonitor</option><option value="1">HostMonit</option></select></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">接口密钥</label>
|
||||
<div class="col-sm-9"><input type="text" name="optimize_ip_key" value="{:config_get('optimize_ip_key', 'o1zrmHAF')}" class="form-control"/></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
|
||||
<a href="javascript:queryapi()" class="btn btn-default btn-block">查询积分</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script>
|
||||
var items = $("select[default]");
|
||||
for (i = 0; i < items.length; i++) {
|
||||
$(items[i]).val($(items[i]).attr("default")||0);
|
||||
}
|
||||
function saveSetting(obj){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '',
|
||||
data : $(obj).serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert('设置保存成功!', {
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
window.location.reload()
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
function queryapi(){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/optimizeip/queryapi',
|
||||
data : $("form").serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg, {icon: 1});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{/block}
|
|
@ -31,7 +31,7 @@ return [
|
|||
'show_error_msg' => true,
|
||||
'exception_tmpl' => \think\facade\App::getAppPath() . 'view/exception.tpl',
|
||||
|
||||
'version' => '1004',
|
||||
'version' => '1005',
|
||||
|
||||
'dbversion' => '1003'
|
||||
'dbversion' => '1005'
|
||||
];
|
||||
|
|
|
@ -6,5 +6,6 @@ return [
|
|||
// 指令定义
|
||||
'commands' => [
|
||||
'dmtask' => 'app\command\Dmtask',
|
||||
'opiptask' => 'app\command\Opiptask',
|
||||
],
|
||||
];
|
||||
|
|
|
@ -24,12 +24,14 @@ Route::any('/login', 'auth/login')->middleware(\think\middleware\SessionInit::cl
|
|||
Route::get('/logout', 'auth/logout');
|
||||
Route::any('/quicklogin', 'auth/quicklogin');
|
||||
Route::any('/dmtask/status', 'dmonitor/status');
|
||||
Route::any('/optimizeip/status', 'optimizeip/status');
|
||||
|
||||
Route::group(function () {
|
||||
Route::any('/', 'index/index');
|
||||
Route::post('/changeskin', 'index/changeskin');
|
||||
Route::get('/cleancache', 'index/cleancache');
|
||||
Route::any('/setpwd', 'index/setpwd');
|
||||
Route::get('/test', 'index/test');
|
||||
|
||||
Route::post('/user/data', 'user/user_data');
|
||||
Route::post('/user/op', 'user/user_op');
|
||||
|
@ -68,6 +70,12 @@ Route::group(function () {
|
|||
Route::get('/dmonitor/mailtest', 'dmonitor/mailtest');
|
||||
Route::post('/dmonitor/clean', 'dmonitor/clean');
|
||||
|
||||
Route::any('/optimizeip/opipset', 'optimizeip/opipset');
|
||||
Route::post('/optimizeip/queryapi', 'optimizeip/queryapi');
|
||||
Route::post('/optimizeip/opiplist/data', 'optimizeip/opiplist_data');
|
||||
Route::get('/optimizeip/opiplist', 'optimizeip/opiplist');
|
||||
Route::any('/optimizeip/opipform/:action', 'optimizeip/opipform');
|
||||
|
||||
})->middleware(\app\middleware\CheckLogin::class)
|
||||
->middleware(\app\middleware\ViewOutput::class);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user