86 std::array<char, 128> buffer;
88 std::unique_ptr<FILE,
decltype(&_pclose)> pipe(_popen(cmd.c_str(),
"r"), _pclose);
90 throw std::runtime_error(
"popen() failed!");
91 while (fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr)
93 result += buffer.data();
98 static std::string
httpGet(
const std::wstring& host,
const std::wstring& path)
102 HINTERNET hSession = WinHttpOpen(L
"RunicVTT/1.0",
103 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
104 WINHTTP_NO_PROXY_NAME,
105 WINHTTP_NO_PROXY_BYPASS, 0);
109 HINTERNET hConnect = WinHttpConnect(hSession, host.c_str(),
110 INTERNET_DEFAULT_HTTPS_PORT, 0);
114 HINTERNET hRequest = WinHttpOpenRequest(hConnect, L
"GET", path.c_str(),
115 NULL, WINHTTP_NO_REFERER,
116 WINHTTP_DEFAULT_ACCEPT_TYPES,
117 WINHTTP_FLAG_SECURE);
121 BOOL bResults = WinHttpSendRequest(hRequest,
122 WINHTTP_NO_ADDITIONAL_HEADERS, 0,
123 WINHTTP_NO_REQUEST_DATA, 0,
127 bResults = WinHttpReceiveResponse(hRequest, NULL);
134 DWORD dwDownloaded = 0;
135 if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
141 std::string buffer(dwSize, 0);
142 if (!WinHttpReadData(hRequest, buffer.data(), dwSize, &dwDownloaded))
145 result.append(buffer.c_str(), dwDownloaded);
147 }
while (dwSize > 0);
149 WinHttpCloseHandle(hRequest);
151 WinHttpCloseHandle(hConnect);
153 WinHttpCloseHandle(hSession);
161 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
163 throw std::runtime_error(
"WSAStartup failed");
167 SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
168 if (sock == INVALID_SOCKET)
171 throw std::runtime_error(
"socket creation failed");
174 sockaddr_in remote{};
175 remote.sin_family = AF_INET;
176 remote.sin_port = htons(53);
177 inet_pton(AF_INET,
"8.8.8.8", &remote.sin_addr);
180 if (connect(sock,
reinterpret_cast<sockaddr*
>(&remote),
sizeof(remote)) != 0)
184 throw std::runtime_error(
"connect failed");
188 int len =
sizeof(local);
189 if (getsockname(sock,
reinterpret_cast<sockaddr*
>(&local), &len) != 0)
193 throw std::runtime_error(
"getsockname failed");
196 char ipStr[INET_ADDRSTRLEN];
197 inet_ntop(AF_INET, &local.sin_addr, ipStr,
sizeof(ipStr));
202 return std::string(ipStr);
435 std::string subdomain = std::regex_replace(subdomainBase, std::regex(
"\\."),
"");
436 for (
auto& c : subdomain)
437 c = (
char)std::tolower((
unsigned char)c);
440 std::lock_guard<std::mutex> lk(
urlMutex);
445 SECURITY_ATTRIBUTES sa{};
446 sa.nLength =
sizeof(sa);
447 sa.bInheritHandle = TRUE;
450 OutputDebugStringA(
"[LT] CreatePipe stdout failed\n");
453 SetHandleInformation(
ltStdoutRd, HANDLE_FLAG_INHERIT, 0);
458 OutputDebugStringA(
"[LT] CreatePipe stdin failed\n");
463 SetHandleInformation(
ltStdinWr, HANDLE_FLAG_INHERIT, 0);
469 std::ostringstream cmd;
470 cmd <<
"\"" << nodePath <<
"\" \"" << ctlPath <<
"\""
471 <<
" --port " << port
472 <<
" --subdomain " << subdomain;
475 PROCESS_INFORMATION pi{};
477 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
481 si.wShowWindow = SW_HIDE;
483 DWORD flags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP;
485 std::string cmdLine = cmd.str();
486 std::vector<char> mutableCmd(cmdLine.begin(), cmdLine.end());
487 mutableCmd.push_back(
'\0');
492 BOOL ok = CreateProcessA(
499 workingDir.empty() ?
nullptr : workingDir.c_str(),
508 DWORD err = GetLastError();
510 OutputDebugStringA(em.c_str());
518 running.store(
true, std::memory_order_relaxed);
523 std::string buf; buf.reserve(4096);
524 constexpr DWORD CHUNK = 1024;
527 auto trimCR = [](std::string& s) {
528 if (!s.empty() && s.back() ==
'\r') s.pop_back();
531 auto handleJsonLine = [](
const std::string& line) {
532 auto findField = [&](
const char* key)->std::string {
533 auto kpos = line.find(std::string(
"\"")+key+
"\"");
534 if (kpos == std::string::npos)
return {};
535 auto colon = line.find(
':', kpos);
536 if (colon == std::string::npos)
return {};
537 auto q1 = line.find(
'"', colon + 1);
538 if (q1 == std::string::npos)
return {};
539 auto q2 = line.find(
'"', q1 + 1);
540 if (q2 == std::string::npos)
return {};
541 return line.substr(q1 + 1, q2 - (q1 + 1));
544 const auto ev = findField(
"event");
545 const auto url = findField(
"url");
546 const auto msg = findField(
"message");
555 }
else if (ev ==
"require_ok") {
557 }
else if (ev ==
"require_err") {
559 }
else if (ev ==
"ready") {
567 }
else if (ev ==
"error") {
569 }
else if (ev ==
"closed") {
578 BOOL ok = ReadFile(rd, tmp, CHUNK, &got,
nullptr);
579 if (!ok || got == 0)
break;
581 buf.append(tmp, got);
585 size_t nl = buf.find(
'\n', pos);
586 if (nl == std::string::npos)
break;
587 std::string line = buf.substr(pos, nl - pos);
592 handleJsonLine(line);
595 if (pos > 0) buf.erase(0, pos);
649 std::unique_lock<std::mutex> lk(
urlMutex);
650 bool have =
urlCv.wait_for(lk, std::chrono::seconds(15), []