diff --git a/docs/Doxyfile b/docs/Doxyfile index b667429d1c3..5695a2d6240 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -52,6 +52,7 @@ INPUT = ../README.md \ app_examples.md \ guides.md \ performance_tuning.md \ + api.md \ troubleshooting.md \ building.md \ contributing.md \ diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000000..2c6e640989d --- /dev/null +++ b/docs/api.md @@ -0,0 +1,64 @@ +# API + +Sunshine has a RESTful API which can be used to interact with the service. + +Unless otherwise specified, authentication is required for all API calls. You can authenticate using +basic authentication with the admin username and password. + +## GET /api/apps +@copydoc confighttp::getApps() + +## GET /api/logs +@copydoc confighttp::getLogs() + +## POST /api/apps +@copydoc confighttp::saveApp() + +## DELETE /api/apps{index} +@copydoc confighttp::deleteApp() + +## POST /api/covers/upload +@copydoc confighttp::uploadCover() + +## GET /api/config +@copydoc confighttp::getConfig() + +## GET /api/configLocale +@copydoc confighttp::getLocale() + +## POST /api/config +@copydoc confighttp::saveConfig() + +## POST /api/restart +@copydoc confighttp::restart() + +## POST /api/password +@copydoc confighttp::savePassword() + +## POST /api/pin +@copydoc confighttp::savePin() + +## POST /api/clients/unpair-all +@copydoc confighttp::unpairAll() + +## POST /api/clients/unpair +@copydoc confighttp::unpair() + +## GET /api/clients/list +@copydoc confighttp::listClients() + +## GET /api/apps/close +@copydoc confighttp::closeApp() + +
+ +| Previous | Next | +|:--------------------------------------------|--------------------------------------:| +| [Performance Tuning](performance_tuning.md) | [Troubleshooting](troubleshooting.md) | + +
+ +
+ + [TOC] +
diff --git a/docs/performance_tuning.md b/docs/performance_tuning.md index 796121425e7..b4418f6d7ef 100644 --- a/docs/performance_tuning.md +++ b/docs/performance_tuning.md @@ -13,9 +13,9 @@ Enabling *Fast Sync* in Nvidia settings may help reduce latency.
-| Previous | Next | -|:--------------------|--------------------------------------:| -| [Guides](guides.md) | [Troubleshooting](troubleshooting.md) | +| Previous | Next | +|:--------------------|--------------:| +| [Guides](guides.md) | [API](api.md) |
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 133a063bbf6..c5fcf13b066 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -200,9 +200,9 @@ permissions on the disk.
-| Previous | Next | -|:--------------------------------------------|------------------------:| -| [Performance Tuning](performance_tuning.md) | [Building](building.md) | +| Previous | Next | +|:--------------|------------------------:| +| [API](api.md) | [Building](building.md) |
diff --git a/src/confighttp.cpp b/src/confighttp.cpp index 886008dd23b..756a4688259 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -324,6 +324,11 @@ namespace confighttp { } } + /** + * @brief Get the list of available applications. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void getApps(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -336,6 +341,11 @@ namespace confighttp { response->write(content, headers); } + /** + * @brief Get the logs from the log file. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void getLogs(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -348,6 +358,36 @@ namespace confighttp { response->write(SimpleWeb::StatusCode::success_ok, content, headers); } + /** + * @brief Save an application. If the application already exists, it will be updated, otherwise it will be added. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "name": "Application Name", + * "output": "Log Output Path", + * "cmd": "Command to run the application", + * "index": -1, + * "exclude-global-prep-cmd": false, + * "elevated": false, + * "auto-detach": true, + * "wait-all": true, + * "exit-timeout": 5, + * "prep-cmd": [ + * { + * "do": "Command to prepare", + * "undo": "Command to undo preparation", + * "elevated": false + * } + * ], + * "detached": [ + * "Detached command" + * ], + * "image-path": "Full path to the application image. Must be a png file.", + * } + * @endcode + */ void saveApp(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -436,6 +476,11 @@ namespace confighttp { proc::refresh(config::stream.file_apps); } + /** + * @brief Delete an application. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void deleteApp(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -485,6 +530,18 @@ namespace confighttp { proc::refresh(config::stream.file_apps); } + /** + * @brief Upload a cover image. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "key": "igdb_", + * "url": "https://images.igdb.com/igdb/image/upload/t_cover_big_2x/.png", + * } + * @endcode + */ void uploadCover(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -545,6 +602,11 @@ namespace confighttp { outputTree.put("path", path); } + /** + * @brief Get the configuration settings. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void getConfig(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -570,6 +632,11 @@ namespace confighttp { } } + /** + * @brief Get the locale setting. This endpoint does not require authentication. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void getLocale(resp_https_t response, req_https_t request) { // we need to return the locale whether authenticated or not @@ -588,6 +655,19 @@ namespace confighttp { outputTree.put("locale", config::sunshine.locale); } + /** + * @brief Save the configuration settings. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "key": "value" + * } + * @endcode + * + * @attention{It is recommended to ONLY save the config settings that differ from the default behavior.} + */ void saveConfig(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -624,6 +704,11 @@ namespace confighttp { } } + /** + * @brief Restart Sunshine. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void restart(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -634,6 +719,21 @@ namespace confighttp { platf::restart(); } + /** + * @brief Update existing credentials. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "currentUsername": "Current Username", + * "currentPassword": "Current Password", + * "newUsername": "New Username", + * "newPassword": "New Password", + * "confirmNewPassword": "Confirm New Password" + * } + * @endcode + */ void savePassword(resp_https_t response, req_https_t request) { if (!config::sunshine.username.empty() && !authenticate(response, request)) return; @@ -692,6 +792,18 @@ namespace confighttp { } } + /** + * @brief Send a pin code to the host. The pin is generated from the Moonlight client during the pairing process. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "pin": "", + * "name": "Friendly Client Name" + * } + * @endcode + */ void savePin(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -724,6 +836,11 @@ namespace confighttp { } } + /** + * @brief Unpair all clients. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void unpairAll(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -742,6 +859,17 @@ namespace confighttp { outputTree.put("status", true); } + /** + * @brief Unpair a client. + * @param response The HTTP response object. + * @param request The HTTP request object. + * The body for the post request should be JSON serialized in the following format: + * @code{.json} + * { + * "uuid": "" + * } + * @endcode + */ void unpair(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -773,6 +901,11 @@ namespace confighttp { } } + /** + * @brief Get the list of paired clients. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void listClients(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; @@ -795,6 +928,11 @@ namespace confighttp { outputTree.put("status", true); } + /** + * @brief Close the currently running application. + * @param response The HTTP response object. + * @param request The HTTP request object. + */ void closeApp(resp_https_t response, req_https_t request) { if (!authenticate(response, request)) return; diff --git a/src_assets/common/assets/web/apps.html b/src_assets/common/assets/web/apps.html index f9191eae088..e10ce0262fb 100644 --- a/src_assets/common/assets/web/apps.html +++ b/src_assets/common/assets/web/apps.html @@ -506,12 +506,12 @@

{{ $t('apps.env_vars_about') }}

if (dotIndex < 0 || slashIndex < 0) { return null; } - const hash = thumb.substring(slashIndex + 1, dotIndex); + const slug = thumb.substring(slashIndex + 1, dotIndex); return { name: game.name, - key: "igdb_" + game.id, - url: "https://images.igdb.com/igdb/image/upload/t_cover_big/" + hash + ".jpg", - saveUrl: "https://images.igdb.com/igdb/image/upload/t_cover_big_2x/" + hash + ".png", + key: `igdb_${game.id}`, + url: `https://images.igdb.com/igdb/image/upload/t_cover_big/${slug}.jpg`, + saveUrl: `https://images.igdb.com/igdb/image/upload/t_cover_big_2x/${slug}.png`, } }).filter(item => item)); }