Skip to content

Upload brief crash info #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: streamlabs
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crash-handler-process/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ ENDIF()
SET(PROJECT_SOURCE
"${PROJECT_SOURCE_DIR}/process.hpp"
"${PROJECT_SOURCE_DIR}/process-manager.cpp" "${PROJECT_SOURCE_DIR}/process-manager.hpp"
"${PROJECT_SOURCE_DIR}/brief-crash-info-uploader.cpp" "${PROJECT_SOURCE_DIR}/brief-crash-info-uploader.hpp"
"${PROJECT_SOURCE_DIR}/message.cpp" "${PROJECT_SOURCE_DIR}/message.hpp"
"${PROJECT_SOURCE_DIR}/http-helper.hpp"
"${PROJECT_SOURCE_DIR}/socket.hpp"
"${PROJECT_SOURCE_DIR}/logger.cpp" "${PROJECT_SOURCE_DIR}/logger.hpp"
"${PROJECT_SOURCE_DIR}/main.cpp"
Expand All @@ -50,7 +52,9 @@ IF(WIN32)
"${PROJECT_SOURCE_DIR}/platforms/util-win.cpp"
"${PROJECT_SOURCE_DIR}/platforms/socket-win.cpp" "${PROJECT_SOURCE_DIR}/platforms/socket-win.hpp"
"${PROJECT_SOURCE_DIR}/platforms/process-win.cpp" "${PROJECT_SOURCE_DIR}/platforms/process-win.hpp"
"${PROJECT_SOURCE_DIR}/platforms/upload-window-win.cpp" "${PROJECT_SOURCE_DIR}/platforms/upload-window-win.hpp"
"${PROJECT_SOURCE_DIR}/platforms/upload-window-win.cpp" "${PROJECT_SOURCE_DIR}/platforms/upload-window-win.hpp"
"${PROJECT_SOURCE_DIR}/platforms/httprequest_i.c" "${PROJECT_SOURCE_DIR}/platforms/httprequest.h"
"${PROJECT_SOURCE_DIR}/platforms/http-helper-win.cpp" "${PROJECT_SOURCE_DIR}/platforms/http-helper-win.hpp"
"${PROJECT_SOURCE_DIR}/minizip/zip.c" "${PROJECT_SOURCE_DIR}/minizip/zip.h"
"${PROJECT_SOURCE_DIR}/minizip/ioapi.c" "${PROJECT_SOURCE_DIR}/minizip/ioapi.h"
"${PROJECT_SOURCE_DIR}/minizip/iowin32.c" "${PROJECT_SOURCE_DIR}/minizip/iowin32.h"
Expand All @@ -60,7 +64,7 @@ ELSE(APPLE)
"${PROJECT_SOURCE_DIR}/platforms/util-osx.mm"
"${PROJECT_SOURCE_DIR}/platforms/socket-osx.cpp" "${PROJECT_SOURCE_DIR}/platforms/socket-osx.hpp"
"${PROJECT_SOURCE_DIR}/platforms/process-osx.mm" "${PROJECT_SOURCE_DIR}/platforms/process-osx.hpp"

"${PROJECT_SOURCE_DIR}/platforms/http-helper-osx.mm" "${PROJECT_SOURCE_DIR}/platforms/http-helper-osx.hpp"
)
find_library(COCOA Cocoa)
# Prepare gettext
Expand Down
117 changes: 117 additions & 0 deletions crash-handler-process/brief-crash-info-uploader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/******************************************************************************
Copyright (C) 2016-2020 by Streamlabs (General Workings Inc)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <codecvt>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <thread>

#include "logger.hpp"
#include "util.hpp"

#include "http-helper.hpp"
#include "brief-crash-info-uploader.hpp"

#if defined(_WIN32)
std::string_view g_pathSeparator("\\");
#else
std::string_view g_pathSeparator("/");
#endif

std::string_view g_briefCrashDataFilename("brief-crash-info.json");

BriefCrashInfoUploader::BriefCrashInfoUploader(const std::string &appDataPath) : m_filename(appDataPath)
{
if (*m_filename.rbegin() != '/' && *m_filename.rbegin() != '\\') {
m_filename += g_pathSeparator;
}
m_filename += g_briefCrashDataFilename;
}

BriefCrashInfoUploader::~BriefCrashInfoUploader() {}

void BriefCrashInfoUploader::Run(std::int64_t maxFileWaitTimeMs)
{
std::string json = ProcessBriefCrashInfoJson(maxFileWaitTimeMs);
if (json.size()) {
UploadJson(json);
}
}

std::string BriefCrashInfoUploader::ProcessBriefCrashInfoJson(std::int64_t maxFileWaitTimeMs)
{
log_info << "Waiting for brief crash info file: " << m_filename << std::endl;
std::string json;
std::filesystem::path briefCrashInfoPath = std::filesystem::u8path(m_filename);
std::int64_t realFileWaitTimeMs = 0;
while (realFileWaitTimeMs < maxFileWaitTimeMs) {
if (std::filesystem::exists(briefCrashInfoPath) && std::filesystem::is_regular_file(briefCrashInfoPath)) {
json = LoadBriefCrashInfoJson();
std::filesystem::remove(briefCrashInfoPath);
log_info << "The brief crash info file has been loaded." << std::endl;
break;
}
// Obviously the sleep can take more than 100ms but not much so we ignore the difference
std::this_thread::sleep_for(std::chrono::milliseconds(100));
realFileWaitTimeMs += 100;
}
log_info << "Waited for the brief crash info file (ms): " << realFileWaitTimeMs << std::endl;
return json;
}

std::string BriefCrashInfoUploader::LoadBriefCrashInfoJson()
{
#if defined(_WIN32)
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::ifstream file(converter.from_bytes(m_filename));
#else
std::ifstream file(m_filename);
#endif
file.seekg(0, std::ios::end);
size_t fileSize = file.tellg();

std::string buffer(fileSize, ' ');
file.seekg(0);
file.read(&buffer.front(), fileSize);
file.close();

return buffer;
}

void BriefCrashInfoUploader::UploadJson(const std::string &json)
{
log_info << "Uploading the brief crash info..." << std::endl;

HttpHelper::Headers requestHeaders = {{"Content-Type", "application/json; Charset=UTF-8"}};
HttpHelper::Headers responseHeaders;
std::string response;

std::uint32_t statusCode = 0;

auto httpHelper = HttpHelper::Create();
HttpHelper::Result result = httpHelper->PostRequest("https://httpbin.org/post", requestHeaders, json, &statusCode, &responseHeaders, &response);

log_info << "Brief crash info upload result (0 means SUCCESS): " << static_cast<int>(result) << std::endl;
log_info << "Brief crash info upload HTTP status code: " << statusCode << std::endl;
log_info << "Brief crash info upload response: " << response << std::endl;

for (const auto &[header, value] : responseHeaders) {
log_info << "Brief crash info upload response header: " << header << " = " << value << std::endl;
}
}
38 changes: 38 additions & 0 deletions crash-handler-process/brief-crash-info-uploader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/******************************************************************************
Copyright (C) 2016-2020 by Streamlabs (General Workings Inc)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#pragma once

#include <cstdint>
#include <string>
#include <string_view>

class BriefCrashInfoUploader final {
public:
BriefCrashInfoUploader(const std::string &appDataPath);
~BriefCrashInfoUploader();

void Run(std::int64_t maxFileWaitTimeMs = 10000);

private:
std::string ProcessBriefCrashInfoJson(std::int64_t maxFileWaitTimeMs);
std::string LoadBriefCrashInfoJson();
void UploadJson(const std::string &json);

std::string m_filename;
};
Binary file modified crash-handler-process/dependencies/crash-handler-process.exe.txt
Binary file not shown.
54 changes: 54 additions & 0 deletions crash-handler-process/http-helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/******************************************************************************
Copyright (C) 2016-2020 by Streamlabs (General Workings Inc)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <cstdint>
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <string_view>
#include <map>

class HttpHelper {
public:
enum class Result {
Success = 0,
InvalidParam,
CouldNotInit,
ConnectFailed,
RequestFailed,
ResponseFailed,
};

enum class Method { Undefined = 0, Get, Post };

using Headers = std::map<std::string, std::string>;

static std::unique_ptr<HttpHelper> Create();

virtual ~HttpHelper() {}

virtual Result Request(Method method, std::string_view url, const Headers &requestHeaders, std::string_view body, std::uint32_t *statusCode,
Headers *responseHeaders, std::string *response) = 0;

virtual Result GetRequest(std::string_view url, const Headers &requestHeaders, std::uint32_t *statusCode, Headers *responseHeaders,
std::string *response) = 0;

virtual Result PostRequest(std::string_view url, const Headers &requestHeaders, std::string_view body, std::uint32_t *statusCode,
Headers *responseHeaders, std::string *response) = 0;
};
23 changes: 21 additions & 2 deletions crash-handler-process/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include "process-manager.hpp"
#include "util.hpp"
#include <codecvt>
#include <filesystem>

#include "brief-crash-info-uploader.hpp"

#include "http-helper.hpp"

#if defined(WIN32)
const std::string log_file_name = "\\crash-handler.log";
Expand All @@ -29,6 +34,9 @@ const std::wstring log_file_name = L"/crash-handler.log";

int main(int argc, char **argv)
{
#if defined(_WIN32)
CoInitialize(NULL);
#endif
Util::setupLocale();

std::string pid_path(Util::get_temp_directory());
Expand All @@ -40,6 +48,7 @@ int main(int argc, char **argv)
std::wstring version;
std::wstring isDevEnv;
std::wstring ipc_path;
std::string appData_path;

std::cout << "Launched with number of arguments = " << argc << std::endl;
#if defined(WIN32)
Expand All @@ -65,6 +74,7 @@ int main(int argc, char **argv)
logging_start(w_log_path);
log_info << "=== Started CrashHandler ===" << std::endl;
Util::setCachePath(w_cache_path);
appData_path = cache_path;
}
if (nArgs >= 6) {
ipc_path = szArglist[5];
Expand All @@ -87,22 +97,31 @@ int main(int argc, char **argv)
logging_start(log_path);
log_info << "=== Started CrashHandler ===" << std::endl;
Util::setCachePath(cache_path);
appData_path = argv[4];
}
if (argc >= 6) {
ipc_path = converter.from_bytes(argv[5]);
log_info << "ipc path option recieve : " << std::string(ipc_path.begin(), ipc_path.end()) << std::endl;
Socket::set_ipc_path(ipc_path);
}

#endif

ProcessManager *pm = new ProcessManager();
pm->runWatcher();

if (pm->m_applicationCrashed)
if (pm->m_applicationCrashed) {
pm->handleCrash(path);
BriefCrashInfoUploader(appData_path).Run();
}

delete pm;

log_info << "=== Terminating CrashHandler ===" << std::endl;
logging_end();

#if defined(_WIN32)
CoUninitialize();
#endif

return 0;
}
38 changes: 38 additions & 0 deletions crash-handler-process/platforms/http-helper-osx.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/******************************************************************************
Copyright (C) 2016-2020 by Streamlabs (General Workings Inc)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#pragma once

#include "../http-helper.hpp"

class HttpHelper_OSX : public HttpHelper {
public:
HttpHelper_OSX();
~HttpHelper_OSX() override;

Result Request(Method method, std::string_view url, const Headers &requestHeaders, std::string_view body, std::uint32_t *statusCode,
Headers *responseHeaders, std::string *response) override;

Result GetRequest(std::string_view url, const Headers &requestHeaders, std::uint32_t *statusCode, Headers *responseHeaders,
std::string *response) override;

Result PostRequest(std::string_view url, const Headers &requestHeaders, std::string_view body, std::uint32_t *statusCode, Headers *responseHeaders,
std::string *response) override;

private:
};
Loading