代码拉取完成,页面将自动刷新
同步操作将从 leo/supervisor 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#if !defined(_WIN32)
#include "watcher.h"
#include "logger.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <csignal>
#include <cstring>
#include <cstdio>
#include <memory>
#include <iostream>
#include <sstream>
static int nCpuIdx = -1;
static int nVszIdx = -1;
static int nResIdx = -1;
static void GetKeyIdx() {
static bool bCalc = false;
if (bCalc) return;
bCalc = true;
FILE * pPipe = popen("ps -u -p 1", "r");
if (!pPipe) return;
std::string sResult;
sResult.reserve(4096);
char pBuf[2048] = {0};
while (!feof(pPipe)) {
size_t nSize = fread(pBuf, 1, 2048, pPipe);
if (nSize > 0) sResult.append(pBuf, nSize);
}
std::istringstream issH(sResult);
int nIdx = 0;
while (issH.good()) {
std::string sKey;
issH >> sKey;
if (sKey == "%CPU") nCpuIdx = nIdx;
else if (sKey == "VSZ") nVszIdx = nIdx;
else if (sKey == "RSS") nResIdx = nIdx;
nIdx++;
}
pclose(pPipe);
}
Watcher & Watcher::Instance() {
static std::unique_ptr<Watcher> iIns;
if (!iIns) iIns.reset(new Watcher);
GetKeyIdx();
return *iIns;
}
void Watcher::Breath() {
static time_t nLastBreath = 0;
static char pBuf[2048] = {0};
time_t nTick = time(NULL);
if (nTick == nLastBreath) return;
nLastBreath = nTick;
Json::Value iMsg;
iMsg["action"] = "update";
iMsg["watchers"] = Json::Value(Json::arrayValue);
for (auto & kv : _mWatcher) {
if (kv.second.emStatus == EStatus::Running) {
int nStatus = 0;
int nChild = waitpid(kv.second.nPid, &nStatus, WNOHANG);
if (nChild > 0) {
Tail(kv.first, kv.second);
CatchExit(kv.first, kv.second, WEXITSTATUS(nStatus) == 0 ? EStatus::Stopped : EStatus::Fatal, true);
continue;
} else if (nChild == 0) {
Tail(kv.first, kv.second);
std::string sCmd = "ps -u -p " + std::to_string(kv.second.nPid);
std::string sResult;
sResult.reserve(1024 * 8);
FILE * pPipe = popen(sCmd.data(), "r");
if (!pPipe) continue;
while (!feof(pPipe)) {
size_t nSize = fread(pBuf, 1, 2048, pPipe);
if (nSize > 0) sResult.append(pBuf, nSize);
}
pclose(pPipe);
int nVsz = 0, nRes = 0, nIdx = 0;
std::string sCpu = "";
std::istringstream iss(sResult);
while (iss.get() != '\n') continue;
while (iss.good()) {
std::string sData;
iss >> sData;
if (nIdx == nCpuIdx) {
sCpu = sData;
} else if (nIdx == nVszIdx) {
nVsz = atoi(sData.data());
} else if (nIdx == nResIdx) {
nRes = atoi(sData.data());
}
nIdx++;
}
Json::Value iStatus;
iStatus["name"] = kv.first;
iStatus["cpu"] = sCpu;
iStatus["vsz"] = nVsz;
iStatus["res"] = nRes;
iMsg["watchers"].append(iStatus);
} else {
CatchExit(kv.first, kv.second, errno == EINTR ? EStatus::Stopped : EStatus::Fatal, true);
}
}
}
if (iMsg["watchers"].size() > 0) Notify("/ws", iMsg);
}
void Watcher::Start(const std::string &sName, const std::string &sPath, const std::string &sCmd, int nRetry) {
auto it = _mWatcher.find(sName);
Info * pInfo = nullptr;
if (it != _mWatcher.end() && it->second.emStatus == EStatus::Running) return;
if (it == _mWatcher.end()) {
Info iInfo;
iInfo.nRetry = nRetry;
iInfo.sCmd = sCmd;
iInfo.sPath = sPath;
_mWatcher[sName] = iInfo;
pInfo = &_mWatcher[sName];
} else if (it->second.emStatus == EStatus::Running) {
return;
} else {
pInfo = &it->second;
}
pInfo->nStart = time(NULL);
std::vector<std::string> vParams;
std::string sDeli = " \t";
std::string::size_type nStart = 0, nEnd = 0;
while (nEnd < sCmd.length()) {
char nTemp = sCmd[nEnd];
if (sDeli.find(nTemp) != std::string::npos) {
if (nStart != nEnd) vParams.push_back(sCmd.substr(nStart, nEnd - nStart));
++nEnd;
nStart = nEnd;
} else {
++nEnd;
}
}
if (nStart != nEnd) vParams.push_back(sCmd.substr(nStart));
if (vParams.size() <= 0) return;
int pFd[2] = {0, 0};
if (pipe(pFd) == -1) {
LOG_ERR("Failed to create pipe for start watcher [%s]", sName.data());
return;
}
pid_t nChildPid = fork();
if (nChildPid == -1) {
LOG_ERR("Start %s ... [Failed] Path : %s, Cmd : %s", sName.data(), sPath.data(), sCmd.data());
pInfo->emStatus = EStatus::Fatal;
pInfo->nPid = -1;
} else if (nChildPid == 0) {
close(pFd[0]);
dup2(pFd[1], STDERR_FILENO);
dup2(pFd[1], STDOUT_FILENO);
setpgid(nChildPid, nChildPid);
if (-1 == chdir(sPath.data())) {
std::cerr << "Failed to change directory : " << sPath << std::endl;
} else {
char * pParam[20] = {0};
memset(pParam, 0, sizeof(pParam));
for (int i = 0; i < vParams.size() && i < 19; ++i)
pParam[i] = (char *)vParams[i].data();
if (-1 == execvp(vParams[0].data(), pParam))
std::cerr << "No such file named : " << vParams[0] << std::endl;
}
exit(-1);
} else {
close(pFd[1]);
int nFlags = fcntl(pFd[0], F_GETFL, 0);
fcntl(pFd[0], F_SETFL, O_NONBLOCK | nFlags);
pInfo->nFd = pFd[0];
pInfo->nPid = nChildPid;
pInfo->emStatus = EStatus::Running;
LOG_INFO("Start %s ... [OK]. FD : %d, PID : %d", sName.c_str(), pInfo->nFd, pInfo->nPid);
}
Json::Value iMsg;
iMsg["action"] = "status_change";
iMsg["watcher"] = sName;
iMsg["status"] = pInfo->emStatus;
iMsg["pid"] = pInfo->nPid;
iMsg["start_time"] = pInfo->GetStartTime();
AppendTail(sName, *pInfo, "\n\n----------- Start -----------\n");
Notify("/ws", iMsg);
}
void Watcher::Stop(const std::string &sName) {
auto it = _mWatcher.find(sName);
if (it == _mWatcher.end() || it->second.emStatus != EStatus::Running) return;
int nStatus = kill(it->second.nPid, SIGINT);
if (nStatus == -1) {
LOG_ERR("Stop %s ... [Failed]", sName.data());
} else {
nStatus = 0;
Tail(sName, it->second);
while (waitpid(it->second.nPid, &nStatus, 0) == -1) {
if (errno != EINTR) break;
}
CatchExit(sName, it->second, WEXITSTATUS(nStatus) == 0 ? EStatus::Stopped : EStatus::Fatal);
LOG_INFO("Stop %s ... [OK]", sName.data());
}
}
void Watcher::StopAll() {
int nStatus = 0;
for (auto & kv : _mWatcher) {
if (kv.second.emStatus == EStatus::Running) {
kill(kv.second.nPid, SIGINT);
while (waitpid(kv.second.nPid, &nStatus, 0) == -1) {
if (errno != EINTR) break;
}
}
}
}
void Watcher::Remove(const std::string &sName) {
auto it = _mWatcher.find(sName);
if (it == _mWatcher.end()) return;
if (it->second.emStatus == EStatus::Running) Stop(sName);
_mWatcher.erase(it);
}
Watcher::Info * Watcher::Get(const std::string &sName) {
auto it = _mWatcher.find(sName);
if (it == _mWatcher.end()) return nullptr;
return &it->second;
}
void Watcher::Notify(const std::string & sScope, const Json::Value & rMsg) {
if (_fNotifier) _fNotifier(sScope, rMsg);
}
void Watcher::Tail(const std::string & sName, Info & rInfo) {
static char pLine[8192] = {0}, pData[8192] = {0};
memset(pLine, 0, 8192);
memset(pData, 0, 8192);
int nSize = read(rInfo.nFd, pLine, 8192);
if (nSize > 0) {
int nRead = 0;
for (int i = 0; i < nSize; ++i) {
if (pLine[i] == 0x1B && pLine[i + 1] == '[') {
while (i < nSize && pLine[i] != 'm') i++;
} else {
pData[nRead] = pLine[i];
++nRead;
}
}
memcpy(rInfo.pTail + rInfo.nTail, pData, nRead);
if (rInfo.nTail + nRead > 8192) {
int nIdx = rInfo.nTail + nRead - 8192;
int i = 0;
for (; nIdx < rInfo.nTail + nRead; ++nIdx) {
if (rInfo.pTail[nIdx] == '\n') {
nIdx++;
break;
}
}
for (; i < rInfo.nTail + nRead - nIdx; ++i) {
rInfo.pTail[i] = rInfo.pTail[i + nIdx];
}
rInfo.pTail[i] = '\0';
rInfo.nTail = i;
} else {
rInfo.nTail += nRead;
}
Json::Value iMsg;
iMsg["action"] = "tail_append";
iMsg["watcher"] = sName;
iMsg["data"] = pData;
Notify("/tail/" + sName, iMsg);
Notify("/tail_all", iMsg);
}
}
void Watcher::AppendTail(const std::string & sName, Info & rInfo, const std::string & sTail) {
int nSize = sTail.size();
memcpy(rInfo.pTail + rInfo.nTail, sTail.data(), nSize);
if (rInfo.nTail + nSize > 8192) {
int nIdx = rInfo.nTail + nSize - 8192;
int i = 0;
for (; nIdx < rInfo.nTail + nSize; ++nIdx) {
if (rInfo.pTail[nIdx] == '\n') {
nIdx++;
break;
}
}
for (; i < rInfo.nTail + nSize - nIdx; ++i) {
rInfo.pTail[i] = rInfo.pTail[i + nIdx];
}
rInfo.pTail[i] = '\0';
rInfo.nTail = i;
} else {
rInfo.nTail += nSize;
}
Json::Value iMsg;
iMsg["action"] = "tail_append";
iMsg["data"] = sTail;
Notify("/tail/" + sName, iMsg);
}
void Watcher::CatchExit(const std::string & sName, Info & rInfo, EStatus emStatus, bool bRetry /* = false */) {
close(rInfo.nFd);
rInfo.emStatus = emStatus;
rInfo.nFd = -1;
rInfo.nPid = -1;
rInfo.nStart = 0;
Json::Value iMsg;
iMsg["action"] = "status_change";
iMsg["watcher"] = sName;
iMsg["status"] = rInfo.emStatus;
iMsg["pid"] = rInfo.nPid;
iMsg["start_time"] = rInfo.GetStartTime();
if (bRetry && rInfo.nRetry > 0) {
rInfo.emStatus = EStatus::Retry;
iMsg["status"] = EStatus::Retry;
Notify("/ws", iMsg);
AppendTail(sName, rInfo, "\n----------- Auto-retry -----------\n");
Start(sName, rInfo.sPath, rInfo.sCmd, rInfo.nRetry - 1);
} else {
Notify("/ws", iMsg);
AppendTail(sName, rInfo, "\n----------- Stopped -----------\n");
}
}
#endif
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。