diff --git a/assets/web/header.html b/assets/web/header.html
index 6e153e14..0bbcc34c 100644
--- a/assets/web/header.html
+++ b/assets/web/header.html
@@ -54,6 +54,9 @@
Change Password
+
+ Troubleshooting
+
diff --git a/assets/web/troubleshooting.html b/assets/web/troubleshooting.html
new file mode 100644
index 00000000..e551c8de
--- /dev/null
+++ b/assets/web/troubleshooting.html
@@ -0,0 +1,74 @@
+
+
Troubleshooting
+
+
+
+
Force Close
+
+
+ If Moonlight complains about an app currently running, force closing the
+ app should fix the issue
+
+
+
+
+
+
+
+
+
+
Unpair All Clients
+
+
Remove all your paired devices
+
+
+
+
+
+
+
+
diff --git a/sunshine/confighttp.cpp b/sunshine/confighttp.cpp
index 3e624809..64d92722 100644
--- a/sunshine/confighttp.cpp
+++ b/sunshine/confighttp.cpp
@@ -211,6 +211,16 @@ void getWelcomePage(resp_https_t response, req_https_t request) {
response->write(header + content);
}
+void getTroubleshootingPage(resp_https_t response, req_https_t request) {
+ if(!authenticate(response, request)) return;
+
+ print_req(request);
+
+ std::string header = read_file(WEB_DIR "header.html");
+ std::string content = read_file(WEB_DIR "troubleshooting.html");
+ response->write(header + content);
+}
+
void getApps(resp_https_t response, req_https_t request) {
if(!authenticate(response, request)) return;
@@ -481,6 +491,56 @@ void savePin(resp_https_t response, req_https_t request) {
}
}
+void unpairAll(resp_https_t response, req_https_t request){
+ if(!authenticate(response, request)) return;
+
+ print_req(request);
+
+ pt::ptree outputTree;
+
+ auto g = util::fail_guard([&]() {
+ std::ostringstream data;
+ pt::write_json(data, outputTree);
+ response->write(data.str());
+ });
+
+ try {
+ nvhttp::erase_all_clients();
+ outputTree.put("status", true);
+ }
+ catch(std::exception &e) {
+ BOOST_LOG(warning) << "unpairAll: "sv << e.what();
+ outputTree.put("status", false);
+ outputTree.put("error", e.what());
+ return;
+ }
+}
+
+void closeApp(resp_https_t response, req_https_t request){
+ if(!authenticate(response, request)) return;
+
+ print_req(request);
+
+ pt::ptree outputTree;
+
+ auto g = util::fail_guard([&]() {
+ std::ostringstream data;
+ pt::write_json(data, outputTree);
+ response->write(data.str());
+ });
+
+ try {
+ proc::proc.terminate();
+ outputTree.put("status", true);
+ }
+ catch(std::exception &e) {
+ BOOST_LOG(warning) << "CloseApp: "sv << e.what();
+ outputTree.put("status", false);
+ outputTree.put("error", e.what());
+ return;
+ }
+}
+
void start() {
auto shutdown_event = mail::man->event(mail::shutdown);
@@ -498,6 +558,7 @@ void start() {
server.resource["^/config$"]["GET"] = getConfigPage;
server.resource["^/password$"]["GET"] = getPasswordPage;
server.resource["^/welcome$"]["GET"] = getWelcomePage;
+ server.resource["^/troubleshooting$"]["GET"] = getTroubleshootingPage;
server.resource["^/api/pin"]["POST"] = savePin;
server.resource["^/api/apps$"]["GET"] = getApps;
server.resource["^/api/apps$"]["POST"] = saveApp;
@@ -505,6 +566,8 @@ void start() {
server.resource["^/api/config$"]["POST"] = saveConfig;
server.resource["^/api/password$"]["POST"] = savePassword;
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
+ server.resource["^/api/clients/unpair$"]["POST"] = unpairAll;
+ server.resource["^/api/apps/close"]["POST"] = closeApp;
server.config.reuse_address = true;
server.config.address = "0.0.0.0"s;
server.config.port = port_https;
diff --git a/sunshine/nvhttp.cpp b/sunshine/nvhttp.cpp
index 0d854fdb..f167778a 100644
--- a/sunshine/nvhttp.cpp
+++ b/sunshine/nvhttp.cpp
@@ -927,4 +927,9 @@ void start() {
ssl.join();
tcp.join();
}
+
+void erase_all_clients(){
+ map_id_client.clear();
+ save_state();
+}
} // namespace nvhttp
diff --git a/sunshine/nvhttp.h b/sunshine/nvhttp.h
index f6d1afeb..af077a56 100644
--- a/sunshine/nvhttp.h
+++ b/sunshine/nvhttp.h
@@ -14,6 +14,7 @@ constexpr auto PORT_HTTPS = -5;
void start();
bool pin(std::string pin);
+void erase_all_clients();
} // namespace nvhttp
#endif //SUNSHINE_NVHTTP_H