where('id', $tid)->find(); if (!$task) throw new Exception('该自动部署任务不存在', 102); $this->task = $task; $this->aid = $task['aid']; $this->client = DeployHelper::getModel($this->aid); if (!$this->client) throw new Exception('该自动部署任务类型不存在', 102); $this->info = $task['info'] ? json_decode($task['info'], true) : []; } public function process($isManual = false) { if ($this->task['status'] >= 1) return; if ($this->task['retry'] >= 6 && !$isManual) { throw new Exception('已超出最大重试次数('.$this->task['error'].')', 103); } $order = Db::name('cert_order')->where('id', $this->task['oid'])->find(); if(!$order) throw new Exception('SSL证书订单不存在', 102); if($order['status'] == 4) throw new Exception('SSL证书订单已吊销', 102); if($order['status'] != 3) throw new Exception('SSL证书订单未完成签发', 102); if(empty($order['fullchain']) || empty($order['privatekey'])) throw new Exception('SSL证书或私钥内容不存在', 102); $this->lockTaskData(); try { $this->deploy($order['fullchain'], $order['privatekey']); } finally { $this->unlockTaskData(); } } //部署证书 public function deploy($fullchain, $privatekey) { $this->client->setLogger(function ($txt) { $this->saveLog($txt); }); $this->saveLog(date('Y-m-d H:i:s')); $config = json_decode($this->task['config'], true); $config['domainList'] = Db::name('cert_domain')->where('oid', $this->task['oid'])->order('sort', 'asc')->column('domain'); try { $this->client->deploy($fullchain, $privatekey, $config, $this->info); $this->saveResult(1); $this->saveLog('[Success] 证书部署成功'); } catch (Exception $e) { $this->saveResult(-1, $e->getMessage(), date('Y-m-d H:i:s', time() + (array_key_exists($this->task['retry'], self::$retry_interval) ? self::$retry_interval[$this->task['retry']] : 3600))); throw $e; } finally { if($this->info){ Db::name('cert_deploy')->where('id', $this->task['id'])->update(['info' => json_encode($this->info)]); } } } //重置任务 public function reset() { Db::name('cert_deploy')->where('id', $this->task['id'])->data(['status' => 0, 'retry' => 0, 'retrytime' => null, 'issend' => 0, 'islock' => 0])->update(); //$file_name = app()->getRuntimePath().'log/'.$this->task['processid'].'.log'; //if (file_exists($file_name)) unlink($file_name); $this->task['status'] = 0; $this->task['retry'] = 0; } private function saveResult($status, $error = null, $retrytime = null) { $this->task['status'] = $status; if (!empty($error) && strlen($error) > 300) { $error = mb_strcut($error, 0, 300); } $update = ['status' => $status, 'error' => $error, 'retrytime' => $retrytime]; if ($status == 1){ $update['retry'] = 0; $update['lasttime'] = date('Y-m-d H:i:s'); } $res = Db::name('cert_deploy')->where('id', $this->task['id'])->data($update); if ($status < 0 || $retrytime) { $this->task['retry']++; $res->inc('retry'); } $res->update(); if ($error) { $this->saveLog('[Error] ' . $error); } } private function lockTaskData() { Db::startTrans(); try { $isLock = Db::name('cert_deploy')->where('id', $this->task['id'])->lock(true)->value('islock'); if ($isLock == 1 && time() - strtotime($this->task['locktime']) < 3600) { throw new Exception('部署任务处理中,请稍后再试'); } $update = ['islock' => 1, 'locktime' => date('Y-m-d H:i:s')]; if (empty($this->task['processid'])) $this->task['processid'] = $update['processid'] = getSid(); Db::name('cert_deploy')->where('id', $this->task['id'])->update($update); Db::commit(); } catch (Exception $e) { Db::rollback(); throw $e; } } private function unlockTaskData() { Db::name('cert_deploy')->where('id', $this->task['id'])->update(['islock' => 0]); } private function saveLog($txt) { if (empty($this->task['processid'])) return; if (!is_dir(app()->getRuntimePath() . 'log')) mkdir(app()->getRuntimePath() . 'log'); $file_name = app()->getRuntimePath().'log/'.$this->task['processid'].'.log'; $file_exists = file_exists($file_name); file_put_contents($file_name, $txt . PHP_EOL, FILE_APPEND); if (!$file_exists) { @chmod($file_name, 0777); } if(php_sapi_name() == 'cli'){ echo $txt . PHP_EOL; } } }