Implement restart support for all platforms
This commit is contained in:
@@ -544,7 +544,6 @@ namespace confighttp {
|
||||
outputTree.put("status", "true");
|
||||
outputTree.put("platform", SUNSHINE_PLATFORM);
|
||||
outputTree.put("version", PROJECT_VER);
|
||||
outputTree.put("restart_supported", platf::restart_supported());
|
||||
|
||||
auto vars = config::parse_config(read_file(config::sunshine.config_file.c_str()));
|
||||
|
||||
@@ -595,30 +594,8 @@ namespace confighttp {
|
||||
|
||||
print_req(request);
|
||||
|
||||
std::stringstream ss;
|
||||
std::stringstream configStream;
|
||||
ss << request->content.rdbuf();
|
||||
pt::ptree outputTree;
|
||||
auto g = util::fail_guard([&]() {
|
||||
std::ostringstream data;
|
||||
|
||||
pt::write_json(data, outputTree);
|
||||
response->write(data.str());
|
||||
});
|
||||
|
||||
if (!platf::restart_supported()) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Restart is not currently supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!platf::restart()) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Restart failed");
|
||||
return;
|
||||
}
|
||||
|
||||
outputTree.put("status", true);
|
||||
// We may not return from this call
|
||||
platf::restart();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
11
src/main.cpp
11
src/main.cpp
@@ -108,6 +108,7 @@ namespace version {
|
||||
} // namespace version
|
||||
|
||||
namespace lifetime {
|
||||
static char **argv;
|
||||
static std::atomic_int desired_exit_code;
|
||||
|
||||
/**
|
||||
@@ -130,6 +131,14 @@ namespace lifetime {
|
||||
std::this_thread::sleep_for(1s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the argv array passed to main()
|
||||
*/
|
||||
char **
|
||||
get_argv() {
|
||||
return argv;
|
||||
}
|
||||
} // namespace lifetime
|
||||
|
||||
/**
|
||||
@@ -207,6 +216,8 @@ SessionMonitorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
lifetime::argv = argv;
|
||||
|
||||
task_pool_util::TaskPool::task_id_t force_shutdown = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace mail {
|
||||
namespace lifetime {
|
||||
void
|
||||
exit_sunshine(int exit_code, bool async);
|
||||
char **
|
||||
get_argv();
|
||||
} // namespace lifetime
|
||||
|
||||
#endif // SUNSHINE_MAIN_H
|
||||
|
||||
@@ -399,9 +399,7 @@ namespace platf {
|
||||
void
|
||||
streaming_will_stop();
|
||||
|
||||
bool
|
||||
restart_supported();
|
||||
bool
|
||||
void
|
||||
restart();
|
||||
|
||||
struct batched_send_info_t {
|
||||
|
||||
@@ -193,16 +193,34 @@ namespace platf {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
bool
|
||||
restart_supported() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
void
|
||||
restart_on_exit() {
|
||||
char executable[PATH_MAX];
|
||||
ssize_t len = readlink("/proc/self/exe", executable, PATH_MAX - 1);
|
||||
if (len == -1) {
|
||||
BOOST_LOG(fatal) << "readlink() failed: "sv << errno;
|
||||
return;
|
||||
}
|
||||
executable[len] = '\0';
|
||||
|
||||
// ASIO doesn't use O_CLOEXEC, so we have to close all fds ourselves
|
||||
int openmax = (int) sysconf(_SC_OPEN_MAX);
|
||||
for (int fd = STDERR_FILENO + 1; fd < openmax; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// Re-exec ourselves with the same arguments
|
||||
if (execv(executable, lifetime::get_argv()) < 0) {
|
||||
BOOST_LOG(fatal) << "execv() failed: "sv << errno;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
restart() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
// Gracefully clean up and restart ourselves instead of exiting
|
||||
atexit(restart_on_exit);
|
||||
lifetime::exit_sunshine(0, true);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
@@ -192,16 +193,33 @@ namespace platf {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
bool
|
||||
restart_supported() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
void
|
||||
restart_on_exit() {
|
||||
char executable[2048];
|
||||
uint32_t size = sizeof(executable);
|
||||
if (_NSGetExecutablePath(executable, &size) < 0) {
|
||||
BOOST_LOG(fatal) << "NSGetExecutablePath() failed: "sv << errno;
|
||||
return;
|
||||
}
|
||||
|
||||
// ASIO doesn't use O_CLOEXEC, so we have to close all fds ourselves
|
||||
int openmax = (int) sysconf(_SC_OPEN_MAX);
|
||||
for (int fd = STDERR_FILENO + 1; fd < openmax; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// Re-exec ourselves with the same arguments
|
||||
if (execv(executable, lifetime::get_argv()) < 0) {
|
||||
BOOST_LOG(fatal) << "execv() failed: "sv << errno;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
restart() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
// Gracefully clean up and restart ourselves instead of exiting
|
||||
atexit(restart_on_exit);
|
||||
lifetime::exit_sunshine(0, true);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -809,19 +809,49 @@ namespace platf {
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
restart_supported() {
|
||||
// Restart is supported if we're running from the service
|
||||
return (GetConsoleWindow() == NULL);
|
||||
void
|
||||
restart_on_exit() {
|
||||
STARTUPINFOEXW startup_info {};
|
||||
startup_info.StartupInfo.cb = sizeof(startup_info);
|
||||
|
||||
WCHAR executable[MAX_PATH];
|
||||
if (GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable)) == 0) {
|
||||
auto winerr = GetLastError();
|
||||
BOOST_LOG(fatal) << "Failed to get Sunshine path: "sv << winerr;
|
||||
return;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (!CreateProcessW(executable,
|
||||
GetCommandLineW(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
false,
|
||||
CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT,
|
||||
nullptr,
|
||||
nullptr,
|
||||
(LPSTARTUPINFOW) &startup_info,
|
||||
&process_info)) {
|
||||
auto winerr = GetLastError();
|
||||
BOOST_LOG(fatal) << "Unable to restart Sunshine: "sv << winerr;
|
||||
return;
|
||||
}
|
||||
|
||||
CloseHandle(process_info.hProcess);
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
restart() {
|
||||
// Gracefully exit. The service will restart us in a few seconds.
|
||||
// We use an async exit call here because we can't block the
|
||||
// HTTP thread or we'll hang shutdown.
|
||||
// If we're running standalone, we have to respawn ourselves via CreateProcess().
|
||||
// If we're running from the service, we should just exit and let it respawn us.
|
||||
if (GetConsoleWindow() != NULL) {
|
||||
// Avoid racing with the new process by waiting until we're exiting to start it.
|
||||
atexit(restart_on_exit);
|
||||
}
|
||||
|
||||
// We use an async exit call here because we can't block the HTTP thread or we'll hang shutdown.
|
||||
lifetime::exit_sunshine(0, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
SOCKADDR_IN
|
||||
|
||||
@@ -123,6 +123,17 @@ namespace system_tray {
|
||||
open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback for restarting Sunshine from the system tray.
|
||||
* @param item The tray menu item.
|
||||
*/
|
||||
void
|
||||
tray_restart_cb(struct tray_menu *item) {
|
||||
BOOST_LOG(info) << "Restarting from system tray"sv;
|
||||
|
||||
platf::restart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback for exiting Sunshine from the system tray.
|
||||
* @param item The tray menu item.
|
||||
@@ -162,6 +173,7 @@ namespace system_tray {
|
||||
{ .text = "PayPal", .cb = tray_donate_paypal_cb },
|
||||
{ .text = nullptr } } },
|
||||
{ .text = "-" },
|
||||
{ .text = "Restart", .cb = tray_restart_cb },
|
||||
{ .text = "Quit", .cb = tray_quit_cb },
|
||||
{ .text = nullptr } },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user